我在我的项目中使用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();
问题: 我按顺序执行此操作:
你可以看到: - 当你输入方法salvaDaPrenotazione()时,你得到正确的MAX(numero)(是db上保存的序列的最后一个值) - 在方法结束时salvaDaPrenotazion()在持久化和刷新后调用getNumeroBiglietto()我从db得到了正确的更新值 - 当你输入方法salva()并从db得到值MAX(numero)时我的错误值!我有一个陈旧的值,就像我在方法salvaDaPrenotazione()的开头一样,好像这个事务没有看到另一个事务的提交。 因此交易失败并带有
org.hibernate.exception.ConstraintViolationException
请注意:
有一个唯一的输入点
public synchronized S salva(S vendita,Long idPrenotazione)抛出异常{
并且此方法是同步的。
我不明白问题出在哪里。我不认为与缓存问题有关,也许与隔离问题有关。
答案 0 :(得分:1)
您是否尝试将其用于测序?它不起作用,因为调用该查询的每个进程都将获得相同的值,除非您保证它们仅通过锁定顺序执行。需要对查询执行悲观锁定,以便在第一个进程完成更新之前,其他任何进程都不能发出相同的查询。 您应该使用数据库或JPA排序策略,而不是重新发明轮子,请参阅http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing