내 JQL 쿼리가 동등한 CriteriaBuilder 쿼리와 다른 결과를 반환하는 이유는 무엇입니까?

Aug 17 2020

Dropwizard Hibernate를 사용하고 있으며 테스트에 문제가 있습니다. 이 예제를 최대한 단순화했습니다. 을 만들고 Foo업데이트 한 다음 가져 오려고합니다. 원시 쿼리를 사용하면 올바른 결과를 얻지 만 동등한 CriteriaBuilder 쿼리는 업데이트를 포착하지 못합니다. 내가 도대체 ​​뭘 잘못하고있는 겁니까?

    @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"
        });
    }

내 설정 코드는 다음과 같습니다.

@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();
    }
...
}

Foo수업 도 보여줄 수 있지만 그다지 흥미롭지는 않습니다.

답변

1 ChristianBeikov Aug 18 2020 at 09:16

Foo인스턴스는 L1 캐시, 즉 업데이트 문에 감동하지 않는 현재 세션에서 아직도있다. Hibernate / JPA는 세션의 엔티티 객체에 대한 ID를 유지해야하므로 update 문으로 인해 세션을 지울 수 없습니다. 일반적으로 현재 상태를 다시 반영하려면 update 문 후에 세션을 지우거나 인스턴스를 새로 고쳐야합니다.

sessionFactory.getCurrentSession().clear();읽기 트랜잭션을 시작할 때 대신 시도하십시오.