简体   繁体   中英

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. 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.

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. 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

@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

<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:

    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.

Got it working by using TransactionManager. The changes I make to my code base are mentioned below.

applicationContext.xml (updated)

  <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)

 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;
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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