我正在开发一个复式会计系统,我需要插入发布记录,顺序ID没有任何空白。由于所有数据库访问都将通过Web应用程序进行,因此我使用同步静态变量来处理id生成:
import org.hibernate.*;
public class JournalService {
private static Object journalLock = new Object();
private Session session;
public JournalService(Session session) {
this.session = session;
}
public void insertJournalEntry(JournalEntry journalEntry) {
Set<PostEntry> entries = journalEntry.getEntries();
double total = 0;
for (PostEntry entry : entries) {
total += entry.getAmount();
}
if(total != 0)
throw new InvalidParameterException("Journal entry is invalid. The sum of all entries must be zero.");
Criteria criteria = session.createCriteria(PostEntry.class);
criteria.setMaxResults(1);
criteria.addOrder(Order.desc("id"));
//here I add some other criteria
synchronized(journalLock) {
PostEntry lastEntry = criteria.uniqueResult();
long currentId = lastEntry.getId();
for (PostEntry entry : entries) {
entry.setId(currentId++)
session.save(entry);
}
session.save(journalEntry);
}
}
}
简而言之,此服务的生命周期与当前的httprequest相关联,并由spring容器管理,此外我还要确保在请求结束时提交整个事务。同步块将处理任何并发性,因此id的序列中不会出现任何间隙。 这里的一个大问题是数据库访问的额外开销,用于选择与特定条件匹配的最后插入记录。我不希望这种情况发生,所以我猜这里的解决方案是使用一个缓存,它将在第一次选择时保存最后插入的记录,因此不需要数据库访问来生成id。 我的问题:是否有任何开箱即用的hibernate解决方法?我是hibernate的新手,听说过查询缓存,但我不确定如何使用它。我不希望缓存保存我使用此服务存储的每个值,我只需要它来存储最后一个符合特定条件的插入条目。例如,如果我执行了五个插入,其中两个匹配相等的条件'X'而另外三个匹配条件'Y',则缓存将只存储两个对象(最后插入的对象匹配每个条件)。 我自己可以很容易地实现它,但我宁愿使用与hibernate API集成的解决方案。
答案 0 :(得分:1)
缓存更适合存储经常访问的但很少修改的对象。什么不是你想要做的。您可以使用可序列化的事务来防止丢失更新和不一致的读取,这是您要避免的。但是你应该记住它的开销。
// Hibernate Transaction isolation level settings
// Serializable isolation level
hibernate.connection.isolation=8
这是SessionFactory API所说的
SessionFactory的行为由配置时提供的属性控制。这些属性在Environment上定义。
作为解决方法,您可以设置两个不同的SessionFactory,其中一个可序列化,如上所示。
因为您正在检索最新插入的PostEntry实体,我认为悲观锁定无法正确应用,因为您的数据库只是锁定检索到的PostEntry。