我们有一个基于网络的应用程序.应用程序中有时间限制的数据库操作(INSERT和UPDATE)需要更多时间才能完成,因此这个特定的流程已经变为Java线程,因此它不会等待(阻止)完成整个数据库操作.
我的问题是,如果超过1个用户遇到这个特定的流程,我面临PostgreSQL抛出的以下错误:
org.postgresql.util.PSQLException: ERROR: deadlock detected
Detail: Process 13560 waits for ShareLock on transaction 3147316424; blocked by process 13566.
Process 13566 waits for ShareLock on transaction 3147316408; blocked by process 13560.
Run Code Online (Sandbox Code Playgroud)
INSERT语句中始终抛出上述错误.
附加信息: 1)我在此表中定义了PRIMARY KEY.2)此表中有FOREIGN KEY引用.3)将单独的数据库连接传递给每个Java线程.
Technologies Web Server:Tomcat v6.0.10 Java v1.6.0 Servlet数据库:PostgreSQL v8.2.3连接管理:pgpool II
我们有一个表没有任何其他表的引用.
????????????????????????????????????????????????????????????
?id_A(bigint)?id_B(bigint) ?val_1(varchar) ?val_2(varchar) ?
????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)
表的主键是id_A和id_B的组合.
该表的读写是高度并发的,表有数百万行.我们有几个存储过程可以进行批量更新和删除.这些存储过程主要由触发器和应用程序代码同时调用.
这些操作通常如下所示,它可以匹配数千条记录来更新/删除:
DELETE FROM table_name
WHERE id_A = ANY(array_of_id_A)
AND id_B = ANY(array_of_id_B)
UPDATE table_name
SET val_1 = 'some value', val_2 = 'some value'
WHERE id_A = ANY(array_of_id_A)
AND id_B = ANY(array_of_id_B)
Run Code Online (Sandbox Code Playgroud)
我们遇到了死锁,我们使用锁(行级使用SELECT FOR UPDATE和表级锁)执行操作的所有尝试似乎都无法解决这些死锁问题.(注意,由于性能影响,我们不能以任何方式在此表上使用访问独占锁定)
还有另一种方法可以尝试解决这些死锁情况吗?参考手册说:
防止死锁的最佳方法通常是通过确保使用数据库的所有应用程序以一致的顺序获取多个对象的锁来避免死锁.
但是我们怎样才能在上述场景中实现这一目标.是否有保证以特定顺序执行批量更新插入操作的方法?
假设两个并发事务在Postgresql DB上执行以下查询:
交易A:
SELECT * FROM mytable WHERE id IN (1, 2, 3, 4) FOR UPDATE
Run Code Online (Sandbox Code Playgroud)
交易B:
SELECT * FROM mytable WHERE id IN (6, 3, 2, 1) FOR UPDATE
Run Code Online (Sandbox Code Playgroud)
由于Postgresql以不一致的顺序获取行锁,是否可能发生死锁?例如,如果Postgresql按照此示例中给出的id的顺序获取行锁,则可能存在死锁.
或者Postgresql内部是否足够智能,以便始终SELECT FOR UPDATE以同一个表上的同时离散语句不会相互死锁的方式获取行锁(例如,始终按主键顺序获取行锁)?
如果PostgreSQL的不自动防止此类死锁的发生,是否有修改,以防止这种情况的查询方式(例如,如果事实上PostgreSQL的收购顺序行锁被赋予的标识,并始终如一地分拣ID应该防止死锁)?
谢谢你的帮助!
我有复杂的查询,创建一个临时表,可能需要5秒钟才能运行或更多.这似乎在同时在类似的表上运行另一个事务时导致死锁.我不能在本地复制,但在生产中我能够每隔几天发生一次.(我记录了mysql错误)
查询非常复杂(显示在页面底部); 但你不需要理解逻辑; 只是它从一堆表和连接中选择,可能需要一段时间才能运行.
我还有一个插入许多相同表的事务.我偶尔会遇到一个mysql错误1213: Deadlock found when trying to get lock; try restarting transaction.
这是交易的伪代码
START TRANSACTION
INSERT INTO phppos_sales
INSERT MANY RECORDS INTO phppos_sales_items
INSERT MANY RECORDS INTO phppos_sales_items_taxes
INSERT MANY RECORDS INTO phppos_sales_payments
END TRANSACTION
Run Code Online (Sandbox Code Playgroud)
How do I go about resolving this deadlock? I tried changing isolation level to READ UNCOMMITTED but mysql settings wouldn't allow for this; and I need to make this work in a variety of environments where I don't have control of …
我有一个存储过程,在Begin和Commit tran下有以下两个事务.
UPDATE mytable
SET UserID = @ToUserID
WHERE UserID = @UserID
DELETE FROM mytable
WHERE UserID = @UserID
Run Code Online (Sandbox Code Playgroud)
在运行具有多次执行的Store Procedure时,我会死锁.这是死锁图:
<deadlock-list>
<deadlock victim="process16409057468">
<process-list>
<process id="process16409057468" taskpriority="0" logused="912" waitresource="RID: 6:1:2392:152" waittime="3022" ownerId="6283339" transactionname="user_transaction" lasttranstarted="2019-02-08T21:08:24.663" XDES="0x16401b98490" lockMode="U" schedulerid="8" kpid="23924" status="suspended" spid="92" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2019-02-08T21:08:24.667" lastbatchcompleted="2019-02-08T21:08:24.667" lastattention="1900-01-01T00:00:00.667" clientapp=".Net SqlClient Data Provider" hostname="GYAAN" hostpid="5624" loginname="sa" isolationlevel="read uncommitted (1)" xactid="6283339" currentdb="6" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="mytable" line="377" stmtstart="33320" stmtend="33540" sqlhandle="0x030006004f6bf63211085201eaa9000001000000000000000000000000000000000000000000000000000000">
UPDATE mytable
SET UserID = @ToUserID
WHERE UserID = @UserID …Run Code Online (Sandbox Code Playgroud) 在DB2(版本9.5)上的SQL语句
SELECT o.Id FROM Table1 o, Table2 x WHERE [...] FOR UPDATE WITH RR
Run Code Online (Sandbox Code Playgroud)
给我错误消息SQLSTATE=42829(不允许FOR UPDATE子句,因为无法修改游标指定的表).
我需要指定WITH RR,因为我在隔离级别上运行READ_COMMITTED,但我需要阻止我的查询,而另一个进程运行相同的查询.
如果我改为这样查询:
SELECT t.Id FROM Table t WHERE t.Id IN (
SELECT o.Id FROM Table1 o, Table2 x WHERE [...]
) FOR UPDATE WITH RR
Run Code Online (Sandbox Code Playgroud)
一切正常.
但是现在,当多个进程同时执行此查询时,我偶尔会遇到死锁异常.
有没有办法在FOR UPDATE不引入可能发生死锁的地方的情况下制定查询?
我尝试从C#中的SQL数据库获取数据时生成了这两个异常:
System.Data.SqlClient.SqlException:事务(进程ID 97)在锁资源上与另一个进程死锁,并被选为死锁牺牲品.
要么
System.Data.SqlClient.SqlException:事务(进程ID 62)在锁资源上与另一个进程死锁,并被选为死锁牺牲品.
要么
System.Data.SqlClient.SqlException:事务(进程ID 54)在锁资源上与另一个进程死锁,并被选为死锁牺牲品.重新运行该交易.
这是代码:
using (SqlConnection con = new SqlConnection(datasource))
{
SqlCommand cmd = new SqlCommand("Select * from MyTable Where ID='1' ", con);
cmd.CommandTimeout = 300;
con.Open();
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
adapter.Fill(ds);
con.Close();
return ds.Tables[0];
}
Run Code Online (Sandbox Code Playgroud)
这些都发生在每一次.
关于如何解决这些问题的任何想法?
我试图理解MySQL在同一个表上的并发客户端处理期间发现的死锁.这是"SHOW InnoDB STATUS"命令的有趣部分:
------------------------
LATEST DETECTED DEADLOCK
------------------------
120704 16:17:51
*** (1) TRANSACTION:
TRANSACTION 0 3547576, ACTIVE 0 sec, process no 10886, OS thread id 140547111458560 inserting
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 368, 1 row lock(s), undo log entries 1
MySQL thread id 41941, query id 1725666 localhost testsuite update
insert into `INode` (`status`,`_type`,`group`,`ctime`,`parent`,`shared`,`basename`,`_rowid`,`displayname`,`user`,`content_type`,`mtime`,`position`,`atime`,`size`) values ('Published','Group','12','2012-07-04 16:17:48.996869','2',null,'1','12','1','3','application/x-empty','2012-07-04 16:17:48.996896','1','2012-07-04 16:17:48.996914',null)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space …Run Code Online (Sandbox Code Playgroud) 我在Tomcat日志中不断收到此异常:
com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector run
WARNING: com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@76b28200 -- APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks!
com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector run
WARNING: com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@76b28200 -- APPARENT DEADLOCK!!! Complete Status:
Managed Threads: 3
Active Threads: 3
Active Tasks:
com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@1201fd18 (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1)
com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@408f3be4 (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0)
com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@7ba516d8 (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2)
Pending Tasks:
com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@137efe53
com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@766b0524
Pool thread stack traces:
Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1,5,main]
java.lang.Thread.sleep(Native Method)
com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask.run(BasicResourcePool.java:1805)
com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)
Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0,5,main]
java.lang.Thread.sleep(Native Method)
com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask.run(BasicResourcePool.java:1805)
com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)
Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2,5,main]
java.lang.Thread.sleep(Native Method)
com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask.run(BasicResourcePool.java:1805)
com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)
Run Code Online (Sandbox Code Playgroud)
我正在使用Hibernate 3.6.2和C3P0 0.9.1.2与MySQL.经过几个小时的Google搜索,这个APPARENT DEADLOCK异常似乎通常与准备好的语句缓存相关联.这是我的hibernate.cfg.xml中的C3P0配置:
<propertyname="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.acquire_increment">5</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">60</property>
<property name="hibernate.c3p0.idle_test_period">120</property>
<property name="hibernate.c3p0.timeout">180</property>
<property name="hibernate.c3p0.max_statements">0</property>
Run Code Online (Sandbox Code Playgroud)
我没有做任何声明缓存.任何有关错误的提示将不胜感激.
我需要对记录集合进行Postgres更新,并且我正在尝试防止压力测试中出现的死锁.
对此的典型解决方案是按照特定顺序更新记录,例如ID - 但似乎Postgres不允许ORDER BY进行更新.
假设我需要进行更新,例如:
UPDATE BALANCES WHERE ID IN (SELECT ID FROM some_function() ORDER BY ID);
Run Code Online (Sandbox Code Playgroud)
同时运行200个查询时会导致死锁.该怎么办?
我正在寻找一个通用的解决方案,而不是像在使用ORDER BY的UPDATE中那样的特定于案例的解决方法
它认为,必须有比写一个光标功能更好的解决方案.此外,如果没有更好的方法,那么光标的最佳运行方式是什么?逐个记录更新
postgresql ×4
mysql ×3
sql ×3
deadlock ×2
transactions ×2
c# ×1
c3p0 ×1
concurrency ×1
database ×1
db2 ×1
hibernate ×1
innodb ×1
php ×1
sql-server ×1