2016-11-22 63 views
3

我爲我的角度項目開發了一個彈簧引導RestController並遇到問題。在我的剩餘服務邏輯中,我使用了兩個不同的數據庫來獲取數據。帶有多個數據源Oracle和H2的彈簧引導

在這裏你可以看到數據源配置:

[application.properties]

#datasource1 
spring.datasource.url=[url] 
spring.datasource.username=[username] 
spring.datasource.password=[password] 
spring.datasource.driverClassName=org.h2.Driver 

#datasource2 
spring.secondDatasource.url=[url] 
spring.secondDatasource.username=[username] 
spring.secondDatasource.password=[password] 
spring.secondDatasource.driverClassName=oracle.jdbc.OracleDriver 

[DatasourceConfig.java]

@Bean 
@Primary 
@ConfigurationProperties(prefix="spring.datasource") 
public DataSource h2DataSource() { 
    return DataSourceBuilder.create().build(); 
} 

@Bean 
@ConfigurationProperties(prefix="spring.secondDatasource") 
public DataSource oracleDataSource() { 
    return DataSourceBuilder.create().build(); 
} 

記錄輸出:(無例外被丟進對於這個問題)

... 
2016-11-22 13:20:25.853 [INFO ] 1 [main] d.b.s.Application : Started Application in 7.757 seconds (JVM running for 12.515) 
2016-11-22 13:20:31.731 [INFO ] 62 [http-nio-8080-exec-1] o.s.w.s.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started 
2016-11-22 13:20:31.757 [INFO ] 62 [http-nio-8080-exec-1] o.s.w.s.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 26 ms 
2016-11-22 13:20:34.984 [INFO ] 65 [http-nio-8080-exec-5] d.b.s.r.RESTclient : /rest/getMyData 
2016-11-22 13:20:34.992 [INFO ] 63 [http-nio-8080-exec-2] d.b.s.r.RESTclient : /rest/getMyData2 
2016-11-22 13:20:34.993 [INFO ] 69 [http-nio-8080-exec-8] d.b.s.r.RESTclient : /rest/getMyData3 
2016-11-22 13:20:35.004 [DEBUG] 65 [http-nio-8080-exec-5] d.b.s.DataSourceService : getH2Connection() 
2016-11-22 13:20:35.022 [DEBUG] 63 [http-nio-8080-exec-2] d.b.s.DataSourceService : getOracleConnection() 
2016-11-22 13:20:35.022 [DEBUG] 69 [http-nio-8080-exec-8] d.b.s.DataSourceService : getH2Connection() 

問題是,其餘服務的每個使用的工作線程(http-nio-8080-?,...)在我的DataSourceService中的datasource.getConnection()掛起。它永遠凍結,並等待無法獲得的連接。

@Service 
public class DataSourceService { 
    private final DataSource h2DataSource; 
    private final DataSource oracleDataSource; 

    @Autowired 
    public DataSourceService(DataSource h2DataSource, DataSource oracleDataSource) { 
     this.h2DataSource = h2DataSource; 
     this.oracleDataSource = oracleDataSource; 
    } 

    public Connection getH2Connection() throws SQLException { 
     LoggerUtil.logDebug(getClass(), "getH2Connection()"); 
     return h2Connection.getConnection(); 
    } 

    public Connection getOracleConnection() throws SQLException { 
     LoggerUtil.logDebug(getClass(), "getOracleConnection()"); 
     return oracleConnection.getConnection(); 
    } 
} 

關於它的奇怪的是,有時它的工作原理沒有改變過的代碼行(所有時間的5%)和大部分(所有時間的95%),其掛斷。

在我的pom.xml我有以下數據庫驅動的依賴:

<dependency> 
    <groupId>com.oracle</groupId> 
    <artifactId>ojdbc6</artifactId> 
    <version>11.2.0.4</version> 
    <scope>runtime</scope> 
</dependency> 
<dependency> 
    <groupId>com.h2database</groupId> 
    <artifactId>h2</artifactId> 
    <version>1.4.193</version> 
    <scope>runtime</scope> 
</dependency> 

如果所有的數據源具有相同的驅動程序,這不會發生,但結合我發現這種奇怪的行爲。

