The problem background
- Unique_format_content_language (format_content_id, LANGUage_code) is a federated index for an old table to ensure data uniqueness during development. After adding a unique index, there is an MQ linkage business scenario where consumption keeps reporting errors:
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [unique_format_content_language] ...
Copy the code
- The basic logic for MQ consumption in this business scenario (the following steps are in a transaction) :
- MQ to receive changes to data
- Incremental translation data
- Delete old translations
- Save the new translation
- The DAO uses spring-data-jPA as follows:
@Repository
public interface KnowledgeContentTranslationRepository extends JpaRepository<ContentTranslationItem.String>{}Copy the code
Problem locating process and solution
- Try to use debug mode, hit a breakpoint in the error area, from the data there is no problem.
- KnowledgeContentTranslationRepository. Delete (deleteContentTranslationItems) deleted resources of translation
- KnowledgeContentTranslationRepository. Save (addContentTranslationItems) added translation of resources
- However, with hibernate SQL logs, you can see that the INSERT statement is executed first. The DELETE method is not executed before the INSERT statement is executed
- So you can assume that there are some features of the JPA framework that are responsible
- Search for the corresponding problem on Github by Google keyword searchissue
- Many people in this issue also encountered the problem of unique index error when delete then Save
- By checking the discussion record of this issue, you can find the corresponding two solutions (both of which are verified to be feasible)
- Use deleteInBatch instead of DELETE
- After delete, call the flush method manually
conclusion
- Spring-data-jpa does not execute delete statements first, but inserts statements directly when a transaction commits when the delete method is called first and then the save method is called
- In this case, a unique index conflict is possible if the table has a unique index. Exception information is as follows:
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [unique_format_content_language] ... Copy the code
- For delete then Save, where a unique index error occurs, consider the following two scenarios to avoid the error
- Use deleteInBatch instead of DELETE
- Recommend it. Delete from [table_name] where id=? or id=? . SQL to execute. When deleting data is too large, there might be a Java. Lang. StackOverflowError anomalies
- After delete, call the flush method manually
- Not really. Because the flush method synchronizes all data prior to the method to DB, there may be performance issues
- Use deleteInBatch instead of DELETE
legacy
- Spring-data-jpa delete then save Why is JPA designed this way?