mysql jpa行锁_spring data jpa mysql 悲观锁

本文介绍了如何在 Spring Data JPA 中使用悲观锁处理并发问题,通过示例展示了悲观锁在更新计数场景下的应用。在并发环境下,未使用悲观锁会导致计数错误。通过添加 `@Lock(LockModeType.PESSIMISTIC_WRITE)` 注解实现悲观锁,确保线程安全,避免数据竞争。实验表明,悲观锁在 MySQL 的 InnoDB 存储引擎下表现为行级锁,而在 MyISAM 下则不支持行锁。
摘要由CSDN通过智能技术生成

实践悲观锁。

业务模型是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代码

0818b9ca8b590ca3270a3433284dd417.png

@Lock(LockModeType.PESSIMISTIC_READ)

public List findByUsername(String username);

对应的 sql 就是:

Java代码

0818b9ca8b590ca3270a3433284dd417.png

select * from t_user where username=? lock in share mode

*

Java代码

0818b9ca8b590ca3270a3433284dd417.png

@Lock(LockModeType.PESSIMISTIC_WRITE)

public List findByUsername(String username);

对应的 sql 就是:

Java代码

0818b9ca8b590ca3270a3433284dd417.png

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不阻塞

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值