我的想法是,這隻有當h2Database在oracle之前被初始化時纔會發生。在這一點上,spring classloader加載了h2-driver類,它們將被緩存。接下來,oracle將被初始化,並且一些類將關閉完全相同,以便某些h2類被用於oracle。正因爲如此,凍結的奇怪狀態被創建。 (也許反之亦然)。

我現在的問題是:爲什麼我不能在Spring-boot的同時使用H2和Oracle數據庫?

編輯:

後一些調試我發現更詳細的信息:

[org.apache.tomcat.jdbc.pool.ClassLoaderUtil]

Row 29: loadClass(...) 
... 
Row 38: return Class.forName(className, true, cl); //className: "oracle.jdbc.OracleDriver" cl: Launcher$AppClassLoader 

在ClassLoaderUtil爲查找通過className的驅動程序類。可以毫無問題地解決className「org.h2.Driver」,但「oracle.jdbc.OracleDriver」不會。

之後,我做了一個線程轉儲,你可以看到卡住的點。此時有5個卡住的線程在不同的位置卡住。

HTTP-NIO-8080-EXEC-2 @ 8307(可運行) (僅使用Oracle數據庫)

"[email protected]" daemon prio=5 tid=0x40 nid=NA runnable 
    java.lang.Thread.State: RUNNABLE 
    blocks [email protected] 
     at java.lang.Class.forName0(Class.java:-1) 
     at java.lang.Class.forName(Class.java:348) 
     at org.apache.tomcat.jdbc.pool.ClassLoaderUtil.loadClass(ClassLoaderUtil.java:38) 
     at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:271) 
     at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:203) 
     at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:718) 
     at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:650) 
     at org.apache.tomcat.jdbc.pool.ConnectionPool.init(ConnectionPool.java:468) 
     at org.apache.tomcat.jdbc.pool.ConnectionPool.<init>(ConnectionPool.java:143) 
     at org.apache.tomcat.jdbc.pool.DataSourceProxy.pCreatePool(DataSourceProxy.java:118) 
     - locked <0x2139> (a org.apache.tomcat.jdbc.pool.DataSource) 
     at org.apache.tomcat.jdbc.pool.DataSourceProxy.createPool(DataSourceProxy.java:107) 
     at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:131) 
     at d.b.s.DataSourceService.getConnection(DataSourceService.java:51)      //<-- That's my package 
     ... 

HTTP-NIO-8080-EXEC-3 @ 8308(可運行) (比較Oracle和H2數據)

"[email protected]" daemon prio=5 tid=0x41 nid=NA runnable 
    java.lang.Thread.State: RUNNABLE 
    at oracle.jdbc.driver.OracleDriver.<clinit>(OracleDriver.java:190) 
    at java.lang.Class.forName0(Class.java:-1) 
    at java.lang.Class.forName(Class.java:348) 
    at org.apache.tomcat.jdbc.pool.ClassLoaderUtil.loadClass(ClassLoaderUtil.java:38) 
    at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:271) 
    at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:203) 
    at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:718) 
    at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:650) 
    at org.apache.tomcat.jdbc.pool.ConnectionPool.init(ConnectionPool.java:468) 
    at org.apache.tomcat.jdbc.pool.ConnectionPool.<init>(ConnectionPool.java:143) 
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.pCreatePool(DataSourceProxy.java:118) 
    - locked <0x213d> (a org.apache.tomcat.jdbc.pool.DataSource) 
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.createPool(DataSourceProxy.java:107) 
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:131) 
    at d.b.s.DataSourceService.getConnection(DataSourceService.java:51) 
    ... 

HTTP-NIO-8080-EXEC-4 @ 8309(可運行) (Oracle和H2數據之間的比較)

(間相同的exec-2)

HTTP-NIO-8080-EXEC-5 @ 8310(可運行) (僅使用H2數據庫)

"[email protected]" daemon prio=5 tid=0x43 nid=NA runnable 
    java.lang.Thread.State: RUNNABLE 
    at sun.reflect.GeneratedConstructorAccessor109.newInstance(Unknown Source:-1) 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:-1) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423) 
    at java.lang.Class.newInstance(Class.java:442) 
    at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:380) 
    at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:404) 
    at java.util.ServiceLoader$1.next(ServiceLoader.java:480) 
    at java.sql.DriverManager$2.run(DriverManager.java:603) 
    at java.sql.DriverManager$2.run(DriverManager.java:583) 
    at java.security.AccessController.doPrivileged(AccessController.java:-1) 
    at java.sql.DriverManager.loadInitialDrivers(DriverManager.java:583) 
    at java.sql.DriverManager.<clinit>(DriverManager.java:101) 
    at org.h2.Driver.load(Driver.java:155) 
    at org.h2.Driver.<clinit>(Driver.java:41) 
    at java.lang.Class.forName0(Class.java:-1) 
    - locked <0x211b> (a java.lang.Class) 
    at java.lang.Class.forName(Class.java:348) 
    at org.apache.tomcat.jdbc.pool.ClassLoaderUtil.loadClass(ClassLoaderUtil.java:38) 
    at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:271) 
    at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:203) 
    at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:718) 
    at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:650) 
    at org.apache.tomcat.jdbc.pool.ConnectionPool.init(ConnectionPool.java:468) 
    at org.apache.tomcat.jdbc.pool.ConnectionPool.<init>(ConnectionPool.java:143) 
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.pCreatePool(DataSourceProxy.java:118) 
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.createPool(DataSourceProxy.java:107) 
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:131) 
    - locked <0x20e9> (a org.apache.tomcat.jdbc.pool.DataSource) 
    at d.b.s.DataSourceService.getConnection(DataSourceService.java:51) 
    ... 

HTTP-NIO-8080-EXEC-6 @ 8311 (等待監視實體) (Oracle和H2數據之間的比較)

"[email protected]" daemon prio=5 tid=0x44 nid=NA waiting for monitor entry 
    java.lang.Thread.State: BLOCKED 
waiting for [email protected] to release lock on <0x2139> (a org.apache.tomcat.jdbc.pool.DataSource) 
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.pCreatePool(DataSourceProxy.java:115) 
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.createPool(DataSourceProxy.java:107) 
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:131) 
    at d.b.s.DataSourceService.getConnection(DataSourceService.java:51) 
    ... 
+0

對我來說似乎不合法,我認爲它與Spring Boot無關。既然你正在配置你自己的'DataSource',你完全可以繞過Spring Boot爲你做的事情。也許池沒有足夠的連接,你沒有正確關閉連接?再次,與Spring Boot無關。 –

回答

0

我也滿足同樣的問題和你一樣,但在H2和mysql.I我不是在同一時間使用H2和甲骨文,在這post,也許你可以找到一些有用的。

這裏是我的雙重數據源配置:

Maven的依賴:

<!-- stater mybatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency> <!-- jdbc --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>

```

datasource: 
    km: 
    driverClassName: com.mysql.jdbc.Driver 
    url: jdbc:mysql://localhost:3306/km?useUnicode=true&characterEncoding=UTF-8&useSSL=false 
    username: root 
    password: 123456 
    max-active: 100 
    max-idle: 10 
    max-wait: 10000 
    test-while-idle: true 
    esb: 
    driverClassName: com.mysql.jdbc.Driver 
    url: jdbc:mysql://localhost:3306/esb?useUnicode=true&characterEncoding=UTF-8&useSSL=false 
    username: root 
    password: 123456 
    max-active: 100 
    max-idle: 10 
    max-wait: 10000 
    test-while-idle: true 

```

數據源公里配置類: ```

import com.package.km.api.commons.config.datasource.annotation.UseDatasourceKM; 
import org.apache.ibatis.session.SqlSessionFactory; 
import org.mybatis.spring.SqlSessionFactoryBean; 
import org.mybatis.spring.annotation.MapperScan; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; 
import org.springframework.boot.context.properties.ConfigurationProperties; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.context.annotation.Primary; 
import org.springframework.core.io.ClassPathResource; 
import org.springframework.jdbc.datasource.DataSourceTransactionManager; 
import org.springframework.transaction.PlatformTransactionManager; 

import javax.sql.DataSource; 
import java.lang.invoke.MethodHandles; 
import java.sql.SQLException; 

/** 
* km datasource config 
* Created by BeeNoisy on 16/5/23. 
*/ 
@Configuration 
@MapperScan(basePackages = "package.km", annotationClass = UseDatasourceKM.class, sqlSessionFactoryRef = KMDatasourceConfig.SQL_SESSION_FACTORY_NAME) 
public class KMDatasourceConfig { 
    public static final String SQL_SESSION_FACTORY_NAME = "sessionFactoryKm"; 
    public static final String TX_MANAGER = "txManagerKm"; 
    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); 

    @Bean(name = "datasourceKm") 
    @Primary 
    @ConfigurationProperties(prefix = "datasource.km") 
    public DataSource dataSourceKm() { 
     return DataSourceBuilder.create().build(); 
    } 

    @Bean(name = TX_MANAGER) 
    @Primary 
    public PlatformTransactionManager txManagerKm() { 
     return new DataSourceTransactionManager(dataSourceKm()); 
    } 

    @Bean(name = KMDatasourceConfig.SQL_SESSION_FACTORY_NAME) 
    @Primary 
    public SqlSessionFactory sqlSessionFactoryBean() throws Exception { 

     SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); 
     sqlSessionFactoryBean.setConfigLocation(new ClassPathResource("/mybatis/mybatis-conf.xml")); 
     sqlSessionFactoryBean.setDataSource(dataSourceKm()); 
     return sqlSessionFactoryBean.getObject(); 
    } 
} 

```

