简体   繁体   English

无法将@Transactional和cn.setAutoCommit(false)与Spring jdbcTemplate一起插入多个表中的记录

[英]Not able insert records in multiple tables using @Transactional and cn.setAutoCommit(false) with spring jdbcTemplate

I have a method in one of the DAO class that is inserting records in 2 different Oracle tables. 我在DAO类之一中有一个方法,可以在2个不同的Oracle表中插入记录。 I would like the records to be either inserted in both the table or none. 我希望将记录插入到表中或都不插入到表中。

In order to achieve this I am using both @Transactional and cn.setAutoCommit(false) code snippet. 为了实现这一点,我同时使用了@Transactionalcn.setAutoCommit(false)代码段。

In order to test it, I intentionally put in a wrong column name in the SQL so that data insertion in the second table fails. 为了对其进行测试,我故意在SQL中输入了错误的列名,从而导致第二个表中的数据插入失败。 The expectation, from me, here is that the data will not get inserted in the first table since the insertion in second table failed because of incorrect query. 我的期望是,由于查询错误而无法在第二张表中插入数据,因此不会在第一张表中插入数据。 But that didn't happen for some reason. 但这由于某种原因没有发生。 The record still got inserted in first table and the second table did not have the record inserted. 记录仍然插入到第一个表中,而第二个表没有插入记录。

It looks like the implementation is not incorrect here. 看起来这里的实现并不正确。 Not sure what I am missing here. 不知道我在这里想念的是什么。

EventLogDao.java EventLogDao.java

@Transactional
public long saveEventData(EventLog eventLog, String userId) throws SQLException {
        Connection cn = this.dataSource.getConnection();
        cn.setAutoCommit(false);

        //(FIRST TABLE INSERTION - Table Name: EVENT_LOG)
        //save data in event log table 
        long eventId = getNextEventIdSequence();
        saveEventLogData(eventId, eventLog);

        //(SECOND TABLE INSERTION - Table Name: EVENT_LOG_MESSAGE)
        //save data in event log message table
        saveEventLogMessageData(eventId, eventLog.getEventLogMessage());

        cn.commit();
        return eventId;
    }


 private void saveEventLogData(long eventId, EventLog eventLog) {
        Object[] parameters = {eventId, eventLog.getRouteId(), eventLog.getEventType().getEventTypeId(),
            eventLog.getOrderId(), eventLog.getIncomingEventTimestamp(), eventLog.getOutgoingEventTimestamp()};
        int[] types = {Types.INTEGER, Types.INTEGER, Types.INTEGER, Types.VARCHAR, Types.TIMESTAMP, Types.TIMESTAMP};
        int rowsAffected = jdbcTemplate.update(INSERT_EVENT_LOG_SQL2, parameters, types);
        System.out.println("rowsAffected (eventlog) = " + rowsAffected);
    }


private int saveEventLogMessageData(long eventId, EventLogMessage eventLogMessage) {
        Object[] parameters = {eventId, eventLogMessage.getIncomingEventMessage(), eventLogMessage.getOutgoingEventMessage()};
        int[] types = {Types.INTEGER, Types.VARCHAR, Types.VARCHAR};
        int rowsAffected = jdbcTemplate.update(INSERT_EVENT_LOG_MESSAGE_SQL2, parameters, types);
        System.out.println("rowsAffected (eventLogMessage) = " + rowsAffected);
        return rowsAffected;
    }

applicationContext.xml applicationContext.xml中

<bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <constructor-arg>
            <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <property name="dataSource" ref="dataSource"/>
            </bean>
        </constructor-arg>
        <property name="propagationBehavior">
            <util:constant static-field="org.springframework.transaction.support.DefaultTransactionDefinition.PROPAGATION_REQUIRED"/>
        </property>
        <property name="isolationLevel">
            <util:constant static-field="org.springframework.transaction.support.DefaultTransactionDefinition.ISOLATION_READ_COMMITTED"/>
        </property>
    </bean>


<bean id="eventLogDao" class="com.ebayenterprise.publicapi.events.dao.EventLogDao">
    <constructor-arg ref="dataSource" />
</bean>

Please guide. 请指导。

I suppose that you should use transactionTemplate with your jdbcTemplate together: 我想您应该将transactionTemplatejdbcTemplate一起使用:

    public long saveEventData(EventLog eventLog, String userId) throws SQLException {
        return transactionTemplate.execute(new TransactionCallback<Long>(){
        @Override
        public Long doInTransaction(TransactionStatus transactionStatus) {
        try {
            Connection cn = this.dataSource.getConnection();
            cn.setAutoCommit(false);

            //(FIRST TABLE INSERTION - Table Name: EVENT_LOG)
            //save data in event log table 
            long eventId = getNextEventIdSequence();
            saveEventLogData(eventId, eventLog);

            //(SECOND TABLE INSERTION - Table Name: EVENT_LOG_MESSAGE)
            //save data in event log message table
            saveEventLogMessageData(eventId, eventLog.getEventLogMessage());

            cn.commit();
            return eventId;
        } catch (Exception e) {
            transactionStatus.setRollbackOnly();
        }
        return 0;
    }

});

You probably has not configuration for JTA and your @Transactional has no effect. 您可能没有JTA的配置,并且@Transactional无效。

Got it working by using TransactionManager. 使用TransactionManager使它正常工作。 The changes I make to my code base are mentioned below. 下面提到我对代码库所做的更改。

applicationContext.xml (updated) applicationContext.xml(已更新)

  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <constructor-arg ref="transactionManager"/>
        <property name="propagationBehavior">
            <util:constant static-field="org.springframework.transaction.support.DefaultTransactionDefinition.PROPAGATION_REQUIRED"/>
        </property>
        <property name="isolationLevel">
            <util:constant static-field="org.springframework.transaction.support.DefaultTransactionDefinition.ISOLATION_READ_COMMITTED"/>
        </property>
    </bean>

<bean id="eventLogDao" class="com.ebayenterprise.publicapi.events.dao.EventLogDao">
    <constructor-arg index="0" ref="dataSource" />
    <constructor-arg index="1" ref="transactionManager"/>
</bean>

EventLogDao.java (updated) EventLogDao.java(已更新)

 public EventLogDao(DataSource dataSource, PlatformTransactionManager transactionManager) {
        super(dataSource, transactionManager);
    }

    public long save(EventLog eventLog, String userId) throws Exception {
        TransactionDefinition txDef = new DefaultTransactionDefinition();
        TransactionStatus txStatus = transactionManager.getTransaction(txDef);
        long eventId = 0L;
        try {
            eventId = getNextEventIdSequence();
            System.out.println("eventId = " + eventId);
            saveEventLogData(eventId, eventLog);
            saveEventLogMessageData(eventId, eventLog.getEventLogMessage());
            userId = StringUtils.defaultIfBlank(userId, DEFAULT_USER_ID);
            saveEventLogAuditData(eventId, userId, eventLog.getOutgoingEventTimestamp());
            transactionManager.commit(txStatus);
        } catch (TransactionException ex) {
            transactionManager.rollback(txStatus);
            throw new RuntimeException("Error occurred during tx management in event log tables...", ex);
        } finally {
            return eventId;
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM