利用悲观锁解决数据库死锁

Reference: [url]http://hi.baidu.com/chenlinping/item/6613c0e9b8fa1ce3fa42ba43[/url]

【IT168技术文档】

  这边讲述的数据库死锁是由于查询条件顺序不对而造成的一类,主要是两个线程在同时对一个数据库表进行操作时,出现了下列情况,假设一个数据库表 内有5行数据,线程1需要对1-4行数据进行update操作,而线程2需要对2-5行数据进行update操作,但是由于操作的顺序调整的不正确,线程 1是对数据行1,2,3,4这样的顺序操作,并且加入batch的,而线程2是对数据行5,4,3,2这样的顺序操作的,并且加入batch,于是锁就这 样产生了:当线程1的executeBatch进行批量update时,锁住了123行数据,开始操第4行数据时,此时线程二的executeBatch 正当操作完第4行数据,准备操作第3行数据,而此时线程2则拿着4,5行数据的锁,并且不会释放。于是线程1发现第4行数据的锁已经被占用,便开始等待这 个锁的释放,对于batch操作来说,在没有完成整个事务时,线程1不会释放对1,2,3行数据的锁的拥有权,同样2号线程也在等待1线程释放3号数据的 锁,同样等待,这个相互等待的过程将不会结束,直到数据库有额外的机制来回滚一个操作。当然,这就意味着这两个操作里面有一个就失败了。当然,最好的解决 办法就是调整操作顺序使其(操作顺序)一致,但是当这个里面有错总复杂的问题的时候,比如有时多个线程之间对同一个表操作,或者多个线程操作多个表时,理 起来就会变得麻烦。这边还有一个方案,对于oracle或者sql server这类支持主观加载悲观锁的数据库,可以利用这个特性来手动实现数据库批量操作的事务锁。针对oracle,可以用select ... for update来加载悲观锁,比如需要对于某个字段进行update,则可以用select语句在末尾加上for update把这个字段锁住,然后进行batch的操作。这边需要注意的是:

  1.对于开始使用select ... for update前,必须将autoCommit设置成false;

  2.完成一个update后,必须commit这个事务以便释放这批锁。

  3.操作时要保证数据库表没有其他死锁,否则也会引起一些问题(sqlplus操作需要commit掉)用这个方法,对于锁的控制主权更多,一 旦出问题时,调试更加简便,缺点是效率还是一个大问题,毕竟对于大规模数据来说,还是调整执行顺序是首选,我这个只能算是个旁门左道,嘿嘿。


ExecutorService executor = Executors.newFixedThreadPool(pool_size);
for (StringBuilder requestParameter : fetcherParams) {
StringBuilder sb = new StringBuilder(requestParameter.toString());
String lastCharacter = sb.substring(sb.length()-1, sb.length());
if("&".equals(lastCharacter)){
sb.delete(sb.length()-1, sb.length());
}
fetcher.setRequestParameter(sb.toString());
OSA_Worker worker = new OSA_Worker();
worker.setAppCode(appCode);
worker.setJobCode(jobCode);
worker.setJobId(jobId);
worker.setUserId(userId);
worker.setColumnCount(columnCount);
worker.setDataIndex(dataIndex);

worker.setFetcher((OSADataFetcher) fetcher.clone());
worker.setInsertSQL(insertSQL);

executor.execute(worker);
}

executor.shutdown();

while (!executor.isTerminated()) {
Thread.sleep(1000);
}



private static final Object objLock = new Object();
...
appConn.setAutoCommit(false);
cs = appConn.prepareCall("{" + insertSQL + "}");
...

synchronized(objLock){
cs.executeBatch();
cs.clearBatch();
appConn.commit();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值