参考文献

JPA自动更新问题

环境以及版本
1
2
SpringBoot 2.2.2.RELEASE
MySQL 8.0.24
示例1
  • 描述: 不加@Transactional注解,两次查询,第一次查询修改实体的某个值
  • 结果: 两次查询的结果一致
1
2
3
4
5
6
7
8
9
10
11
12
@GetMapping("/test3")
public void test3() {
Optional<TestJpa> byId = testDAO.findById(36);
if (byId.isPresent()) {
TestJpa test = byId.get();
// id=36, x=0, y=71, z=53
log.info("test: {}", test);
test.setX(123);
}
TestJpa test2 = testDAO.findById(36).get();
log.info("test2: {}", test2);
}

img

示例2
  • 描述: 相对示例1,多了个@Transactional
  • 结果: 两次查询的结果不一致,第一次查询后修改的值,在方法结束前自动更新了数据库
1
2
3
4
5
6
7
8
9
10
11
12
13
@Transactional
@GetMapping("/test4")
public void test4() {
Optional<TestJpa> byId = testDAO.findById(36);
if (byId.isPresent()) {
TestJpa test = byId.get();
// id=36, x=0, y=71, z=53
log.info("test: {}", test);
test.setX(123);
}
TestJpa test2 = testDAO.findById(36).get();
log.info("test2: {}", test2);
}

img

分析
  • Hibernate对象生命周期

    img
  • 第一查询到的数据test为持久态,修改X后还是持久态,当第二次查询相同的记录的时候,是直接从持久态上下文获取的.

    img

  • 最后在方法结束前提交事务前会做下列操作

    1
    2
    3
    4
    5
    6
    7
    8
    Execute all SQL (and second-level cache updates) in a special order so that foreign-key constraints cannot be violated:
    Inserts, in the order they were performed
    Updates
    Deletion of collection elements
    Insertion of collection elements
    Deletes, in the order they were performed
    Params:
    session – The session being flushed

    img

    img

    img

    img

    img

示例3
  • 描述: 相对示例2,多了entityManager.unwrap(org.hibernate.Session.class).evict(test);
  • 结果和示例1相似,两次查询结果一致
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Transactional
@GetMapping("/test5")
public void test5() {
Optional<TestJpa> byId = testDAO.findById(36);
if (byId.isPresent()) {
TestJpa test = byId.get();
// id=36, x=0, y=71, z=53
log.info("test: {}", test);
test.setX(123);
entityManager.unwrap(org.hibernate.Session.class).evict(test);
}
TestJpa test2 = testDAO.findById(36).get();
log.info("test2: {}", test2);
}

img