我正在使用 Hibernate 访问 Oracle 数据库。
我认为我在使用 Hibernate 的一级(或会话)缓存时遇到了一些问题。我有代表帐户的表:ACCOUNT 表、INVOICE 表和 PAYMENTS 表。Oracle 数据库中定义了一些过程,因此添加 PAYMENT 将自动更新相关 INVOICE 和 ACCOUNT 表中的列。
我遇到的问题是当我使用 Hibernate 执行以下操作时:
Account account = accountDao.get(accountId);
assertEquals(0.00, account.getBalance());
// Saving a payment will trigger stored procedures that
// will update the account balance.
paymentDao.save(createPaymentForAccount(accountId, 20.00));
account = accountDao.get(accountId);
assertEquals(20.00, account.getBalance());
最后的断言将失败,因为account.getBalance()
返回0.00
而不是20.00
.
我希望第二次调用来accountDao.get(...)
访问数据库,并取回新的 ACCOUNT 对象。但是 Hibernate 似乎返回了已经在其缓存中的帐户对象(当我检查查找调用的调试输出时,我看到了number of objects hydrated: 0
)。
我假设 Hibernate 不知道数据库由于存储过程调用而发生了变化,这就是它使用缓存中的对象的原因。
于是我开始思考解决方案。一种是在保存 PAYMENT 时从休眠会话缓存中删除任何 ACCOUNT 和 PAYMENT 对象。这将强制对任何 ACCOUNT 或 INVOICE 操作进行数据库获取(使用新更新的值)。
我尝试了以下方法:
public void save(Payment payment) {
getSession().persist(payment);
getSessionFactory().evict(Invoice.class);
getSessionFactory().evict(Account.class);
}
但是休眠跟踪日志显示什么也没发生。我认为这sessionFactory.evict(...)
在二级缓存上运行,该二级缓存未启用,因此没有什么可以驱逐的。
接下来,我尝试通过逐出我能找到的每个实例来逐出会话缓存中的所有 ACCOUNT 和 INVOICE 对象:
public void save(Payment payment) {
getSession().persist(payment);
for (Invoice invoice: lookupInvoices()) { // e.g. "from Invoice" query
getSession().evict(invoice);
}
for (Account account: lookupAccounts()) { // e.g. "from Account" query
getSession().evict(account);
}
}
这似乎可行,但效率极低,因为它在驱逐它们之前将所有实例加载到休眠会话缓存中,而我真正想做的只是驱逐会话中的任何当前实例。
我看不到任何清除指定类型的所有对象的一级缓存的方法,那么还有哪些其他解决方案可用?