2016-11-22 64 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()方法来查找更多详细信息。

相关问题