【问题标题】:Not able insert records in multiple tables using @Transactional and cn.setAutoCommit(false) with spring jdbcTemplate无法使用 @Transactional 和带有 spring jdbcTemplate 的 cn.setAutoCommit(false) 在多个表中插入记录
【发布时间】:2017-11-26 01:30:47
【问题描述】:

我有一个 DAO 类中的一个方法,它在 2 个不同的 Oracle 表中插入记录。我希望记录要么插入表中,要么不插入。

为了实现这一点,我同时使用了 @Transactionalcn.setAutoCommit(false) 代码 sn-p。

为了测试,我故意把SQL的列名放错了,导致第二张表的数据插入失败。我的期望是,由于查询不正确,第二个表中的插入失败,因此数据不会插入到第一个表中。但由于某种原因,这并没有发生。记录仍然插入到第一个表中,第二个表没有插入记录。

看起来这里的实现不正确。不确定我在这里缺少什么。

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>

请指导。

【问题讨论】:

  • 我不确定,但我认为您使用的连接与事务处理的连接不同,当您从数据源检索连接时,此连接与事务无关,除非您是使用 JTA 事务和一些包装器。您必须区分容器和数据库事务,您能否发布有关您的配置的更多信息?
  • @karelss - 不确定这是否有帮助,但只是使用 applicationContext 配置更新了原始帖子

标签: java spring oracle spring-jdbc spring-transactions


【解决方案1】:

我想您应该将transactionTemplate 与您的jdbcTemplate 一起使用:

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

});

你可能没有配置 JTA,你的@Transactional 没有效果。

【讨论】:

  • 谢谢,我试试看。
【解决方案2】:

使用 TransactionManager 让它工作。下面提到了我对代码库所做的更改。

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(更新)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-24
    • 1970-01-01
    • 2019-06-30
    • 2016-02-21
    相关资源
    最近更新 更多