我已经实现了一个通用存储库,并想知道是否有一种智能方法可以在出现死锁异常的情况下实现重试逻辑?
所有存储库方法的方法都应该相同.那么无论如何我可以避免在每一种方法中使用retry-count再次编写'try/catch - call方法'吗?
任何建议都是受欢迎的.
我的存储库代码:
public class GenericRepository : IRepository
{
private ObjectContext _context;
public List<TEntity> ExecuteStoreQuery<TEntity>(string commandText, params object[] parameters) where TEntity : class
{
List<TEntity> myList = new List<TEntity>();
var groupData = _context.ExecuteStoreQuery<TEntity>(commandText, parameters);
return myList;
}
public IQueryable<TEntity> GetQuery<TEntity>() where TEntity : class
{
var entityName = GetEntityName<TEntity>();
return _context.CreateQuery<TEntity>(entityName);
}
public IEnumerable<TEntity> GetAll<TEntity>() where TEntity : class
{
return GetQuery<TEntity>().AsEnumerable();
}
Run Code Online (Sandbox Code Playgroud)
编辑:
1.Solution:
从 chris.house.00的解决方案略微修改
public static T DeadlockRetryHelper<T>(Func<T> repositoryMethod, int maxRetries) …Run Code Online (Sandbox Code Playgroud) c# entity-framework try-catch repository-pattern database-deadlocks
让我们先忘掉Hibernate吧.假设我有两个表,A和B.两个事务正在更新这两个表中的相同记录,但是txn 1更新B然后更新A,而txn 2更新A然后更新B.这是一个典型的死锁示例.避免这种情况的最常见方法是预先定义获取资源的顺序.例如,我们应该更新表A然后B.
回到Hibernate.当我们在一个会话中更新大量实体时,一旦我刷新会话,不同实体的更改将为DB生成相应的插入/更新/删除语句.Hibernate是否有一些算法来决定实体之间的更新顺序?如果没有,Hibernate用于防止第1段中描述的死锁情况的方式是什么?
如果Hibernate维护订单,我怎么知道或控制订单?我不希望我的数据库中的显式更新与Hibernate冲突,并导致死锁.
我有一个大约有5,000,000行的MySQL表,通过DBI连接的并行Perl进程以小的方式不断更新.该表有大约10列和几个索引.
一个相当常见的操作有时会产生以下错误:
DBD::mysql::st execute failed: Deadlock found when trying to get lock; try restarting transaction at Db.pm line 276.
Run Code Online (Sandbox Code Playgroud)
触发错误的SQL语句是这样的:
UPDATE file_table SET a_lock = 'process-1234' WHERE param1 = 'X' AND param2 = 'Y' AND param3 = 'Z' LIMIT 47
Run Code Online (Sandbox Code Playgroud)
该错误仅在有时触发.我估计只有1%或更少的电话.然而,它从未发生在一个小桌子上,随着数据库的增长而变得越来越普遍.
请注意,我正在使用file_table中的a_lock字段来确保我运行的四个几乎相同的进程不会尝试在同一行上工作.该限制旨在将他们的工作分解成小块.
我没有在MySQL或DBD :: mysql上做太多调整.MySQL是标准的Solaris部署,数据库连接设置如下:
my $dsn = "DBI:mysql:database=" . $DbConfig::database . ";host=${DbConfig::hostname};port=${DbConfig::port}";
my $dbh = DBI->connect($dsn, $DbConfig::username, $DbConfig::password, { RaiseError => 1, AutoCommit => 1 }) or die $DBI::errstr;
Run Code Online (Sandbox Code Playgroud)
我在网上看到其他几个人报告了类似的错误,这可能是一个真正的僵局.
我有两个问题:
究竟是什么情况导致上述错误?
有一种简单的方法来解决它或减少它的频率?例如,我究竟如何"在Db.pm第276行重新启动交易"?
提前致谢.
等待死亡和伤口等待有什么区别?
我发现两种防止死锁的技术都做同样的事情(老回程的回滚).
可以任何机构解释我,他们与适当的例子有什么区别.
关于PostgreSQL死锁,我有点困惑.
典型的死锁示例是:
-- Transaction 1
UPDATE customer SET ... WHERE id = 1
UPDATE customer SET ... WHERE id = 2
-- Transaction 2
UPDATE customer SET ... WHERE id = 2
UPDATE customer SET ... WHERE id = 1
Run Code Online (Sandbox Code Playgroud)
但是,如果我更改代码如下:
-- Transaction 1
UPDATE customer SET ... WHERE id IN (1, 2)
-- Transaction 2
UPDATE customer SET ... WHERE id IN (1, 2)
Run Code Online (Sandbox Code Playgroud)
这可能会陷入僵局吗?
基本上我的问题是:在第二种情况下,PostgreSQL会逐行锁定行,还是锁定WHERE条件所涵盖的整个范围?
提前致谢!
我已经搜索了很长时间,但无法找到问题的解决方案.我们将SQLAlchemy与MySQL结合用于我们的项目,我们遇到了几次可怕的错误:
1213,'试图锁定时发现死锁; 尝试重启事务'.
在这种情况下,我们想尝试最多重启三次交易.
我已经开始编写一个装饰器来执行此操作,但我不知道如何在失败之前保存会话状态并在之后重试相同的事务?(因为SQLAlchemy在引发异常时需要回滚)
我到目前为止的工作,
def retry_on_deadlock_decorator(func):
lock_messages_error = ['Deadlock found', 'Lock wait timeout exceeded']
@wraps(func)
def wrapper(*args, **kwargs):
attempt_count = 0
while attempt_count < settings.MAXIMUM_RETRY_ON_DEADLOCK:
try:
return func(*args, **kwargs)
except OperationalError as e:
if any(msg in e.message for msg in lock_messages_error) \
and attempt_count <= settings.MAXIMUM_RETRY_ON_DEADLOCK:
logger.error('Deadlock detected. Trying sql transaction once more. Attempts count: %s'
% (attempt_count + 1))
else:
raise
attempt_count += 1
return wrapper
Run Code Online (Sandbox Code Playgroud) 我有一个报告死锁的错误日志:
事务(进程ID 55)在锁定时死锁 与另一个进程通信缓冲资源并被选为死锁牺牲品.重新运行该交易.
我试图重现此错误,但我的标准死锁SQL代码产生一个不同的错误:
事务(进程ID 54)在锁资源上与另一个进程发生死锁,并被选为死锁牺牲品.重新运行该交易.
我想非常清楚,我不是在问什么是僵局.我完全理解基础知识.
我的问题是:lock | communication buffer resources在这种情况下的含义是什么?什么是"通信缓冲资源"?这lock |意味着什么吗?
我最好的猜测是当并行线程结合其结果时使用通信缓冲区.任何人都可以确认或否认这个吗?
我的最终目标是以某种方式触发第一个错误再次发生.
我最近在实时应用程序上遇到了一个问题.我意识到我有越来越多的并发异常和数据库锁.
基本上我启动一个事务,它需要一个SELECT和一个INSERT在同一个表上提交.
但是因为负载非常繁重,所以每个事务都会锁定表,在大多数情况下,它会如此之快,不会导致任何问题,但锁存器开始等待的时间越来越多.
我通过调整查询来解决这个问题.
虽然,现在,我想用PHPUnit编写一些测试来验证我的修复并避免任何回归.
我无法找到任何关于如何做到这一点的材料.
由于PHP不是多线程的,我不知道如何在单个测试中运行并发查询来验证.
基本上,我希望能够在一次测试中运行多个调用,以确保一切正常.
我知道我可以通过直接查询http服务器并加载整个应用程序来尝试进行一些高级测试,但由于我的问题来自一个独立的库,我宁愿自己测试它.
有任何想法吗?
sql server中的死锁是什么时候出现的?死锁有什么问题以及如何解决?
我在MySQL表中遇到死锁.只涉及一个表,我可以一致地重现它.它只发生在我运行代码的多个线程时.
这是表格:
CREATE TABLE `users_roles` (
`role_id` bigint(20) NOT NULL,
`user_id` bigint(20) NOT NULL,
`created` datetime NOT NULL,
PRIMARY KEY (`user_id`,`role_id`),
KEY `created` (`created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Run Code Online (Sandbox Code Playgroud)
然后,我在每个线程中运行这两个查询,每个线程对user_id具有不同的值.
BEGIN;
DELETE FROM `users_roles` WHERE user_id = X;
INSERT INTO `users_roles` VALUES (7, X, NOW()); -- DEADLOCK ON THIS QUERY
COMMIT;
Run Code Online (Sandbox Code Playgroud)
应该注意,当调用DELETE语句时,user_id X 在数据库中永远不存在.运行这些查询的代码位用于创建新用户.但是,该功能允许我修改用户所在的帐户,并因此从旧用户的团队中删除现有角色.
因此,当足够的这些查询并行运行时,我开始遇到死锁.InnoDB状态的死锁部分在每次死锁后显示此信息.
------------------------
LATEST DETECTED DEADLOCK
------------------------
2014-05-09 16:02:20 7fbc99e5f700
*** (1) TRANSACTION:
TRANSACTION 6241424274, ACTIVE 0 sec inserting
mysql tables in use 1, …Run Code Online (Sandbox Code Playgroud) deadlock ×6
mysql ×3
database ×2
c# ×1
concurrency ×1
hibernate ×1
innodb ×1
php ×1
phpunit ×1
postgresql ×1
python ×1
sql ×1
sql-server ×1
sqlalchemy ×1
transactions ×1
try-catch ×1