1

여러 데이터베이스에 연결하는 응용 프로그램이 있습니다. Spring Transaction Management를 데이터베이스 연결 중 하나에 추가 할 때까지 모든 것이 잘 돌아갔다.스프링 관리 트랜잭션이 닫힌 연결로 연결

@Transactional 주석을 서비스 메소드에 추가 한 이후로 데이터베이스 연결이 첫 번째 관리 트랜잭션에 올바르게 작동합니다. 그러나 트랜잭션이 완료된 후 실제 데이터베이스 연결이 닫히지 만 논리적 연결 개체는 연결이 아직 열려 있다고 생각합니다. 결과는 해당 연결을 사용하는 모든 후속 데이터베이스 호출이 "Closed Connection"오류로 실패합니다.

는 다른 말로하면, 이러한 시나리오 모든 작업 :

  • @Transactional
  • @Transactional 흐름없이 읽기 또는 쓰기 작업의 모든 순서 처음
  • 동일한 흐름을 제외하고 @Transactional 특성이 제거 된 상태에서 여러 번 반복됨

이 문제는 응용 프로그램이 @Transactional 주석을 사용하여 메서드를 실행 한 후에 만 ​​발생합니다. 트랜잭션이 성공적으로 커밋되거나 롤백되면 문제가되지 않습니다.

자세한 수업 및 로그 및 내용은 아래를 참조하십시오. 그들은 익명으로 처리되었으므로 오타는 오타입니다.

처음으로 데이터베이스에 도달하면 모든 것이 완벽하게 작동합니다. 이것은 내가 로그에서 볼 것입니다 :

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! 

가 여기에 해당 클래스입니다 :

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 

이 난 이후의 시도에 로그에 표시되는 내용입니다. 컨트롤러, 모델 클래스, mybatis mappers 및 다른 데이터베이스의 구성을 포함하여 일부 내용을 생략했습니다.

구성

@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> 
+0

'shippingSqlSession'을 제거하십시오.'SqlSessionFactoryBean'이 처리합니다. 이제 첫 번째 트랜잭션 후에 닫히는 단일 세션이 열리고 있습니다. 또는 [documentation] (http://www.mybatis.org/spring/sqlsession.html)에서 설명한대로 SqlSessionTemplate을 사용하십시오. –

+0

그래, 그게 해결책입니다. 이 질문을 답으로 게시하려면 답변 해 줄 수 있습니다. 감사. – aug

답변

0

이 수정 프로그램은 SqlSessionFactory에서 직접 세션을 여는 대신 SqlSessionTemplate을 사용했습니다.

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