我有一个与hibernate交互的java servlet。因此有必要在系统上生成一个检查ID:
for (long j = 0; j < soldProductQuantity.longValue(); j++) {
checkId = Hotel.getNextMcsCheckAndIncrement();
checkIdString = checkId.toString();
McsCheck.generateCheck(checkIdString);
}
其中getNextMcsCheckAndIncrement()
定义为
static public synchronized Long getNextMcsCheckAndIncrement()
它使用hibernate从数据库中提取一个值,对它执行一些操作,将修改后的值存储回来,然后返回该数字。
由于getNextMcsCheckAndIncrement
是同步的,我希望没有两个检查具有相同的数字,因为没有两个线程可以同时输入该方法。
然而,我可以在我的数据中看到多个检查ID的重复实例。很明显,这不起作用。我错过了什么?
按要求执行getNext:
// Increment FIRST, then return the resulting value as the current MCS check value.
static public synchronized Long getNextMcsCheckAndIncrement() {
Hotel theHotel = null;
Long checkCounter;
@SuppressWarnings("unchecked")
List<Hotel> hotelList = Hotel.returnAllObjects();
for (Hotel currentHotel : hotelList) { // there should be only one.
theHotel = currentHotel;
}
checkCounter = theHotel.getMcsCheckCounter()+1;
theHotel.setMcsCheckCounter(checkCounter);
theHotel.update();
return checkCounter;
}
static public List returnAllObjects() {
return Hotel.query ("from Hotel");
}
static public List query(String queryString) {
Session session = HibernateUtil.getSessionFactory().openSession();
List result = session.createQuery(queryString).list();
session.close();
return result;
}
public void update() {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
session.update(this);
transaction.commit();
session.close();
}
是的,我知道这不是最好的方法,我会及时解决这个问题。但直接的问题是并发失败的原因。
答案 0 :(得分:0)
评论中的匿名给出了正确的答案:问题必须是hibernate数据库中的Hotel对象,而不是同步方法。虽然计数器方法已正确同步,但如果在此算法之外修改了酒店对象,则不会同步这些访问。
因此,正确的答案是仔细检查对酒店对象的所有数据库访问,并确保在此循环正在进行时不在其他位置修改对象,或者将计数器从Hotel对象重构为专用存储。