Ситуация:Hibernate параллелизм проблема при чтении/обновлении
У нас есть веб-приложение (Java EE-Spring-Hibernate), который генерирует PDF со штрих-кодом. Штрих-код содержит идентификатор, который создается во время выполнения. У нас есть служба Java, которая использует Hibernate для проверки наличия идентификатора для текущей даты, если он не существует, создается запись. Если он существует, он увеличивается и обновляется. Существует одна строка в день, содержащая следующие поля: id, coverPageId, date
Итак, когда пользователь создает первый штрих-код дня, строка добавляется к текущей дате с помощью coverPageId = 1. Затем все последующие штрих-коды получат последний идентификатор из базы данных, увеличивают его и сохраняют строку с добавочным значением.
Проблема:
Когда несколько пользователей создавать PDF в то же время, Hibernate будет получать такое же значение, как для пользователей, в результате чего тот же штрих-код на PDF-файлов.
Пытались Решение:
Код, который выбирает текущий идентификатор, увеличивает его и обновляет строку это все выполняется тем же способом. Это метод внутри компонента Spring. Так как весенние бобы - это синглеты, я попытался сделать метод synchronized
. Это не помогло.
Метод:
@Transactional(isolation=Isolation.SERIALIZABLE)
public synchronized long getNextId(Date date)
{
List<CoverpageID> allCoverpageIds = this.getAllCurrentIds(date);
if(allCoverpageIds.size() == 0)
{
loggingService.warn(String.format("Found no existing ID for date '%tD', creating new record", date));
System.out.println(String.format("Found no existing ID for date '%tD', creating new record", date));
return this.createNewCoverpageIdRecord(new Date());
}
else if(allCoverpageIds.size() == 1)
{
CoverpageID coverpageId = allCoverpageIds.get(0);
loggingService.debug(String.format("Found existing ID for date '%tD': %d, incrementing and persisting", date, coverpageId.getCoverPageId()));
System.out.println(String.format("Found existing ID for date '%tD': %d, incrementing and persisting", date, coverpageId.getCoverPageId()));
coverpageId.setCoverPageId(coverpageId.getCoverPageId() + 1);
dao.save(coverpageId);
loggingService.debug(String.format("Saved existing ID for date '%tD' with incremented ID: %d", date, coverpageId.getCoverPageId()));
return coverpageId.getCoverPageId();
}
else
{
loggingService.warn(String.format("Found multiple records for date '%tD'", date));
return -1;
}
}
private List<CoverpageID> getAllCurrentIds(Date date)
{
String exClause = "where date = :date";
Map<String, Object> values = new HashMap<String, Object>();
values.put("date", date);
return dao.getAllEx(CoverpageID.class, exClause, values);
}
private long createNewCoverpageIdRecord(Date date)
{
dao.save(new CoverpageID(new Date(), new Long(1)));
return 1;
}
CoverpageID.class (объект для штрих-кода):
@NamedQueries({
@NamedQuery(
name = "getCoverPageIdForDate",
query = "from CoverpageID c where c.date = :date",
readOnly = true
)})
@Entity
public class CoverpageID
{
private Long id;
private Date date;
private long coverPageId;
public CoverpageID() {}
public CoverpageID(Date date, Long coverPageId)
{
this.date = date;
this.coverPageId = coverPageId;
}
public void setId(Long id)
{
this.id = id;
}
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public Long getId()
{
return id;
}
@Temporal(TemporalType.DATE)
public Date getDate()
{
return date;
}
public void setDate(Date date)
{
this.date = date;
}
public long getCoverPageId()
{
return coverPageId;
}
public void setCoverPageId(long coverPageId)
{
this.coverPageId = coverPageId;
}
}
Кто-нибудь есть какие-либо другие идеи, как мы можем предотвратить эту проблему параллелизма случилось?
Даже если это не ошибка Hibernate, мой синхронизированный метод должен делать трюк, не так ли? Один экземпляр объекта (singleton), поэтому все вызовы проходят один и тот же метод объекта. И синхронизированный должен заставить всех абонентов ждать, если он обрабатывает звонок уже ... –
Это не поможет. Я собираюсь обновить свой ответ. –
И если я совершу транзакцию INSIDE, метод? –