数据库死锁的解决办法

转载 2012年03月21日 16:31:41
 

近日在博客网站上,回复别人的数据库死锁避免问题,之前也曾经几次答复过同样的内容,觉得很有必要汇聚成一个博客文章,方便大家。

这里的办法,对所有的数据库都适用。

 

这个解决办法步骤如下:

1. 每个表中加 updated_count (integer) 字段

 

2. 新增一行数据,updated_count =0 :
insert into table_x (f1,f2,...,update_count) values(...,0);

 

3. 根据主键获取一行数据 SQL,封装成一个 DAO 函数(我的习惯是每个表一个 uuid 字段做主键。从不用组合主键,组合主键在多表 join 时 SQL 写起来很麻烦;也不用用户录入的业务数据做主键,因为凡是用户录入的数据都可能错误,然后要更改,不适合做主键)。
select * from table_x where pk = ?

 

4. 删除一行数据
4.1 先通过主键获取此行数据, 见 3.

4.2 delete from table_x where pk = ? and update_count=? , 这里 where 中的 update_count 通过 4.1 中获取
4.3 检查 4.2 执行影响数据行数,如果删除失败,则是别人已经删除或者更新过同一行数据,抛异常,在最外面 rollback,并通过合适的词语提醒用户有并发操作,请稍候再试。
int count = cmd.ExecuteNonQuery();
if(udpatedCount < 1){
throw new Exception(“检测到并发操作,为防止死锁,已放弃当前操作,请稍候再试,表 xxx, 数据 key ….”);
}

 

5. 更新一行数据
5.1 先通过主键获取此行数据, 见 3.
5.2 update table_x set f1=?,f2=?, ...,update_count=update_count+1 where pk = ? and update_count=? , 这里where 中的 update_count 通过 5.1 中获取
5.3 检查 5.2 执行影响数据行数,如果更新失败,则是别人已经删除或者更新过同一行数据,抛异常,在最外面 rollback,并通过合适的词语提醒用户有并发操作,请稍候再试。
int count = cmd.ExecuteNonQuery();
if(udpatedCount < 1){
throw new Exception(“检测到并发操作,为防止死锁,已放弃当前操作,请稍候再试,表 xxx, 数据 key ….”);
}

 

6. 数据库访问层 DAO 中,绝对不要写 try catch,也不要写 commit/rollback. 因为当我写了一个 dao1.insert(xxx) ,另一个人写了 dao2.insert(xxx), 两周后有可能会有人把这两个函数组合在一起放在一个事务中。如果dao1.insert(xxx)已经 commit ,那么dao2.insert(xxx) 中rollback 会达不到期望效果。很多电脑书中示例代码,都有这个错误。


数据库事务应该是这样界定起始范围:

6.1 单机版程序,每个按钮操作,对应一个事务。可以在把 connection/transaction 传递到 dao 中。在按钮响应的代码处,处理事务。catch 到任何 Exception 都要 rollback.


6.2 网页版程序,每个按钮操作,对应一个事务。可以在把 connection/transaction 传递到 dao 中。在按钮响应的代码处,处理事务。我强烈建议对于 Web应用,数据库连接的打开/关闭、数据库事务的开始和 commit/rollback 全在 filter 中处理(Java EE 和 ASP.NET MVC 都有 filter, 其它的不知道),事务、数据库连接通过 threadlocal 传入到 DAO 中。filter 中 catch 到任何 Exception 都要 rollback.

 

见过很多用 Spring 的人,代码中启动了几个数据库事务自己都不知道,符不符合自己的需要,也不知道。我的建议是,禁止使用 Spring 管理数据库事务。

 

7. 单表的增、删、改、通过主键查,应该用工具自动生成。自动生成代码,应该放在单独一个目录,以便后面有数据库表改动,可以重新生成代码并覆盖。自动生成的文件,在第一行就写上注释,表示这是一个自动生成的文件,以后会被自动覆盖,所以不要改这个文件。

举例来说,对于 tm_system_user 表,可以自动生成 TmSystemUserDAO, 包含函数: insert(TmSystemUser), update(TmSystemUser), delete(TmSystemUser), getByKey(key), batchInsert(TmSystemUser[])。


8. 总是使用事务,并用 ReadCommited 级别,即使是纯查询 SQL,也这么写。这可以简化设计与写代码,没有发现明显多余的性能消耗。

 

9. 数据设计时,尽量避免 update/delete. 举例来说,如果是一个请假条的审批流程,把请假条申请设计成一个表,领导批复设计成另一个表。尽量避免设计时合并成一个表,把批准状态(同意/否决)、批准时间当成“请假条申请”的属性。
说极端一点,最好从数据库设计上,避免后续编程有 update/delete, 只有 insert。 好像现在流行的 NoSQL 也是这么个思路。

 

10. 补充,如果在后台检查页面录入数据,报错处理,有以下两种方法:

10.1 只要有一个错误,就 throw exception.

10.2 把所有的错误都检测出来,比如,用户名未录入,电子邮件未录入,放在一个 List中,然后 throw exception.

数据库死锁原因及解决办法(转)

http://wxy6080.blog.163.com/blog/static/6201552020099142328485/ 所谓死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造...

数据库死锁的解决办法

这个解决办法步骤如下: 1. 每个表中加 updated_count (integer) 字段   2. 新增一行数据,updated_count =0 : insert into table...
  • lchyz89
  • lchyz89
  • 2012年03月21日 14:18
  • 286

数据库死锁查看及解决办法

本文通过实例来分析数据库死锁造成网站无法访问的解决方法。 问题:网站访问不了,主机重启之后,网站运行正常。 解决对策:由于数据库死锁造成。 死锁原因: 提取查询数据相应数据,修改Sta...

数据库死锁原因及解决办法

死锁(Deadlock)   所谓死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死...

sql表死锁解决办法

  • 2017年07月26日 11:46
  • 13KB
  • 下载

用存储过程查出引起死锁的进程和SQL语句--数据库死锁原因及解决办法

死锁(Deadlock)  所谓死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些...

windows下的多线程死锁的彻底解决办法

上篇文章Windows下解决TerminateThread终止线程导致死锁问题中,曾推断方法2会带来隐患,2.1只能减少死锁,不能彻底根除死锁。 前几天的几次测试中,确实再次出现死锁...

死锁产生的原因和解决办法

如果有两个会话,每个会话都持有另一个会话想要的资源,此时就会发生死锁。 用下面实验来说明死锁的产生原因和解决办法。 SESSION1: SQL> create table t2 as selec...

java线程死锁的简单解释和解决办法

public class Test01 extends Thread { public Object o1; public Object o2; public Test01(Object...

Java死锁产生的条件以及解决办法

进程死锁及解决办法  一、要点提示 (1) 掌握死锁的概念和产生死锁的根本原因。 (2) 理解产生死锁的必要条件--以下四个条件同时具备:互斥条件、不可抢占条件、占有且申请条件、循环等待条件...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:数据库死锁的解决办法
举报原因:
原因补充:

(最多只允许输入30个字)