這裏是數據源ESB配置類:

```

import com.package.km.api.commons.condition.EsbEnabledCondition; 
import com.package.km.api.commons.config.datasource.annotation.UseDatasourceESB; 
import org.apache.ibatis.session.SqlSessionFactory; 
import org.mybatis.spring.SqlSessionFactoryBean; 
import org.mybatis.spring.annotation.MapperScan; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; 
import org.springframework.boot.context.properties.ConfigurationProperties; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Conditional; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.core.io.ClassPathResource; 
import org.springframework.jdbc.datasource.DataSourceTransactionManager; 
import org.springframework.transaction.PlatformTransactionManager; 

import javax.sql.DataSource; 
import java.lang.invoke.MethodHandles; 

/** 
* Created by BeeNoisy on 16/5/23. 
*/ 
@Configuration 
@Conditional(EsbEnabledCondition.class) 
@MapperScan(basePackages = "package.esb", annotationClass = UseDatasourceESB.class, sqlSessionFactoryRef = EsbDatasourceConfig.SQL_SESSION_FACTORY_NAME) 
public class EsbDatasourceConfig { 
    public static final String SQL_SESSION_FACTORY_NAME = "sessionFactoryEsb"; 
    public static final String TX_MANAGER = "txManagerEsb"; 
    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); 

    @Bean(name = "datasourceEsb") 
    @Conditional(EsbEnabledCondition.class) 
    @ConfigurationProperties(prefix = "datasource.esb") 
    public DataSource dataSourceEsb() { 
     return DataSourceBuilder.create().build(); 
    } 

    @Bean(name = TX_MANAGER) 
    @Conditional(EsbEnabledCondition.class) 
    public PlatformTransactionManager txManagerEsb() { 
     return new DataSourceTransactionManager(dataSourceEsb()); 
    } 

    @Bean(name = EsbDatasourceConfig.SQL_SESSION_FACTORY_NAME) 
    @Conditional(EsbEnabledCondition.class) 
    public SqlSessionFactory sqlSessionFactoryBean() throws Exception { 

     SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); 
     sqlSessionFactoryBean.setConfigLocation(new ClassPathResource("/mybatis/mybatis-conf.xml")); 
     sqlSessionFactoryBean.setDataSource(dataSourceEsb()); 
     return sqlSessionFactoryBean.getObject(); 
    } 
} 

```

然後你就可以使用這兩個註解: UseDatasourceESBUseDatasourceKM來標註您的映射器類:

```

@UseDatasourceKM 
public interface GroupBaseDAO { 
    public static final String COL_ALL = " id, name, create_time, last_update_time "; 
    public static final String TABLE = " group_base "; 

    @Select(" select " + COL_ALL + " from " + TABLE + " where id = #{id} ") 
    public GroupBase findById(@Param("id") int id); 

    @Select(" select " + 
      COL_ALL + 
      " from " + 
      TABLE + 
      " where id < #{lastId} " + 
      " limit #{count} ") 
    public List<GroupBase> list(
      @Param("lastId") int lastId, 
      @Param("count") int count 
    ); 
... 

```

有在MySQL \ H2和Oracle數據源2。您可以在調試模型中運行您的代碼,然後進入getConnection()方法來查找更多詳細信息。

相關問題