MySQL триггер работает через прямую вставку, но не при фиксации через Hibernate - PullRequest
1 голос
/ 27 февраля 2020

У меня есть следующий фрагмент, который мы используем для сохранения сущности в нашей БД:

private void singleStatusChange( Employee employee , OrderStatusType type , String comment , String classification ){
        try( CloseableEntityManager em = HibernateUtil.getEntityManager() ){
            em.beginTransaction();
            OrderStatusChangeRequest orderStatusChangeRequest = new OrderStatusChangeRequest();
            orderStatusChangeRequest.setOrder( em.getEntityReferenceById( Order.class , this.getId() ) );
            orderStatusChangeRequest.setOrderStatusType( type );
            orderStatusChangeRequest.setEmployee( employee );
            orderStatusChangeRequest.setComment( comment );
            orderStatusChangeRequest.setClassification( classification );
            //When this entry is being persisted a BEFORE INSERT Trigger is activated and 1.- Check if status change is feasible, 2.- Expire all previous order statuses, 3.- Updates order lastHandledBy
            em.persist( orderStatusChangeRequest );
            em.commit();
        }catch ( Exception e ){
            e.printStackTrace();
            throw new InvalidOrderStatusChangeException( e );
        }
    }

Когда это происходит, перед INSERT запускается триггер, который заботится о дополнительных бизнес-логиках c для наше приложение. Все, кроме одного утверждения, завершено, и я не совсем уверен, почему это так. Это наш триггер:

CREATE DEFINER=`gofarma`@`%` TRIGGER OrderStatusChangeRequestsBeforeInsert
BEFORE INSERT
ON OrderStatusChangeRequests FOR EACH ROW
BEGIN
    SELECT COUNT(1) INTO @IsNewStatusPossible FROM OrderStatusTypeFlows ostf WHERE ostf.`To` = NEW.Status AND ostf.`From` IS NULL ;

    SELECT COUNT(1) INTO @IsPossible FROM OrderStatusTypeFlows ostf WHERE ostf.`To` = NEW.Status AND ostf.`From` = ( SELECT o.Status FROM Orders o WHERE o.ID = NEW.`Order` LIMIT 1 );

    SELECT COUNT(1) INTO @IsImpossible FROM OrderStatusTypeFlows ostf WHERE ostf.`To` = NEW.Status AND ostf.`NeverIfThisPresent` IN ( SELECT `OrderStatusType` FROM OrderHistoryEntries WHERE `Order` = NEW.`Order` ) ;

    SELECT COUNT(1) INTO @IsAdmin FROM Employees e LEFT JOIN EmployeeRoles er ON e.ID = er.EmployeeID LEFT JOIN Roles r ON er.RoleID = r.ID
    WHERE r.IsAdmin AND e.ID = NEW.Employee;

    IF( ( ( @IsPossible = 0 AND @IsNewStatusPossible = 0 ) OR @IsImpossible > 0 ) AND @IsAdmin = 0 ) THEN
        SIGNAL SQLSTATE '12345' set message_text='com.gofarma.olimpo.exceptions.InvalidOrderStatusChangeException';
    END IF;

    UPDATE OrderHistoryEntries os SET os.EffectiveTo = CURRENT_TIMESTAMP WHERE os.`Order` = NEW.`Order` AND os.EffectiveTo > CURRENT_TIMESTAMP;

    INSERT INTO OrderHistoryEntries
    (ID, Comment, EffectiveFrom, EffectiveTo, OrderStatusType, PrescriptionAction, SystemFrom, SystemTo, `Type`, Employee, `Order`)
    VALUES(UUID(), NEW.Comment, current_timestamp(), '9999-12-31 23:59:59', CASE
        WHEN NEW.Status = 0 THEN 'NEW'
        WHEN NEW.Status = 1 THEN 'PACKED'
        WHEN NEW.Status = 2 THEN 'SENT'
        WHEN NEW.Status = 3 THEN 'COMPLETED'
        WHEN NEW.Status = 4 THEN 'CANCELED'
        WHEN NEW.Status = 5 THEN 'UNKNOWN'
        WHEN NEW.Status = 6 THEN 'COLLECTED'
        WHEN NEW.Status = 7 THEN 'DELIVERED'
        WHEN NEW.Status = 8 THEN 'PRECOMPLETED'
        WHEN NEW.Status = 9 THEN 'RESENT'
        WHEN NEW.Status = 10 THEN 'UNPAID'
        WHEN NEW.Status = 11 THEN 'UNDELIVERED'
        WHEN NEW.Status = 12 THEN 'PENDING'
        WHEN NEW.Status = 13 THEN 'WAITING_FOR_ADVANCE'
        WHEN NEW.Status = 14 THEN 'ADVANCE_PICKED'
        WHEN NEW.Status = 15 THEN 'ADVANCE_NOT_PICKED'
    END, NULL, current_timestamp(), '9999-12-31 23:59:59', 'ORDER_STATUS', NEW.Employee, NEW.`Order`);

    UPDATE Orders o SET o.LastHandledBy = NEW.Employee , o.Status = NEW.Status WHERE o.ID = NEW.`Order`;

    IF( NEW.Status IN ( 3 , 8 , 9 , 10 , 12 ) ) THEN
        UPDATE Trips t JOIN TripOrders ot ON ot.TripID = t.ID JOIN DriverShifts ds ON ds.Driver = t.Driver
        SET t.status = 1 , t.closeComment = NEW.Comment , t.arrivalTime = CURRENT_TIMESTAMP , t.realEndTime = COALESCE( t.realEndTime , CURRENT_TIMESTAMP ) , ds.AvailableSince = CURRENT_TIMESTAMP
        WHERE ot.OrderID = NEW.`Order` AND t.Status = 0 AND !t.IsTransporter;
    END IF;

    IF( (SELECT `PrescriptionAction` FROM `Orders` `o` WHERE `o`.`ID` = NEW.`Order`) <> 0 AND NEW.`Status` = 8) THEN
        UPDATE `Orders` `o` SET `o`.`PrescriptionNumber` = (
            SELECT 
                COALESCE(MAX(`PrescriptionNumber`),0)+1
            FROM 
                Orders
            WHERE 
                `PrescriptionAction` = `o`.`PrescriptionAction`
            AND
                `Branch` = `o`.`Branch`
            GROUP BY `Branch`) WHERE `o`.`ID` = NEW.`Order`;
    END IF;
