`
qtlkw
  • 浏览: 300415 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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

    博客分类:
  • JAVA
 
阅读更多
Reference: http://hi.baidu.com/chenlinping/item/6613c0e9b8fa1ce3fa42ba43

【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();
			}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics