jdbc -- PostgreSql死锁检测异常

在开发数据库JDBC程序程序时,如果出现死锁:

举例 :

 A线程开启事务

 B线程开启事务

  A  线程更新表 update table set name=? where id=1//--成功

  B   线程更新表 update table  set name=? where id=2//--成功

  ----------------A与B操作成功。

  A线程更新表 update table set name=? where id=2//这时由于id=2记录被B线程connection锁定,因此等待B 线程完成事      务,释放锁。

  B线程更新表 update table  set name=? where id=1//这时由于id=1记录被A线程connection锁定,因此等待A 线程完成事务,释放锁。

 即A线程与B线程都被阻塞,相互等待对象方释放锁,才能继续执行。

  因此 A线程与B线程的 数据库操作产生死锁。 

 死锁会导至两条线程都一直阻塞,connection连接被占用不释放,线程被占用不释放,id=1,id=2的两条记录被锁定,其它线程更新也会阻塞。

PostgreSQL 9.5.2 版本、JDBC版本:9.4:

能够检测到死锁,并使其中一个connection的sql执行抛出异常,另一个connection操作成功。 

jdbc 异常信息如下:

Caused by: org.postgresql.util.PSQLException: ERROR: deadlock detected
  详细:Process 21853 waits for ShareLock on transaction 74456083; blocked by process 21852.
Process 21852 waits for ShareLock on transaction 74456084; blocked by process 21853.
  建议:See server log for query details.
  在位置:while updating tuple (0,9) in relation "test_user"
	at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2270)
	at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1998)
	at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:570)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:420)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:413)
	at com.alibaba.druid.pool.DruidPooledPreparedStatement.execute(DruidPooledPreparedStatement.java:493)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:45)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:73)
	at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:49)
	at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:115)
	at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:75)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:170)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:386)

 PostgreSQL 能够检测死锁的前提是 两个connection 相互等待对象释放锁。 

 对于另一种情况:

    A启用事务

    B启用事务

    A connction 更新 update table set name =? where id=1 

         并且因为某种原因一直未提交事务,使id=1的记录一直被锁定

    B connection 更新update table set name =? where id=1 

         由于该记录被Aconnction锁定,B 一直等待Aconnection commit 或 rollback 来释放锁。 

    这样B 操作一直阻塞中。 

   这种情况 一个connection 一直等待另一个connection 释放锁,这种不是死锁,但会一直阻塞。

  解决办法 可以设置java.sql.Statement.setQueryTimeout(),来设置sql操作的超时时间,如果超时

则抛出异常,防止阻塞。 (前提是需要jdbc驱动支持)

    

猜你喜欢

转载自java12345678.iteye.com/blog/2373596