We have a Kafka consumer in a Java - Spring Boot service that has multiple instances in multiple clusters (all with same consumer group id). The consumer saves data to the database (SQL Server).
The code checks if a record exists in the ItemSet
table before saving to the database. The actual data in the payload gets saved in a child table ItemValue
and not the parent, ItemSet
. The relational data table hierarchy is one to many in this order ItemSet
-> ItemName
-> ItemValue
. ItemSet
table has a unique constraint
for department id, season combination to prevent multiple duplicate adds.
I need to do some processing after catching this exception to ensure that the incoming data still gets saved under the existing ItemSet
and doesn't get lost. I am using Spring Data JPA and as soon as I catch the exception and try to retrieve the existing record I end up getting:
org.hibernate.AssertionFailure: null id in ItemSet entry (don't flush the Session after an exception occurs).
The getItemSet()
in the catch block blows up.
What is the best way to overcome these race conditions?
ItemSet savedItemSet = null;
try
{
String seasonName = itemSet.getSeasonName();
Long seasonYear = itemSet.getSeasonYear();
Long departmentId = itemSet.getDepartment().getId();
List<ItemSet> itemSets = attributeSetRepository.findBySeasonNameAndSeasonYearAndDepartmentId(
seasonName, seasonYear, departmentId);
LOGGER.info("Found {} item sets corresponding to season name : {}, season year : {}, "
"department id : {}", itemSets.size(), seasonName, seasonYear, departmentId);
if(CollectionUtils.isEmpty(itemSets)) {
savedItemSet = itemSetRepository.save(itemSet);
}
else {
return new CreatedItemSet(itemSets.get(0).getId());
}
}
catch(PersistenceException | DataIntegrityViolationException e)
{
LOGGER.error("An exception occurred while saving itemSet set", e);
if (e.getCause() instanceof ConstraintViolationException)
{
String seasonName = itemSet.getSeasonName();
Long seasonYear = itemSet.getSeasonYear();
Long deptId = itemSet.getDepartment().getId();
LOGGER.info("A duplicate item set found in the database corresponding "
"to season name : {}, season year : {} and department : {}",
seasonName, seasonYear, deptId);
ExistingItemSet existingItemSet = getItemSet(seasonName,
seasonYear, deptId);
if(existingItemSet == null) {
LOGGER.info("No item set found");
return null;
}
return new CreatedItemSet(existingItemSet.getId());
}
}
CodePudding user response:
You can't "continue". A transaction is marked for rollback and the persistence context is unusable after a constraint violation happens.
You can either try to avoid the constraint violation, by checking if the DB contains an entry before persisting/updating, or you run the rest of your code in a separate transaction if a constraint violation happens.