EntityManager refresh() 方法不刷新而是重置
EntityManager refresh() method does not refresh but resets
下面代码中的em.refresh(person)
不起作用。它不是使用数据库中的新值刷新 person
,而是重置(撤消或丢弃)在缓存中所做的更改。我无法理解为什么?
em.getTransaction().begin();
Person person = em.find(Person.class, 2L); //Person[id=2L, age=23]
person.setAge(24);
System.out.println(person.getAge()); //it prints 24
//Person with id=2 in database gets modified concurrently somehow,
//its age becomes 25 in PERSON table (by an SQL update for example "UPDATE person SET age=25 WHERE id=2")
em.refresh(person); // attempts to load fresh value from database with a SELECT...
System.out.println(person.getAge()); //it prints 23, rather than 25, why?
em.getTransaction().commit();
em.close();
有人可以通过 EntityManager
的 refresh()
方法帮助我理解这种行为吗?
如果您想在一个事务中查看其他事务所做的更改,您需要将隔离级别更改为 READ_COMMITTED
<property name="hibernate.connection.isolation">TRANSACTION_READ_COMMITTED</property>
几个定义来澄清讨论:
- 可重复读取:本质上意味着在一个事务中数据库将看到相同的值,除非数据在该事务中被修改
- Hibernate flush:会话中所做的修改(例如
person.setAge(24);
)在刷新之前对数据库不可见。刷新发生在调用 em.flush、提交或通常执行诸如 select * from Person where name=...
的查询时,但调用 refresh() 时不会
- Hibernate 刷新:从数据库中读取数据并使用该数据更新 session/1st 级缓存。
所以基本上:
- 您正在通过调用 setAge() 修改年龄,但该更改未刷新,因此数据库不可见
- 您正在从另一个会话更新,但该更改不可见,因为事务是隔离的(除非使用 READ_COMMITTED)
- 当调用刷新时,数据库不知道调用了 setAge() 并将更新与另一个事务隔离,因此它显示 23
下面代码中的em.refresh(person)
不起作用。它不是使用数据库中的新值刷新 person
,而是重置(撤消或丢弃)在缓存中所做的更改。我无法理解为什么?
em.getTransaction().begin();
Person person = em.find(Person.class, 2L); //Person[id=2L, age=23]
person.setAge(24);
System.out.println(person.getAge()); //it prints 24
//Person with id=2 in database gets modified concurrently somehow,
//its age becomes 25 in PERSON table (by an SQL update for example "UPDATE person SET age=25 WHERE id=2")
em.refresh(person); // attempts to load fresh value from database with a SELECT...
System.out.println(person.getAge()); //it prints 23, rather than 25, why?
em.getTransaction().commit();
em.close();
有人可以通过 EntityManager
的 refresh()
方法帮助我理解这种行为吗?
如果您想在一个事务中查看其他事务所做的更改,您需要将隔离级别更改为 READ_COMMITTED
<property name="hibernate.connection.isolation">TRANSACTION_READ_COMMITTED</property>
几个定义来澄清讨论:
- 可重复读取:本质上意味着在一个事务中数据库将看到相同的值,除非数据在该事务中被修改
- Hibernate flush:会话中所做的修改(例如
person.setAge(24);
)在刷新之前对数据库不可见。刷新发生在调用 em.flush、提交或通常执行诸如select * from Person where name=...
的查询时,但调用 refresh() 时不会
- Hibernate 刷新:从数据库中读取数据并使用该数据更新 session/1st 级缓存。
所以基本上:
- 您正在通过调用 setAge() 修改年龄,但该更改未刷新,因此数据库不可见
- 您正在从另一个会话更新,但该更改不可见,因为事务是隔离的(除非使用 READ_COMMITTED)
- 当调用刷新时,数据库不知道调用了 setAge() 并将更新与另一个事务隔离,因此它显示 23