我在我的项目中使用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() 的末尾,在持久化和刷新后进行调用到 getNumeroBiglietto() 我从 db 获得了正确的更新值 - 当您输入方法 salva() 并且我从 db 获得值 MAX(numero) 时,我的值错误!我有一个陈旧的价值,就像我在方法 salvaDaPrenotazione() 开始时得到的一样,好像这个事务没有看到另一个事务的提交。所以交易失败了
org.hibernate.exception.ConstraintViolationException
注意:
有一个独特的进入点是
公共同步 S salva(S vendita, Long idPrenotazione) 抛出异常 {
并且这个方法是同步的。
- 事务隔离在 spring jpa 中为 DEFAULT,在 my.cnf 中为 READ_COMMITTED(我使用的是 Mysql)
- 如果您在第一次失败后重试间接调用方法 salva() ,它会起作用!
我不明白问题出在哪里。我认为与缓存问题无关,可能与隔离问题有关。