0

我正在使用以下测试用例测试我的声明性事务配置:

我尝试将 2 条记录插入具有 4 列(id、内容、位置、时间)的表中,而位置是唯一索引。我使用mysql 5.5和innoDB引擎,用Spring 3.2.2、Mybatis 3.2.2、Mybatis-Spring 1.2.0开发测试。下面是创建插入了实验数据的数据库和表的sql。


    CREATE DATABASE `development` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
    USE `development`;

    CREATE TABLE IF NOT EXISTS `test` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `content` varchar(256) DEFAULT NULL,
      `position` int(10) unsigned NOT NULL,
      `time` int(10) unsigned NOT NULL DEFAULT '0',
      PRIMARY KEY (`id`),
      UNIQUE KEY `position` (`position`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=97 ;

    INSERT INTO `test` (`id`, `content`, `position`, `time`) VALUES (1, 'test', 0, 1368164281),(2, '测试内容', 1, 1368164364),(44, 'bbb', 2, 1368431459),(45, 'ccc', 3, 1368431459),

这是配置xml service.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="testDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        <property name="driverClassName" value="${test.driverClass}" />
        <property name="url" value="${test.jdbcUrl}" />
        <property name="username" value="${test.user}" />
        <property name="password" value="${test.password}" />
        <property name="minPoolSize" value="${test.miniPoolSize}" />
        <property name="maxPoolSize" value="${test.maxPoolSize}" />
        <property name="initialPoolSize" value="${test.initialPoolSize}" />
        <property name="maxIdleTime" value="${test.maxIdleTime}" />
        <property name="acquireIncrement" value="${test.acquireIncrement}" />
        <property name="acquireRetryAttempts" value="${test.acquireRetryAttempts}" />
        <property name="acquireRetryDelay" value="${test.acquireRetryDelay}" />
        <property name="testConnectionOnCheckin" value="${test.testConnectionOnCheckin}" />
        <property name="automaticTestTable" value="${test.automaticTestTable}" />
        <property name="idleConnectionTestPeriod" value="${test.idleConnectionTestPeriod}" />
        <property name="checkoutTimeout" value="${test.checkoutTimeout}" />
    </bean>

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

    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true" />
            <tx:method name="add*" />
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="testServiceOperation" expression="execution(* com.ssports.test.service.TestServiceImpl.addRecords(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="testServiceOperation" />
    </aop:config>

    <bean id="TestService" class="com.ssports.test.service.TestServiceImpl" />
</beans>

下面是 test-mapper-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd">

    <bean id="recordMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="sqlSessionFactory" ref="testSqlSessionFactory" />
    <property name="mapperInterface" value="com.ssports.test.mapper.RecordMapper" />
    </bean>
</beans>

这是 serviceImpl 类:

package com.ssports.test.service;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import com.ssports.test.mapper.RecordMapper;
import com.ssports.test.model.Record;
import com.ssports.test.model.RecordExample;
import com.ssports.util.SpringHelper;

public class TestServiceImpl implements TestService {
    Logger logger = LoggerFactory.getLogger(TestServiceImpl.class);
    private static RecordMapper mapper = SpringHelper.getBean("recordMapper");

    public List<Record> getAll() {
        return mapper.selectByExample(new RecordExample());
    }

    public Record getRecordbyId(int id) {
        return mapper.selectByPrimaryKey(id);
    }

    public void addRecords(List<Record> recordList) throws Exception {
           for (Record record : recordList) {
                logger.info(record.getPosition() + ":" + record.getTime());
                    mapper.insert(record);
        }
    }

}

测试代码为:package com.ssports.db;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import com.ssports.test.model.Record;
import com.ssports.test.service.TestService;
import com.ssports.util.SpringHelper;

public class TransTest {
    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        Logger logger = LoggerFactory.getLogger(TransTest.class);

        TestService service = SpringHelper.getBean("TestService");
        List<Record> records = new ArrayList<Record>();

        Record record1 = service.getRecordbyId(1);
        Record record4 = new Record();
        record4.setContent("ddd");
        record4.setPosition(4);
        record4.setTime((int) (new Long(System.currentTimeMillis()) / 1000));

        records.add(record4);
        records.add(record1);

        DataSourceTransactionManager txManager = SpringHelper.getBean("txManager");
        try {
            service.addRecords(records);
        } catch (UnsupportedOperationException ex) {            
            logger.info(ex.getMessage());
        }

        List<Record> recordlist = service.getAll();
        for (Record item : recordlist) {
            logger.info(item.getId() + ":" + item.getContent() + ":"
                    + new Date((long) item.getTime() * 1000) + ":"
                    + item.getPosition());
        }

    }

}

