【发布时间】:2013-09-10 20:51:55
【问题描述】:
我在我的项目中使用 spring jpa。
我有一个同步方法的服务:
@Service("venditaCustom")
@Transactional
public class VenditaCustomRepositoryImpl implements VenditaCustomRepository {
@Override
public synchronized <S extends Vendita> S salva(S vendita, Long idPrenotazione) throws Exception {
if (idPrenotazione == null || idPrenotazione < 0) {
return salva(vendita);
} else {
return salvaDaPrenotazione(vendita, idPrenotazione);
}
}
此方法向方法 salva 或 salvaDaPrenotazione 发送请求。
public <S extends Vendita> S salva(S vendita) throws Exception {
....do many operation on object Vendita.....
int numeroFiscale = getNumeroBiglietto();
...
manager.persist(vendita);
manager.flush();
getNumeroBiglietto() 方法查询最后一个序列号:
private int getNumeroBiglietto() {
String sQuery = "SELECT MAX(numero) FROM Biglietto WHERE anno = :anno ";
Query q = manager.createQuery(sQuery);
q.setParameter("anno", new GregorianCalendar().get(Calendar.YEAR));
Integer maxNum = 0;
try {
maxNum = (Integer) q.getSingleResult();
if (maxNum == null)
maxNum = 0;
} catch (NoResultException e) {
maxNum = 0;
} catch (Exception e) {
log.error("", e);
maxNum = 0;
}
if (maxNum == null || maxNum == 0) {
maxNum = PRIMO_NUMERO_FISCALE_BIGLIETTI;
} else {
maxNum++;
}
log.trace("maxNum " + maxNum);
return maxNum;
}
方法salvaDaPrenotazione与salva()非常相似:
public <S extends Vendita> S salvaDaPrenotazione(S vendita, Long idPrenotazione) throws Exception {
...do many action on object Vendita
int numeroFiscale = getNumeroBiglietto();
.....
manager.persist(vendita);
manager.flush();
问题:我按顺序做这个动作:
- 使用大数据间接调用方法salvaDaPrenotazion(),因此该方法需要很长时间才能完成(大约7s)
- 在第一个方法完成之前,我间接调用方法 salva()
你可以看到: - 当您输入方法 salvaDaPrenotazione() 时,您会得到正确的 MAX(numero)(是保存在 db 上的序列的最后一个值) - 在方法salvaDaPrenotazion() 的末尾,在persist 和flush 调用getNumeroBiglietto() 之后,我从db 中获得了正确的更新值 - 当您输入方法 salva() 并且我从 db 获得值 MAX(numero) 时,我的值错误!我有一个过时的值,就像我在方法 salvaDaPrenotazione() 开始时得到的一样,好像这个事务没有看到另一个事务的提交。 所以交易失败了
org.hibernate.exception.ConstraintViolationException
注意:
-
有一个独特的进入点是
public synchronized S salva(S vendita, Long idPrenotazione) throws Exception {
并且这个方法是同步的。
- 事务隔离在 spring jpa 中为 DEFAULT,在 my.cnf 中为 READ_COMMITTED(我使用的是 Mysql)
- 如果您在第一次失败后重试间接调用方法 salva(),它会起作用!
我不明白问题出在哪里。我认为与缓存问题无关,可能与隔离问题有关。
【问题讨论】:
标签: java hibernate jpa transactions spring-data