数据库死锁的解决办法
来源:未知 责任编辑:责任编辑 发表时间:2013-12-22 14:57 点击:次
近日在博客网站上,回复别人的数据库死锁避免问题,之前也曾经几次答复过同样的内容,觉得很有必要汇聚成一个博客文章,方便大家。
这里的办法,对所有的数据库都适用。
这个解决办法步骤如下:
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 管理数据库事务。
相关新闻>>
最新推荐更多>>>
- 发表评论
-
- 最新评论 更多>>