数据库中for update的使用

最近,一直在做一些关于并发的应用程序,如果在单个Java进程中可以通过synchronized关键字来保证线程之间的资源竞争和同步问题。

但是如果在多个Java进程之间需要完成数据之间的获取和使用问题就比较麻烦。

这里我说一下我们在数据库层面上来完成数据的之间的同步问题:数据库中有一条数据这条数据在多线程的情况下只能有一个线程来执行,当此线程执行完成后另外一个线程就会自动放弃这个任务。

实现过程如下:

@Transactional(rollbackFor=Exception.class)
	public void run() {
		logger.info("锁测试开始...");
		PayCenterTTaskCtl ttaskCtl = ttask.selectForUpdata("20160418114426", "11");
		if(null != ttaskCtl){
			PayCenterTTaskCtl ctl = new PayCenterTTaskCtl();
			ctl.setTASK_SEQ("20160418114426");
			ctl.setTASK_TYPE("11");
			ctl.setTASK_STAT("00");
			int updateCnt = ttask.updateByTaskTypeAndSeq(ctl);
			logger.info("更新行数{}", updateCnt);
		}
		logger.info("锁测试结束。查询出对象{}", ttaskCtl);
	}
selectForUpdata对应SQL:select * from table_name where TASK_SEQ = #{0} AND TASK_TYPE = #{1} AND task_stat='01' for update
updateByTaskTypeAndSeq对应SQL:update table_name set task_stat='00' where TASK_SEQ = #{0} AND TASK_TYPE = #{1}

上面方法的执行日志如下:

2016-12-18 15:12:39,813 [Thread-6]  INFO (TestServiceImpl.java:48) - 锁测试开始...

2016-12-18 15:12:39,824 [Thread-5]  INFO (TestServiceImpl.java:48) - 锁测试开始...

2016-12-18 15:12:39,851 [Thread-5] DEBUG (BaseJdbcLogger.java:139) - ==>  Preparing: select * from T_TASK_CTL where TASK_SEQ = ? AND TASK_TYPE = ? AND task_stat='01' for update 
2016-12-18 15:12:39,855 [Thread-6] DEBUG (BaseJdbcLogger.java:139) - ==>  Preparing: select * from T_TASK_CTL where TASK_SEQ = ? AND TASK_TYPE = ? AND task_stat='01' for update 
2016-12-18 15:12:39,990 [Thread-6] DEBUG (BaseJdbcLogger.java:139) - ==> Parameters: 20160418114426(String), 11(String)
2016-12-18 15:12:39,990 [Thread-5] DEBUG (BaseJdbcLogger.java:139) - ==> Parameters: 20160418114426(String), 11(String)
2016-12-18 15:12:40,049 [Thread-6] DEBUG (BaseJdbcLogger.java:139) - <==      Total: 1

2016-12-18 15:12:40,087 [Thread-6] DEBUG (BaseJdbcLogger.java:139) - ==>  Preparing: update T_TASK_CTL SET TASK_TYPE = ? ,TASK_STAT = ? ,UPD_TIME = SYSDATE ,AFFIX1 = ? where TASK_SEQ = ? AND TASK_TYPE = ? 
2016-12-18 15:12:40,087 [Thread-6] DEBUG (BaseJdbcLogger.java:139) - ==> Parameters: 11(String), 00(String), null, 20160418114426(String), 11(String)
2016-12-18 15:12:40,094 [Thread-6] DEBUG (BaseJdbcLogger.java:139) - <==    Updates: 1
2016-12-18 15:12:40,095 [Thread-6]  INFO (TestServiceImpl.java:56) - 更新行数1
2016-12-18 15:12:40,095 [Thread-6]  INFO (TestServiceImpl.java:58) - 锁测试结束。查询出对象任务类型:11,任务编号:20160418114426,任务状态:01,任务总笔数:0,成功笔数:0,失败笔数:0,任务开始时间:Mon Apr 18 11:44:26 CST 2016,任务结束时间:null,更新时间:Mon Apr 18 15:18:27 CST 2016,附加字段1:null,附加字段2:10.63.32.6:34,附加字段3:null

2016-12-18 15:12:40,107 [Thread-5] DEBUG (BaseJdbcLogger.java:139) - <==      Total: 0
2016-12-18 15:12:40,107 [Thread-5] DEBUG (SqlSessionUtils.java:163) - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@60707666]
2016-12-18 15:12:40,108 [Thread-5]  INFO (TestServiceImpl.java:58) - 锁测试结束。查询出对象null

从上面日志可以看出线程6执行SQL(selectForUpdata)先于线程5,当线程6执行时线程5一直处于等待状态,当线程6执行完成并提交事务之后线程5开始查询,可以看出查询结果为0,所以没有更新记录的操作。


从上面的过程我得到如下结论:

1、如果需要使用for update就需要在使用前显示的启动事务,处理完成后显示的提交事务,不然下一个线程获取到此数据后会将永远等待;

2、for update执行的时为了防止多操作数据,应该在语句中添加一个状态,即时两个线程同时访问到一条数据也不会出现多处理的问题;

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值