Spring托管事务导致关闭连接

时间:2016-09-26 17:43:16

标签: spring transactions mybatis spring-jdbc spring-transactions

我有一个连接到多个数据库的应用程序。在我尝试将Spring Transaction Management添加到其中一个数据库连接之前,一切正常。

自从我向服务方法添加@Transactional注释后,数据库连接将对第一个托管事务正常工作。但是,在该事务完成后,它看起来像实际的数据库连接关闭,但逻辑连接对象认为连接仍然是打开的。结果是使用该连接的任何后续数据库调用都失败了" Closed Connection"错误。

换句话说,这些方案都有效:

  • 没有@Transactional
  • 的任何读取或写入操作序列
  • @Transactional流程,第一次
  • 完全相同的流程除了删除了@Transactional属性,重复任意次数

仅在应用程序运行带有@Transactional注释的方法后才会出现此问题。如果事务成功提交或回滚,则无关紧要。

请参阅下面的详细课程和日志。他们已经匿名为SO,所以任何错别字都只是错别字。

我第一次点击数据库时,一切都很完美。这就是我在日志中看到的内容:

DEBUG 26 Sep 2016 13:15:00,659 () interceptor.RestServiceLoggingInterceptor preHandle 48 - Received request at path /service/trial/tmr/submit:
DEBUG 26 Sep 2016 13:15:01,259 () datasource.DataSourceTransactionManager getTransaction 367 - Creating new transaction with name [com.example.service.shipping.createShipment]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; 'shippingTxManager',-java.lang.Exception
DEBUG 26 Sep 2016 13:15:01,260 () datasource.DataSourceTransactionManager doBegin 206 - Acquired Connection [ConnectionHandle{url=jdbc:oracle:thin:@//example.com:1535/SCHEMA, user=user, debugHandle=null, lastResetAgoInSec=94, lastUsedAgoInSec=94, creationTimeAgoInSec=94}] for JDBC transaction
DEBUG 26 Sep 2016 13:15:01,265 () datasource.DataSourceTransactionManager doBegin 223 - Switching JDBC Connection [ConnectionHandle{url=jdbc:oracle:thin:@//example.com:1535/SCHEMA, user=user, debugHandle=null, lastResetAgoInSec=94, lastUsedAgoInSec=94, creationTimeAgoInSec=94}] to manual commit
DEBUG 26 Sep 2016 13:15:01,268 () transaction.SpringManagedTransaction openConnection 86 - JDBC Connection [ConnectionHandle{url=jdbc:oracle:thin:@//example.com:1535/SCHEMA, user=user, debugHandle=null, lastResetAgoInSec=94, lastUsedAgoInSec=94, creationTimeAgoInSec=94}] will be managed by Spring
<snip a bunch of select, insert, and update statements>
DEBUG 26 Sep 2016 13:15:02,223 () datasource.DataSourceTransactionManager processCommit 759 - Initiating transaction commit
DEBUG 26 Sep 2016 13:15:02,223 () datasource.DataSourceTransactionManager doCommit 269 - Committing JDBC transaction on Connection [ConnectionHandle{url=jdbc:oracle:thin:@//example.com:1535/SCHEMA, user=user, debugHandle=null, lastResetAgoInSec=95, lastUsedAgoInSec=95, creationTimeAgoInSec=95}]
DEBUG 26 Sep 2016 13:15:02,271 () datasource.DataSourceTransactionManager doCleanupAfterCompletion 327 - Releasing JDBC Connection [ConnectionHandle{url=jdbc:oracle:thin:@//example.com:1535/SCHEMA, user=user, debugHandle=null, lastResetAgoInSec=95, lastUsedAgoInSec=95, creationTimeAgoInSec=95}] after transaction
DEBUG 26 Sep 2016 13:15:02,271 () datasource.DataSourceUtils doReleaseConnection 327 - Returning JDBC Connection to DataSource

这是我在后续尝试的日志中看到的:

DEBUG 26 Sep 2016 13:23:38,235 () datasource.DataSourceTransactionManager getTransaction 367 - Creating new transaction with name [com.example.service.shipping.createShipment]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; 'shippingTxManager',-java.lang.Exception
DEBUG 26 Sep 2016 13:23:38,236 () datasource.DataSourceTransactionManager doBegin 206 - Acquired Connection [ConnectionHandle{url=jdbc:oracle:thin:@//example.com:1535/SCHEMA, user=user, debugHandle=null, lastResetAgoInSec=1, lastUsedAgoInSec=602, creationTimeAgoInSec=612}] for JDBC transaction
DEBUG 26 Sep 2016 13:23:38,236 () datasource.DataSourceTransactionManager doBegin 223 - Switching JDBC Connection [ConnectionHandle{url=jdbc:oracle:thin:@//example.com:1535/SCHEMA, user=user, debugHandle=null, lastResetAgoInSec=1, lastUsedAgoInSec=602, creationTimeAgoInSec=612}] to manual commit
DEBUG 26 Sep 2016 13:23:38,236 () ShippingMapper.getShipmentInfo debug 142 - ==>  Preparing: select * from shipments where shipment_id = ?
DEBUG 26 Sep 2016 13:23:38,271 () datasource.DataSourceTransactionManager processRollback 851 - Initiating transaction rollback
DEBUG 26 Sep 2016 13:23:38,272 () datasource.DataSourceTransactionManager doRollback 284 - Rolling back JDBC transaction on Connection [ConnectionHandle{url=jdbc:oracle:thin:@//example.com:1535/SCHEMA, user=user, debugHandle=null, lastResetAgoInSec=1, lastUsedAgoInSec=602, creationTimeAgoInSec=612}]
DEBUG 26 Sep 2016 13:23:38,316 () datasource.DataSourceTransactionManager doCleanupAfterCompletion 327 - Releasing JDBC Connection [ConnectionHandle{url=jdbc:oracle:thin:@//example.com:1535/SCHEMA, user=user, debugHandle=null, lastResetAgoInSec=1, lastUsedAgoInSec=602, creationTimeAgoInSec=612}] after transaction
DEBUG 26 Sep 2016 13:23:38,317 () datasource.DataSourceUtils doReleaseConnection 327 - Returning JDBC Connection to DataSource
ERROR 26 Sep 2016 13:23:38,318 () impl.IntegrationServiceImpl submitTmr 235 - error:
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database.  Cause: java.sql.SQLException: Connection is closed!

以下是相关课程。我省略了一些东西,包括控制器,模型类,mybatis映射器和其他数据库的配置。

配置

@Configuration
@EnableTransactionManagement
public class AppConfig {

    @Bean(name = "shippingDataSource")
    public DataSource shippingDataSource() {
        BoneCPDataSource dataSource = new BoneCPDataSource();
        dataSource.setDriverClass("oracle.jdbc.OracleDriver");
        dataSource.setJdbcUrl("jdbc:oracle:thin:@//example.com:1535/SCHEMA");
        dataSource.setUsername("user");
        dataSource.setPassword("pass");
        return dataSource;
    }

    @Bean(name = "shippingTxManager")
    public PlatformTransactionManager TxManager(){
        return new DataSourceTransactionManager(shippingDataSource());
    }

    @Bean(name = "shippingSqlSessionFactoryBean")
    public SqlSessionFactoryBean shippingSqlSessionFactoryBean() {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(shippingDataSource());
        bean.setTypeAliasesPackage("com.example.shipping.model");
        bean.setConfigLocation(new ClassPathResource("mybatis-config.xml"));
        return bean;
    }

    @Bean(name = "shippingSqlSession")
    public SqlSession shippingSqlSession() throws Exception {
        return shippingSqlSessionFactoryBean().getObject().openSession();
    }
}

服务层

@Service("shippingService")
// Remove the "Transactional" annotation and everything else works.
@Transactional(rollbackFor=ShippingException.class, transactionManager = "shippingTxManager")
public class ShippingService {

    @Autowired 
    ShippingDao dao;

    // If any packages are not inserted successfully, throw an exception
    // and roll back the whole shipment.
    public void CreateShipment(Shipment shipment){
        try {
            dao.insertShipment(shipment);
            for(Package package : shipment.getPackages()) {
                dao.insertPackage(package);
            }
        } catch (Exception e) {
            throw new ShippingException(e);
        }
    }
}

数据层

@Repository
public class ShippingDao {

    @Autowired
    @Qualifier("shippingSqlSession")
    private SqlSession session;

    public int insertShipment(Shipment shipment){
        return session.insert("insertShipment", shipment);
    }

    public int insertPackage(Package package){
        return session.insert("insertPackage", package);
    }
}

的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <artifactId>example</artifactId>
    <groupId>com.example</groupId>
    <version>0.0.1-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.ws</groupId>
            <artifactId>spring-ws-core</artifactId>
            <version>2.2.4.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-aop</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>com.jolbox</groupId>
            <artifactId>bonecp</artifactId>
            <version>0.8.0.RELEASE</version>
        </dependency>
    </dependencies>
</project>

1 个答案:

答案 0 :(得分:0)

修复是使用SqlSessionTemplate而不是直接从SqlSessionFactory打开会话。

@Bean(name = "shippingSqlSession")
public SqlSession shippingSqlSession() throws Exception {
    return new SqlSessionTemplate(shippingSqlSessionFactoryBean().getObject());
}