0

我有一个 Spring + Hibernate + DBUnit + MySQL 应用程序。

步骤如下:

1. I launch the application.
2. A DBUnit test loads data directly into the database (via JDBC).
3. I perform operations and HQL queries to assert the results.


在第 2 步之后,我立即从控制台查询数据库,并确认数据已正确加载。我的问题是,在第 3 步中,我通过 HQL 查询获得的对象不包含在第 2 步中加载的值,而是包含原始值(第 1 步及之前存在的值)。

在阅读了这里的一些帖子后,我决定在第 3 步之前清理会话缓存和二级缓存,以强制 Hibernate 直接获取数据库。但问题仍然存在。

有什么我做错了吗?


这是我在第 3 步中尝试的脚本:

在应用程序启动之前(步骤 1),数据库中的帐户余额为 125。在步骤 2 中,DBUnit 确实将数据库中的余额更改为 10。

   // A break-point here allows me to check through a console that balance at database is cartainly 10.

   // I query the account and print the balance, which is 125.
   List l1 = this.getHibernateTemplate().find("select a from Account a where a.number = ?", parameter);
   Account account1 = (Account) l1.get(0);
   System.out.println("A.- Account 1 balance: " + account1.getBalance());

   // I clear session cache and second-level cache.
   this.getSession().evict(account1);
   this.getSessionFactory().evict(Account.class);       
   this.getSessionFactory().evictQueries();     

   // I repeat the same query, now expecting to force a database fetch. But it still prints 125 and not 10.
   List l2 = this.getHibernateTemplate().find("select a from Account a where a.number = ?", parameter);
   Account account2 = (Account) l2.get(0);
   System.out.println("B.- Account 2 balance: " + account2.getBalance());

我也尝试过 refresh(account1) 和 session.clear(),但它们没有用。

如果这不是正确的解决方案,我愿意听取其他人的意见。

谢谢,迭戈。

4

2 回答 2

0

我认为您看到这种行为是因为您的事务是在 REPEATABLE_READ 中配置的。这意味着 Hibernate 保证同一事务中的两次读取将始终返回相同的结果。由于隔离级别优先于您的缓存驱逐,缓存驱逐没有任何可见的影响。

有一种方法可以解决此问题:
将您的事务隔离级别声明为 READ_UNCOMMITTED 或 READ_COMMITTED。如果您使用标准方言,您可能会遇到著名的“标准 JPA 不支持自定义隔离级别”异常。在这种情况下,您可以应用以下解决方法:
spring 3.3:http
://amitstechblog.wordpress.com/2011/05/31/supporting-custom-isolation-levels-with-jpa/ spring 3.2:http://shahzad- mughal.blogspot.com/2012/04/spring-jpa-hibernate-support-for-custom.html

于 2013-11-17T03:48:41.067 回答
-1

我不知道hibernate,但这是使用JPA应该做的:

public <T> T load(Class<T> entityClass, Object pk)
{
    Map<String, Object> props = new HashMap<>();
    props.put("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS);

    return getEntityManager().find(entityClass, pk, props);
}
于 2013-11-07T18:28:36.577 回答