END

Бит, который не выполняется должным образом, следующий:

    UPDATE Orders o SET o.LastHandledBy = NEW.Employee , o.Status = NEW.Status WHERE o.ID = NEW.`Order`;

Все остальное вставляется и обновляется. Однако это утверждение не выполняется вообще. Это происходит только всякий раз, когда мы сохраняем сущность через Hibernate, если мы должны выполнить запрос для вставки новой записи в нашу таблицу OrderStatusChangeRequest, все будет работать так, как ожидается. Есть что-то, чего нам не хватает? Наш файл hibernate.cfg. xml содержит следующее:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration">

<hibernate-configuration>
    <session-factory>
        <property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
        <property name="connection.provider_class">org.hibernate.hikaricp.internal.HikariCPConnectionProvider</property>
        <property name="connection.pool_size">500</property>
        <!--<property name="connection.autoReconnect">true</property>-->
        <!--<property name="connection.autoReconnectForPools">true</property>-->
        <property name="hibernate.dialect.storage_engine">innodb</property>
        <!--<property name="connection.release_mode">ON_CLOSE</property>-->
        <!--<property name="show_sql">true</property>-->
        <!--<property name="hbm2ddl.auto">update</property>-->

        <property name="hibernate.hikari.leakDetectionThreshold">30000</property>

        <property name="hibernate.connection.autocommit">true</property>
    </session-factory>
</hibernate-configuration>

В качестве дополнительной информации CloseableEntityManager - это просто оболочка для EntityManager, которая реализует Autocloseable:

    public CloseableEntityManager beginTransaction() {
        if (this.getTransaction().isActive()) return this;
        this.getTransaction().begin();
        return this;
    }

    public void commit() {
        this.getTransaction().commit();
    }

    @Override
    public void close() {
        logger.debug( String.format("Entity Manager %s close call",this.id) );
        if( this.entityManager == null ) return;
        boolean isActive = this.entityManager.getTransaction().isActive();
        if( isActive || readOnly ){
            logger.debug( String.format("Entity Manager %s transaction was active, rolling back",this.id) );
            this.entityManager.getTransaction().rollback();
        }
        this.entityManager.close();
    }

1 Ответ

0 голосов
/ 27 февраля 2020

Как описано в комментарии к вопросу, использование @DynamicUpdate сработало в моем случае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...