org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: url not set
该问题是出现在使用spring将数据源配置文件引入到配置类里面的时候
spring将数据源配置文件引入到配置类的两种方式
方式一
方式一:创建一个数据源配置类,引入spring的配置类(不会出现数据无法注入的问题)
方式二
方式二:在spring的配置类里面,直接引入外部的数据源配置文件,如果在成员变量上进行注入,会出现无法注入的情况。
错误的原因分析
方式一
import方式导入数据源配置类DataSourceConfig2,spring容器在初始化会创建DataSourceConfig2对象,也会初始化DataSourceConfig2类里面成员变量,就会通过spel表达式注入数据源文件的key对应的值。同时将配置了@Bean注解的返回对象存到容器里面
@PropertySource ( "classpath:db.properties" )
public class DataSourceConfig2 {
@Value ( "${jdbc.driverClassName}" )
private String driverClassName;
@Value ( "${jdbc.url}" )
private String url;
@Value ( "${jdbc.username}" )
private String username;
@Value ( "${jdbc.password}" )
private String password;
@Bean ( "dataSource" )
public DataSource getDruidDataSource ( ) {
DruidDataSource ds = new DruidDataSource ( ) ;
ds. setDriverClassName ( driverClassName) ;
ds. setUrl ( url) ;
ds. setUsername ( username) ;
ds. setPassword ( password) ;
return ds;
}
}
@Import ( { DataSourceConfig2 . class } )
@Configuration
public class SpringConfigHand2 {
}
方式二
原因:SpringConfigHand是一个配置类,spring容器不会创建SpringConfigHand对象,也就意味着不会对类中的成员变量进行赋值 解决方案:将通过@Value注入的数据配置到带@Bean注解的方法里面。 原因: spring容器会管理@Bean注解的方法的返回对象.
@Configuration
@ComponentScan ( "com.hand.service" )
@Import ( DataSourceConfig . class )
public class SpringConfigHand2 {
@Value ( "${jdbc.driver}" ) * String driver;
@Value ( "${jdbc.url}" ) String url;
@Value ( "${jdbc.username}" ) String username;
@Value ( "${jdbc.password}" ) String password;
@Bean
public DataSource getDataSource ( ) {
DruidDataSource dataSource = new DruidDataSource ( ) ;
dataSource. setDriverClassName ( driver) ;
dataSource. setUsername ( username) ;
dataSource. setUrl ( url) ;
dataSource. setPassword ( password) ;
return dataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactory ( DataSource dataSource) {
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean ( ) ;
ssfb. setTypeAliasesPackage ( "com.hand.entity" ) ;
ssfb. setDataSource ( dataSource) ;
return ssfb;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer ( ) {
MapperScannerConfigurer msc = new MapperScannerConfigurer ( ) ;
msc. setBasePackage ( "com.hand.dao" ) ;
return msc;
}
@Bean
public PlatformTransactionManager createTransactionManager ( DataSource dataSource) {
DataSourceTransactionManager pt = new DataSourceTransactionManager ( ) ;
pt. setDataSource ( dataSource) ;
return pt;
}
}
上述代码存在的问题就是在加载配置类的时候不会对成员变量进行赋值,所以就会出现url not set的错误。事实上,driver、url、username、password都没有set 解决办法:将通过@Value注入的数据配置到带@Bean注解的方法里面。即将代码上述代码的成员变量通过参数传递的方式传递给方法。
@Configuration
@ComponentScan ( "com.hand.service" )
@Import ( DataSourceConfig . class )
public class SpringConfigHand2 {
@Bean
public DataSource getDataSource ( @Value ( "${jdbc.driver}" ) String driver,
@Value ( "${jdbc.url}" ) String url,
@Value ( "${jdbc.username}" ) String username,
@Value ( "${jdbc.password}" ) String password) {
DruidDataSource dataSource = new DruidDataSource ( ) ;
dataSource. setDriverClassName ( driver) ;
dataSource. setUsername ( username) ;
dataSource. setUrl ( url) ;
dataSource. setPassword ( password) ;
return dataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactory ( DataSource dataSource) {
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean ( ) ;
ssfb. setTypeAliasesPackage ( "com.hand.entity" ) ;
ssfb. setDataSource ( dataSource) ;
return ssfb;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer ( ) {
MapperScannerConfigurer msc = new MapperScannerConfigurer ( ) ;
msc. setBasePackage ( "com.hand.dao" ) ;
return msc;
}
@Bean
public PlatformTransactionManager createTransactionManager ( DataSource dataSource) {
DataSourceTransactionManager pt = new DataSourceTransactionManager ( ) ;
pt. setDataSource ( dataSource) ;
return pt;
}
}