我运行应用程序,这里是日志:

DEBUG: org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource - Adding transactional method [get*] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly]
DEBUG: org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource - Adding transactional method [add*] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT]
DEBUG: org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource - Adding transactional method [get*] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly]
DEBUG: org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource - Adding transactional method [add*] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT]
DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Creating new transaction with name [com.ssports.test.service.TestServiceImpl.addRecords]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Acquired Connection [org.apache.commons.dbcp.PoolableConnection@6650af3b] for JDBC transaction
DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Switching JDBC Connection [org.apache.commons.dbcp.PoolableConnection@6650af3b] to manual commit
INFO : com.ssports.test.service.TestServiceImpl - 4:1368602606
INFO : com.ssports.test.service.TestServiceImpl - 0:1368164281
DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Initiating transaction rollback
DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Rolling back JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@6650af3b]
DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Releasing JDBC Connection [org.apache.commons.dbcp.PoolableConnection@6650af3b] after transaction
INFO : com.ssports.db.TransTest - 
### Error updating database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1' for key 'PRIMARY'
### The error may involve com.ssports.test.mapper.RecordMapper.insert-Inline
### The error occurred while setting parameters
### SQL: insert into test (id, content, position,        time)     values (?, ?, ?,        ?)
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1' for key 'PRIMARY'
; SQL []; Duplicate entry '1' for key 'PRIMARY'; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1' for key 'PRIMARY'
INFO : com.ssports.db.TransTest - 1:test:Fri May 10 13:38:01 CST 2013:0
INFO : com.ssports.db.TransTest - 2:测试内容:Fri May 10 13:39:24 CST 2013:1
INFO : com.ssports.db.TransTest - 44:bbb:Mon May 13 15:50:59 CST 2013:2
INFO : com.ssports.db.TransTest - 45:ccc:Mon May 13 15:50:59 CST 2013:3
INFO : com.ssports.db.TransTest - 98:ddd:Wed May 15 15:23:26 CST 2013:4

您可以看到,当异常抛出时,事务管理器回滚数据库,但仍然插入一条记录。

有没有人可以告诉这里出了什么问题,或者它是一个错误?

更新

我尝试使用下面的代码进行编程事务,当然注释 service.xml 中的行以禁用 aop 和 txAdvice。之后,它的工作原理:

package com.ssports.test.service;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import com.ssports.test.mapper.RecordMapper;
import com.ssports.test.model.Record;
import com.ssports.test.model.RecordExample;
import com.ssports.util.SpringHelper;

public class TestServiceImpl implements TestService {
    Logger logger = LoggerFactory.getLogger(TestServiceImpl.class);
    private static RecordMapper mapper = SpringHelper.getBean("recordMapper");
    private static DataSourceTransactionManager txManager = SpringHelper.getBean("txManager");
    private static TransactionDefinition def = new DefaultTransactionDefinition();
    private static TransactionStatus status = txManager.getTransaction(def);

    public List<Record> getAll() {
        return mapper.selectByExample(new RecordExample());
    }

    public Record getRecordbyId(int id) {
        Thread t = Thread.currentThread();
        logger.debug("Thread Name: "+t.getName());
        logger.debug("Thread id: "+t.getId());
        return mapper.selectByPrimaryKey(id);
    }

    public void addRecords(List<Record> recordList) throws Exception {


        try {
        for (Record record : recordList) {
            Thread t = Thread.currentThread();
            logger.debug("Thread Name: "+t.getName());
            logger.debug("Thread id: "+t.getId());
            logger.info(record.getPosition() + ":" + record.getTime());
            mapper.insert(record);
        }
        } catch (Exception ex) {
            logger.debug("Exception throw");
            logger.debug(ex.getMessage());
            txManager.rollback(status);
            throw ex;
        }

        txManager.commit(status);
    }

}

这是日志:

