问题
I'm using Dropwizard Hibernate and am having issues with my tests. I've simplified this example as much as possible. I create a Foo
, update it, and then try to fetch it. Using a raw query gets the correct result, but the equivalent CriteriaBuilder query doesn't catch the update. What am I doing wrong?
@Test
public void testFoo() {
String id = "12345";
// Create
Foo foo = Foo.builder()
.id(id)
.name("old-name")
.build();
sessionFactory.getCurrentSession().replicate(foo, ReplicationMode.EXCEPTION);
// Update
database.inTransaction(() -> {
CriteriaBuilder cb = sessionFactory.getCurrentSession().getCriteriaBuilder();
CriteriaUpdate<Foo> update = cb.createCriteriaUpdate(Foo.class);
Root<Foo> root = update.from(Foo.class);
update.set(Foo_.name, "new-name");
update.where(cb.equal(root.get(Foo_.id), id));
int updated = sessionFactory.getCurrentSession().createQuery(update).executeUpdate();
});
// Select
database.inTransaction(() -> {
sessionFactory.getCurrentSession().flush(); // Not sure if this matters
String newName = (String) sessionFactory.getCurrentSession()
.createQuery("select name from Foo where id=:id")
.setParameter("id", id)
.getSingleResult();
assertEquals("new-name", newName);
log.error("New name is " + newName);
CriteriaBuilder cb = sessionFactory.getCurrentSession().getCriteriaBuilder();
CriteriaQuery<Foo> cq = cb.createQuery(Foo.class);
Root<Foo> root = cq.from(Foo.class);
cq.where(cb.equal(root.get(Foo_.id), id));
Query query = sessionFactory.getCurrentSession().createQuery(cq);
Foo foo2 = (Foo) query.getSingleResult();
log.error("New name is " + foo2.getName()); // Prints "old-name"
});
}
Here's my setup code:
@ExtendWith(DropwizardExtensionsSupport.class)
public class UpdateTest {
private SessionFactory sessionFactory;
public DAOTestExtension database = DAOTestExtension.newBuilder()
.addEntityClass(Foo.class)
.build();
@BeforeEach
public void setup() {
sessionFactory = database.getSessionFactory();
}
...
}
I can also show the Foo
class, but it's not very interesting.
回答1:
The Foo
instance is still in the L1 cache i.e. the current session which is not touched by the update statement. Since Hibernate/JPA has to retain identity for entity objects of a session, it can't clear the session due to the update statement. Usually, one has to clear the session or refresh instances after an update statement to reflect the current state again.
Try doing sessionFactory.getCurrentSession().clear();
instead at the start of your read transaction
来源:https://stackoverflow.com/questions/63457714/why-does-my-jql-query-return-a-different-result-than-the-equivalent-criteriabuil