我是靠谱客的博主 活力纸飞机,最近开发中收集的这篇文章主要介绍jpa删除数据后数据库无修改_Jpa同一个事务中对同一数据先改后查,获取数据并未改变。...,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、事件原因。

在使用JPA的时候。在同一个事务中,对某条数据。先查询,然后更新,再查询。由于第2次查询是从缓存取得第1次查询的结果。会出现2种情况:

如果更新是用save()等JPA自带的语句。会更新缓存。第2次查询的和数据库一致。

如果用自己写的更新语句。因为没有更新缓存。第2次查询从缓存获取数据,导致更新的数据第2次取不到。导致查询数据和数据库预期的不一致。

本质上就是要清楚,在同一个事务中,事务没有提交。第2次查询从缓存获取数据。

二、 证明第二次从缓存获取数据。

上面的代码中,2个对象的地址都一样是Organization@9556。所以第2次查询是从缓存获取的数据。

三、 参考例子1:

@Transactional

@Override

public void update() {

//查询

Organization organization = organizationRepo.findById(1803L).get();

organization.setName("Test step1ppp33");

//更新(因为是在事务中,所以更新了缓存,但是没有保存到数据库)

organizationRepo.save(organization);

查询数据

Organization org2 = organizationRepo.findById(1803L).get();

//获得的数据是 org2.getName()===Test step1ppp33 。证明没有从数据库拿,是从同一个事务缓存中取得的。

System.out.println("org2.getName()==="+org2.getName());

}

上面代码中org2.getName()===Test step1ppp33。证明没有从数据库拿,是从同一个事务缓存中取得的。

四、 参考例子2:

@Transactional

@Override

public void update() {

//查询

Organization organization = organizationRepo.findById(1803L).get();

/**

* @Modifying

* @Query("UPDATE Organization o set o.name='myUpdate' WHERE o.id=:id")

*void myUpdate(@Param("id") Long id);

*/

// 只做了一个更新语句,没有更新缓存的organization变量。

organizationRepo.myUpdate(1803L);

//查询缓存数据

Organization org2 = organizationRepo.findById(1803L).get();

//org2.getName()===Test step1ppp33 ,证明从缓存获取的数据。更新的数据没有被查询到,

System.out.println("org2.getName()==="+org2.getName());

}

自己写了一个update语句,并没有更新缓存的数据,所以第2次查询出来的name值并没有改变。

五、先更新,后查询。会查询出更新后的数据。

//把名字更新为 “myUpdate周4”

organizationRepo.myUpdate(1803L);

Organization organization = organizationRepo.findById(1803L).get();

//“myUpdate周4”

System.out.println(organization.getName());

可以看到最后打印出myUpdate周4表示查询出了更新后的数据。hibernate生成语句的顺序如下:

update Organization。

select from Organization。

select from Organization。

六、 高并发陷进。

如果我们要写一个方法methodA(),目的是减掉某个商品数量amount。就会有2种情况:

使用save()语句更新。如下:

public void methodA() {

Goods goods = goodsRepo.findById(1);

goods.setAmount(goods.getAmount() - quantity);

goodsRepo.save(goods);

}

这个时候缓存也被更新。同一个事务中,外部methodB()调用methodA()之后,在methodB()中使用goodsRepo.findById(1)查询库存。能保证查询的缓存数量和数据库一致。

但是高并发下,如果期间有另一个线程把商品的Amount更新为0,当前线程执行完之后商品数和当前线程一样,就导致其他线程的更新丢失。

2. 使用自定义语句更新amount。如下:

检查了数量的自定义update语句。

@Modifying

@Query("UPDATE Goods g SET g.amount=g.amount - :amount WHERE g.id=:id AND g.amount >=:amount")

void myUpdate(@Param("id") Long id,@Param("amount") Long amount);

减数量的逻辑。

public void methodA() {

Goods goods = goodsRepo.findById(1);

//减数量

goodsRepo.myUpdate(1,amount);

}

这个时候。同一个事务中,外部methodB()调用methodA()之后,在methodB()中使用goodsRepo.findById(1)查询库存。就会出现和预期不一致的情况。

总结: 必须让预期的数据库数量,和缓存的数量一致。

最后

以上就是活力纸飞机为你收集整理的jpa删除数据后数据库无修改_Jpa同一个事务中对同一数据先改后查,获取数据并未改变。...的全部内容,希望文章能够帮你解决jpa删除数据后数据库无修改_Jpa同一个事务中对同一数据先改后查,获取数据并未改变。...所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部