Исключение тупиковой ситуации при использовании jpa с eclipselink на SQL сервере - PullRequest
0 голосов
/ 17 апреля 2020

Я постоянно получаю много исключений тупиковой ситуации.

Я пытаюсь быть максимально подробным и вынимаю весь код, который не имеет отношения.

База данных: SQL Сервер

Зависимости

javax.persistence: javax.persistence-api: 2.2

org.eclipse.persistence: eclipselink: 2.7.0

Классы сущностей

У меня просто есть два класса сущностей, Ticket и Tasks, и один Ticket может иметь много задач.

@Entity 
class Ticket {
    //Ticket doesnt have any mention to task
    ...
    String status;

    //getters and setters

}

@Entity 
class Task {
    //There is no cascade for updates
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "request_id")
    @MapsId("requestId")
    private Ticket ticket; 

}

Класс обслуживания


 public void insertTicketAndTasks(Ticket ticket, ...) throws Exception {        
        //entityManagerFactory is a singleton initialized at startup
        EntityManager entitymanager = entityManagerFactory.createEntityManager(); 
            entitymanager.getTransaction().begin();
            entitymanager.persist(ticket);
            for (some loop) {
                Task task = new Task(....);
                entitymanager.persist(task);
            }            
            entitymanager.getTransaction().commit();
            entitymanager.close();
}


private List<Ticket> updateTickets(List<Ticket> tickets) {
        ////entityManagerFactory is a singleton initialized at startup
        EntityManager entitymanager = entityManagerFactory.createEntityManager();
        List<Ticket> ret = new ArrayList<>();
        for (Ticket ticket : tickets) {
            ticket.updateLastUpdatedByAndDate(LocalDateTime.now());
            ret.add(entityManager.merge(ticket));
        }
        entitymanager.close();
        return ret;
}

Бизнес-класс

Ticket ticket = new Ticket(....)
insertTicketAndTasks(ticket, ....)
//do some operation and set status based on that operation
ticket.setStatus(...);
updateTickets(Collections.singletonList(ticket));

Вот трассировка исключения

01:30:40.095 [main] DEBUG eclipselink.logging.sql - UPDATE ticket SET last_updated_date = ?, status = ?, VERSION = ? WHERE ((request_id = ?) AND (VERSION = ?))
        bind => [2020-03-25T01:30:40.094, READY_TO_PUBLISH, 2, 001aff45-1f40-413a-be67-2167a4055854, 1]
01:30:51.197 [main] DEBUG eclipselink.logging.sql - SELECT 1
01:30:51.201 [main] WARN  eclipselink.logging.all -
org.eclipse.persistence.exceptions.DatabaseException:
Internal Exception: com.microsoft.sqlserver.jdbc.SQLServerException: Transaction (Process ID 57) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
Error Code: 1205
Call: UPDATE ticket SET last_updated_date = ?, status = ?, VERSION = ? WHERE ((request_id = ?) AND (VERSION = ?))
        bind => [2020-03-25T01:30:40.094, READY_TO_PUBLISH, 2, 001aff45-1f40-413a-be67-2167a4055854, 1]
Query: UpdateObjectQuery(db.entity.Ticket@351ede23)
        at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:331)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:905)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:967)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:637)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:564)

I Я уверен, что над этим объектом заявки не работает никакой другой процесс.

На основании некоторых других связанных сообщений я обновляю SQL Настройки изоляции сервера до

SET ALLOW_SNAPSHOT_ISOLATION ON  
SET READ_COMMITTED_SNAPSHOT ON

Но это не сильно помочь.

...