实践悲观锁。
业务模型是User访问target,target的点击数量+1
一般流程是 读——count+1——写
如果在并发下,存在count计数失误的情况,可以以如下方法验证:
为了模拟放大并发的现象,在读与写之间➕ sleep
读-sleep(6000) —— count++ ——写
public PageResult detail(Integer userId, Integer id) {
EquityMoney equityMoney = equityMoneyDao.findById(id);
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
equityMoney.setReading_quantity(equityMoney.getReading_quantity()+1);
equityMoneyDao.save(equityMoney);
return PageResult.genSuccess(equityMoney);
}
@Query("SELECT cd from EquityMoney cd where cd.id=:id ")
EquityMoney findById(@Param("id")Integer id);
测试配置1:
准备一台服务器A
准备浏览器两个标签,同时访问A
访问时两边同时sleep
结果两边结果都显示访问量(reading_quantity)为相同值
现在我们修改一下,为findById加上悲观锁
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT cd from EquityMoney cd where cd.id=:id ")
EquityMoney findById(@Param("id")Integer id);
再行相同测试,此时看到访问量两个标签为递增状态了,说明悲观锁起作用了,线程1读取时加锁,导致线程2无法读取,直到线程1的reading_quantity+1并写入操作,事务完成,线程2才读取,此时再+1,所以两边访问量差1
注:
1 PESSIMISTIC_READ报了Deadlock found when trying to get lock; try restarting transaction
查找了下资料:http://suene.iteye.com/blog/1756295
*
Java代码
@Lock(LockModeType.PESSIMISTIC_READ)
public List findByUsername(String username);
对应的 sql 就是:
Java代码
select * from t_user where username=? lock in share mode
*
Java代码
@Lock(LockModeType.PESSIMISTIC_WRITE)
public List findByUsername(String username);
对应的 sql 就是:
Java代码
select * from t_user where username=? for update
http://blog.csdn.net/cug_jiang126com/article/details/50544728
SELECT ... LOCK IN SHARE MODE走的是IS锁(意向共享锁),即在符合条件的rows上都加了共享锁,这样的话,其他session可以读取这些记录,也可以继续添加IS锁,但是无法修改这些记录直到你这个加锁的session执行完成(否则直接锁等待超时)。 SELECT ... FOR UPDATE 走的是IX锁(意向排它锁),即在符合条件的rows上都加了排它锁,其他session也就无法在这些记录上添加任何的S锁或X锁。如果不存在一致性非锁定读的话,那么其他session是无法读取和修改这些记录的,但是innodb有非锁定读(快照读并不需要加锁),for update之后并不会阻塞其他session的快照读取操作,除了select ...lock in share mode和select ... for update这种显示加锁的查询操作。 通过对比,发现for update的加锁方式无非是比lock in share mode的方式多阻塞了select...lock in share mode的查询方式,并不会阻塞快照读。
2 此悲观锁基于事务,应在service层上加上
@Transactional
测试结果
有事务注解
无事务注解
innodb
ok
no
myisam
no
/
数据库锁比起代码锁的好处之一是数据库锁适用于分布式
测试配置2:
准备两台服务器
A sleep
B none sleep
前提:
@Transcation+innodb
结果:
先访问A,再访问B
相同的id
发现B随着A的sleep一起阻塞了,证明id这条数据被锁导致B服务器线程阻塞
A id1,B id2
发现并未发生阻塞的情况,证明inndb mysql是行级锁,id1与id2并不互相影响
相同id
不同id
innodb
B阻塞
B不阻塞
myisam
B不阻塞
/