2013-05-16 11:23:17 625 DEBUG: org.mybatis.spring.SqlSessionFactoryBean - Parsed configuration file: 'class path resource [config/mybatis-config.xml]'
2013-05-16 11:23:17 929 DEBUG: org.mybatis.spring.SqlSessionFactoryBean - Parsed mapper file: 'file [/home/zhangzhi/workspace-STS/MultiDb/target/classes/com/ssports/uc/mybatis/mappers/UcMemberMapper.xml]'
2013-05-16 11:23:17 948 DEBUG: org.mybatis.spring.SqlSessionFactoryBean - Parsed configuration file: 'class path resource [config/mybatis-config.xml]'
2013-05-16 11:23:18 247 DEBUG: org.mybatis.spring.SqlSessionFactoryBean - Parsed mapper file: 'file [/home/zhangzhi/workspace-STS/MultiDb/target/classes/com/ssports/site/mybatis/mappers/adMapper.xml]'
2013-05-16 11:23:18 264 DEBUG: org.mybatis.spring.SqlSessionFactoryBean - Parsed configuration file: 'class path resource [config/mybatis-config.xml]'
2013-05-16 11:23:18 316 DEBUG: org.mybatis.spring.SqlSessionFactoryBean - Parsed mapper file: 'file [/home/zhangzhi/workspace-STS/MultiDb/target/classes/com/ssports/test/mybatis/mappers/RecordMapper.xml]'
2013-05-16 11:23:18 476 DEBUG: org.mybatis.spring.SqlSessionFactoryBean - Parsed configuration file: 'class path resource [config/mybatis-config.xml]'
2013-05-16 11:23:18 546 DEBUG: org.mybatis.spring.SqlSessionFactoryBean - Parsed mapper file: 'file [/home/zhangzhi/workspace-STS/MultiDb/target/classes/com/ssports/uc/mybatis/mappers/UcMemberMapper.xml]'
2013-05-16 11:23:18 556 DEBUG: org.mybatis.spring.SqlSessionFactoryBean - Parsed configuration file: 'class path resource [config/mybatis-config.xml]'
2013-05-16 11:23:18 680 DEBUG: org.mybatis.spring.SqlSessionFactoryBean - Parsed mapper file: 'file [/home/zhangzhi/workspace-STS/MultiDb/target/classes/com/ssports/site/mybatis/mappers/adMapper.xml]'
2013-05-16 11:23:18 690 DEBUG: org.mybatis.spring.SqlSessionFactoryBean - Parsed configuration file: 'class path resource [config/mybatis-config.xml]'
2013-05-16 11:23:18 728 DEBUG: org.mybatis.spring.SqlSessionFactoryBean - Parsed mapper file: 'file [/home/zhangzhi/workspace-STS/MultiDb/target/classes/com/ssports/test/mybatis/mappers/RecordMapper.xml]'
2013-05-16 11:23:18 739 DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2013-05-16 11:23:18 740 DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Acquired Connection [org.apache.commons.dbcp.PoolableConnection@6188024d] for JDBC transaction
2013-05-16 11:23:18 747 DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Switching JDBC Connection [org.apache.commons.dbcp.PoolableConnection@6188024d] to manual commit
2013-05-16 11:23:18 748 DEBUG: com.ssports.db.TransTest - Get record1.
2013-05-16 11:23:18 749 DEBUG: com.ssports.db.TransTest - Thread Name: main
2013-05-16 11:23:18 749 DEBUG: com.ssports.db.TransTest - Thread id: 1
2013-05-16 11:23:18 749 DEBUG: com.ssports.test.service.TestServiceImpl - Thread Name: main
2013-05-16 11:23:18 749 DEBUG: com.ssports.test.service.TestServiceImpl - Thread id: 1
2013-05-16 11:23:18 754 DEBUG: org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
2013-05-16 11:23:18 757 DEBUG: org.mybatis.spring.SqlSessionUtils - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@158b6810]
2013-05-16 11:23:18 776 DEBUG: org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [org.apache.commons.dbcp.PoolableConnection@6188024d] will be managed by Spring
2013-05-16 11:23:18 777 DEBUG: com.ssports.test.mapper.RecordMapper.selectByPrimaryKey - ooo Using Connection [org.apache.commons.dbcp.PoolableConnection@6188024d]
2013-05-16 11:23:18 783 DEBUG: com.ssports.test.mapper.RecordMapper.selectByPrimaryKey - ==>  Preparing: select id, content, position, time from test where id = ? 
2013-05-16 11:23:18 807 DEBUG: com.ssports.test.mapper.RecordMapper.selectByPrimaryKey - ==> Parameters: 1(Integer)
2013-05-16 11:23:18 824 DEBUG: org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@158b6810]
2013-05-16 11:23:18 824 DEBUG: com.ssports.db.TransTest - Invoking service method[addRecords]
2013-05-16 11:23:18 824 DEBUG: com.ssports.db.TransTest - Thread Name: main
2013-05-16 11:23:18 824 DEBUG: com.ssports.db.TransTest - Thread id: 1
2013-05-16 11:23:18 824 DEBUG: com.ssports.test.service.TestServiceImpl - Thread Name: main
2013-05-16 11:23:18 824 DEBUG: com.ssports.test.service.TestServiceImpl - Thread id: 1
2013-05-16 11:23:18 824 INFO : com.ssports.test.service.TestServiceImpl - 4:1368674598
2013-05-16 11:23:18 824 DEBUG: org.mybatis.spring.SqlSessionUtils - Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@158b6810] from current transaction
2013-05-16 11:23:18 825 DEBUG: com.ssports.test.mapper.RecordMapper.insert - ooo Using Connection [org.apache.commons.dbcp.PoolableConnection@6188024d]
2013-05-16 11:23:18 825 DEBUG: com.ssports.test.mapper.RecordMapper.insert - ==>  Preparing: insert into test (id, content, position, time) values (?, ?, ?, ?) 
2013-05-16 11:23:18 825 DEBUG: com.ssports.test.mapper.RecordMapper.insert - ==> Parameters: null, ddd(String), 4(Integer), 1368674598(Integer)
2013-05-16 11:23:18 826 DEBUG: org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@158b6810]
2013-05-16 11:23:18 826 DEBUG: com.ssports.test.service.TestServiceImpl - Thread Name: main
2013-05-16 11:23:18 826 DEBUG: com.ssports.test.service.TestServiceImpl - Thread id: 1
2013-05-16 11:23:18 826 INFO : com.ssports.test.service.TestServiceImpl - 0:1368164281
2013-05-16 11:23:18 826 DEBUG: org.mybatis.spring.SqlSessionUtils - Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@158b6810] from current transaction
2013-05-16 11:23:18 826 DEBUG: com.ssports.test.mapper.RecordMapper.insert - ooo Using Connection [org.apache.commons.dbcp.PoolableConnection@6188024d]
2013-05-16 11:23:18 826 DEBUG: com.ssports.test.mapper.RecordMapper.insert - ==>  Preparing: insert into test (id, content, position, time) values (?, ?, ?, ?) 
2013-05-16 11:23:18 826 DEBUG: com.ssports.test.mapper.RecordMapper.insert - ==> Parameters: null, test(String), 0(Integer), 1368164281(Integer)
2013-05-16 11:23:18 871 DEBUG: org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@158b6810]
2013-05-16 11:23:18 871 DEBUG: com.ssports.test.service.TestServiceImpl - Exception throw
2013-05-16 11:23:18 871 DEBUG: com.ssports.test.service.TestServiceImpl - 
### Error updating database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '0' for key 'position'
### The error may involve com.ssports.test.mapper.RecordMapper.insert-Inline
### The error occurred while setting parameters
### SQL: insert into test (id, content, position,        time)     values (?, ?, ?,        ?)
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '0' for key 'position'
; SQL []; Duplicate entry '0' for key 'position'; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '0' for key 'position'
2013-05-16 11:23:18 871 DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Initiating transaction rollback
2013-05-16 11:23:18 871 DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Rolling back JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@6188024d]
2013-05-16 11:23:18 907 DEBUG: org.mybatis.spring.SqlSessionUtils - Transaction synchronization rolling back SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@158b6810]
2013-05-16 11:23:18 907 DEBUG: org.mybatis.spring.SqlSessionUtils - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@158b6810]
2013-05-16 11:23:18 908 DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Releasing JDBC Connection [org.apache.commons.dbcp.PoolableConnection@6188024d] after transaction
2013-05-16 11:23:18 909 DEBUG: com.ssports.db.TransTest - Exception throw
2013-05-16 11:23:18 909 DEBUG: com.ssports.db.TransTest - 
### Error updating database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '0' for key 'position'
### The error may involve com.ssports.test.mapper.RecordMapper.insert-Inline
### The error occurred while setting parameters
### SQL: insert into test (id, content, position,        time)     values (?, ?, ?,        ?)
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '0' for key 'position'
; SQL []; Duplicate entry '0' for key 'position'; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '0' for key 'position'
2013-05-16 11:23:18 909 DEBUG: com.ssports.db.TransTest - Checking Result
2013-05-16 11:23:18 909 DEBUG: org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
2013-05-16 11:23:18 909 DEBUG: org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2c8446f7] was not registered for synchronization because synchronization is not active
2013-05-16 11:23:18 929 DEBUG: org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [org.apache.commons.dbcp.PoolableConnection@6188024d] will not be managed by Spring
2013-05-16 11:23:18 929 DEBUG: com.ssports.test.mapper.RecordMapper.selectByExample - ooo Using Connection [org.apache.commons.dbcp.PoolableConnection@6188024d]
2013-05-16 11:23:18 929 DEBUG: com.ssports.test.mapper.RecordMapper.selectByExample - ==>  Preparing: select id, content, position, time from test 
2013-05-16 11:23:18 930 DEBUG: com.ssports.test.mapper.RecordMapper.selectByExample - ==> Parameters: 
2013-05-16 11:23:18 931 DEBUG: org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2c8446f7]
2013-05-16 11:23:18 932 INFO : com.ssports.db.TransTest - 1:test:Fri May 10 13:38:01 CST 2013:0
2013-05-16 11:23:18 932 INFO : com.ssports.db.TransTest - 2:测试内容:Fri May 10 13:39:24 CST 2013:1
2013-05-16 11:23:18 932 INFO : com.ssports.db.TransTest - 44:bbb:Mon May 13 15:50:59 CST 2013:2
2013-05-16 11:23:18 932 INFO : com.ssports.db.TransTest - 45:ccc:Mon May 13 15:50:59 CST 2013:3

