I'm currently designing an image tag system. There's a n..m relationship from image to tag. The tag itself is restricted with a unique constraint.
Now let's say the user uploads an image with tags [animal,magic,summer]
. The tag might exist in the database already, or might not exist. If it doesn't, it must be inserted. Now I cannot make a select and insert the missing tags, because two threads might to that in parallel, and one upload will fail due to unique constraint violation.
My current design works, but seems very unperformant (one insert per tag). I have to use a new transaction for these inserts due to postgres restrictions of type ERROR: current transaction is aborted, commands ignored until end of transaction block
. Is there any better way?
@Override
@Transactional
public String createImageEntry(MyDto myDto, long accountId) {
for (String tag : myDto.getTags()) {
insertTags(tag);
}
Set<ImageTag> tags = myDto.getTags().stream().map(s -> imageTagRepository.findByTag(s).orElseThrow()).collect(Collectors.toSet());
Image image = new Image(...);
imageRepository.persist(image);
return image.getExternalKey();
}
@Transactional(Transactional.TxType.REQUIRES_NEW)
public void insertTags(String tag) {
ImageTag imageTag = new ImageTag();
imageTag.setTag(tag);
try {
imageTagRepository.persistAndFlush(imageTag);
} catch (PersistenceException ignored) {
}
}