通过Spring Boot / JPA和MySQL进行“upsert”时,我遇到了避免死锁的麻烦。我异步调用服务层中的方法,因此单个请求可以同时多次调用upsert,同时也可以有多个请求。性能也是一个考虑因素。我需要做些什么来避免死锁?
这是我的Spring JPA方法:
@Modifying
@Transactional
@Query(value = "INSERT INTO message_resource (organizationId, messageId, bucket, friendlyName, fullPathName, uuid, md5, contentType, reference, size, created, updated)\n" +
"VALUES (:organizationId, :messageId, :bucket, :friendlyName, :fullPathName, :uuid, :md5, :contentType, :reference, :size, :created, :updated)\n" +
"ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), friendlyName=:friendlyName, uuid=:uuid, md5=:md5, contentType=:contentType, reference=:reference, size=:size, created=:created, updated=:updated", nativeQuery = true)
int upsert(
@Param("organizationId") long organizationId,
@Param("messageId") long messageId,
@Param("bucket") String bucket,
@Param("friendlyName") String friendlyName,
@Param("fullPathName") String fullPathName,
@Param("uuid") String uuid,
@Param("md5") String md5,
@Param("contentType") String contentType,
@Param("reference") String reference,
@Param("size") long size,
@Param("created") long created,
@Param("updated") long updated);
这是我的服务层呼叫:
@Async
public void upsert() throws IOException {
...
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
messageResourceRepository.upsert(
mediaObject.getOrganizationId(),
mediaObject.getMessageId(),
messageResourceEntity.getBucket(),
messageResourceEntity.getFriendlyName(),
messageResourceEntity.getFullPathName(),
messageResourceEntity.getUuid(),
messageResourceEntity.getMd5(),
messageResourceEntity.getContentType(),
messageResourceEntity.getReference(),
messageResourceEntity.getSize(),
messageResourceEntity.getCreated(),
messageResourceEntity.getUpdated()
);
entityManager.getTransaction().commit();
entityManager.close();
...
}