这是 SpringHelper 类:

package com.ssports.util;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringHelper {

    private static Log logger = LogFactory.getLog(SpringHelper.class);

    private static ApplicationContext cx = null;

    @SuppressWarnings("unchecked")
    public static <T> T getBean(String beanId){
        if(cx == null){
          cx = new ClassPathXmlApplicationContext("classpath:spring/application-context.xml");
        }
        return (T)cx.getBean(beanId);
    }

    public synchronized static void init(){
        if(cx == null){
          cx = new ClassPathXmlApplicationContext("classpath:spring/application-context.xml");
          logger.info("Spring config success!,ApplicationContext set a object");
        }
    }

    public synchronized static void init(String[] paths){

        if(cx == null){
          cx = new ClassPathXmlApplicationContext(paths);
          logger.info("Spring config success!,ApplicationContext set a object");
        }

    }

    public synchronized static void init(String path){

        init(new String[]{path});
    }

}

更新 了我对TestServiceImpl做了一点改动,已经解决了,如下:

private static RecordMapper mapper;

public void init() {
    if (null == mapper) {
        mapper = (RecordMapper) SpringHelper.getBean("recordMapper");
    }
}
4

1 回答 1

1

问题:

我会说问题出在您的 SpringHelper 类实现以及您如何使用它(即 TestServiceImpl 中的静态引用)。您可能初始化了两个 Spring 上下文(此症状包含在日志文件的前 4 行中)。

为什么它不起作用:

一个上下文中的事务+回滚对另一个上下文建立的数据库连接没有任何影响(都有自己的testDataSourcetxManagerbean)。

如何解决:

Spring 是一个依赖注入框架,所以我看不出实现你自己的依赖查找策略的意义。您可能需要检查Autowired注释以获取依赖项(例如 your TestServiceImpl.mapper)。

查看 Spring 文档和演示项目(例如https://github.com/SpringSource/greenhouse),了解如何充分利用 Spring。尝试以标准方式使用 Spring

其他 AOP 问题:

顺便提一句。您的切入点定义不正确,因为只读建议不包括在内。

于 2013-05-15T23:25:24.183 回答