2023年8月3日发(作者:)
⽤最简单的springboot+mybatis解释forupdate的使⽤场景正经学徒,佛系记录,不搞事情本⽂的主⾓是mysql InnoDB的写锁,即排他锁(for update)使⽤他最好的⽅式就是理解他:1. 排他锁不能与其他锁共存2. ⼀个事务获取了某⾏的排他锁,其他事务就不能再获取该⾏的锁3. 获取排他锁的当前事务内可以对数据进⾏读取和修改4. 不开启事务,FOR UPDATE 不会锁数据5. FOR UPDATE 是写锁,读操作不会锁住6. FOR UPDATE 即可能是⾏锁也可能是表锁假设有个表单products ,⾥⾯有id跟name⼆个栏位,id是主键。例1: (明确指定主键,并且有此笔资料,row lock)SELECT * FROM wallet WHERE id=’3′ FOR UPDATE;例2: (明确指定主键,若查⽆此笔资料,⽆lock)SELECT * FROM wallet WHERE id=’-1′ FOR UPDATE;例2: (⽆主键,table lock)SELECT * FROM wallet WHERE name=’Mouse’ FOR UPDATE;例3: (主键不明确,table lock)SELECT * FROM wallet WHERE id<>’3′ FOR UPDATE;例4: (主键不明确,table lock)SELECT * FROM wallet WHERE id LIKE ‘3’ FOR UPDATE;带着上⾯的总结,开始试验:建⽴⼀张最基本的表,数据库增加数据id=1,score=0CREATE TABLE `score` ( `id` int(6) NOT NULL AUTO_INCREMENT COMMENT '主键', `score` int(6) DEFAULT NULL COMMENT '分数', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;java部分代码,主要是A、B两个⽅法进⾏操作,之所以分成两个⽅法就是为了测试不同操作同时修改同⼀条数据会引发的情况,如果是调⽤的痛⼀个⽅法,那直接使⽤可重⼊锁或synchronize等处理并发问题就可以解决了@RestController@RequestMapping(value = "/score")public class ScoreController { @Autowired private ScoreBS scoreBS; @PutMapping(value = "/A") public void A(){ scoreBS.A(); } @PutMapping(value = "/B") public void B(){ scoreBS.B(); }}@Service@Transactional(rollbackFor = )public class ScoreBSImpl implements ScoreBS { @Autowired private ScoreMapper scoreMapper; @Override public void A(){ } @Override public void B(){ }}需求:甲⼄两个⽤户分别操作A、B⽅法,两个⽅法需要先根据id查询出数据,并对score的值进⾏追加修改普通写法如下:@Overridepublic void A(){ Score score = ById(1); re(re()+10); Score(score);}@Overridepublic void B(){ Score score = ById(1); re(re()+5); Score(score);}
B⽅法也使⽤for update进⾏查询,由于其他事物不能获取已有排他锁的锁,因此会等待当前数据的排他锁被释放才能后进⾏查询,也就是所谓的,在查询时就进⾏阻塞最终结果:score=15另外⼀种解决思路就是执⾏A⽅法时,同时调⽤了B⽅法,不进⾏阻塞,直接抛出异常,通知⽤户“服务器繁忙请重试”等,此⽅法的⽬的是通过⽤户重新发起调⽤来避免并发情况的出现,使⽤的是关键词FOR UPDATE NOWAIT,此⽅法暂不推荐在⾼并发的情况下使⽤,即影响⽤户体验,也影响执⾏速度,仅当做⼀个思路
2023年8月3日发(作者:)
⽤最简单的springboot+mybatis解释forupdate的使⽤场景正经学徒,佛系记录,不搞事情本⽂的主⾓是mysql InnoDB的写锁,即排他锁(for update)使⽤他最好的⽅式就是理解他:1. 排他锁不能与其他锁共存2. ⼀个事务获取了某⾏的排他锁,其他事务就不能再获取该⾏的锁3. 获取排他锁的当前事务内可以对数据进⾏读取和修改4. 不开启事务,FOR UPDATE 不会锁数据5. FOR UPDATE 是写锁,读操作不会锁住6. FOR UPDATE 即可能是⾏锁也可能是表锁假设有个表单products ,⾥⾯有id跟name⼆个栏位,id是主键。例1: (明确指定主键,并且有此笔资料,row lock)SELECT * FROM wallet WHERE id=’3′ FOR UPDATE;例2: (明确指定主键,若查⽆此笔资料,⽆lock)SELECT * FROM wallet WHERE id=’-1′ FOR UPDATE;例2: (⽆主键,table lock)SELECT * FROM wallet WHERE name=’Mouse’ FOR UPDATE;例3: (主键不明确,table lock)SELECT * FROM wallet WHERE id<>’3′ FOR UPDATE;例4: (主键不明确,table lock)SELECT * FROM wallet WHERE id LIKE ‘3’ FOR UPDATE;带着上⾯的总结,开始试验:建⽴⼀张最基本的表,数据库增加数据id=1,score=0CREATE TABLE `score` ( `id` int(6) NOT NULL AUTO_INCREMENT COMMENT '主键', `score` int(6) DEFAULT NULL COMMENT '分数', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;java部分代码,主要是A、B两个⽅法进⾏操作,之所以分成两个⽅法就是为了测试不同操作同时修改同⼀条数据会引发的情况,如果是调⽤的痛⼀个⽅法,那直接使⽤可重⼊锁或synchronize等处理并发问题就可以解决了@RestController@RequestMapping(value = "/score")public class ScoreController { @Autowired private ScoreBS scoreBS; @PutMapping(value = "/A") public void A(){ scoreBS.A(); } @PutMapping(value = "/B") public void B(){ scoreBS.B(); }}@Service@Transactional(rollbackFor = )public class ScoreBSImpl implements ScoreBS { @Autowired private ScoreMapper scoreMapper; @Override public void A(){ } @Override public void B(){ }}需求:甲⼄两个⽤户分别操作A、B⽅法,两个⽅法需要先根据id查询出数据,并对score的值进⾏追加修改普通写法如下:@Overridepublic void A(){ Score score = ById(1); re(re()+10); Score(score);}@Overridepublic void B(){ Score score = ById(1); re(re()+5); Score(score);}
B⽅法也使⽤for update进⾏查询,由于其他事物不能获取已有排他锁的锁,因此会等待当前数据的排他锁被释放才能后进⾏查询,也就是所谓的,在查询时就进⾏阻塞最终结果:score=15另外⼀种解决思路就是执⾏A⽅法时,同时调⽤了B⽅法,不进⾏阻塞,直接抛出异常,通知⽤户“服务器繁忙请重试”等,此⽅法的⽬的是通过⽤户重新发起调⽤来避免并发情况的出现,使⽤的是关键词FOR UPDATE NOWAIT,此⽅法暂不推荐在⾼并发的情况下使⽤,即影响⽤户体验,也影响执⾏速度,仅当做⼀个思路
发布评论