数据源的通用配置方式,单一或多数据源,使用Druid连接池。当然配置中可以选择其他数据库连接池。当然Druid效率可能稍微差些,但其稳定性非常值得肯定,并且监控强大。本文代码完全可以使用在生成环境。
见jdbc.properties。配置中有两个
#datasource_1
spring.datasource.activity.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.activity.url=jdbc:mysql://10.99.11.252:3306/db_qiku_activity?useSSL=false&zeroDateTimeBehavior=convertToNull
spring.datasource.activity.username=root
spring.datasource.activity.password=qiku
spring.datasource.activity.driver-class-name=com.mysql.jdbc.Driver
#datasource_2
spring.datasource.theme.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.theme.url=jdbc:mysql://10.99.11.252:3306/db_test_themes?useSSL=false&zeroDateTimeBehavior=convertToNull
spring.datasource.theme.username=root
spring.datasource.theme.password=qiku
spring.datasource.theme.driver-class-name=com.mysql.jdbc.Driver
# DataSource DruidDataSource连接池的基本配置信息
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
spring.datasource.maxWait=60000
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.filters=stat,wall,log4j
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
spring.datasource.initialize=false
由于spring boot的自动配置中没有集成Druid数据库连接池,因此,第一步配置我们的datasorce
@Configuration //Configuration 注解进行bean配置
@PropertySource(value = { "classpath:config/jdbc.properties"}, ignoreResourceNotFound=false) //引入jdbc文件,当然文件不可不存在
public class DruidConfig {
//数据源1 由jdbc.properties自动注入属性值
@Value("${spring.datasource.activity.url:#{null}}")
private String acitvityDbUrl;
@Value("${spring.datasource.activity.username: #{null}}")
private String acitvityUsername;
@Value("${spring.datasource.activity.password:#{null}}")
private String acitvityPassword;
@Value("${spring.datasource.activity.driverClassName:#{null}}")
private String acitvityDriverClassName;
//数据源2
@Value("${spring.datasource.theme.url:#{null}}")
private String themeDbUrl;
@Value("${spring.datasource.theme.username: #{null}}")
private String themeUsername;
@Value("${spring.datasource.theme.password:#{null}}")
private String themePassword;
@Value("${spring.datasource.theme.driverClassName:#{null}}")
private String themeDriverClassName;
@Value("${spring.datasource.initialSize:#{null}}")
private Integer initialSize;
@Value("${spring.datasource.minIdle:#{null}}")
private Integer minIdle;
@Value("${spring.datasource.maxActive:#{null}}")
private Integer maxActive;
@Value("${spring.datasource.maxWait:#{null}}")
private Integer maxWait;
@Value("${spring.datasource.timeBetweenEvictionRunsMillis:#{null}}")
private Integer timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.minEvictableIdleTimeMillis:#{null}}")
private Integer minEvictableIdleTimeMillis;
@Value("${spring.datasource.validationQuery:#{null}}")
private String validationQuery;
@Value("${spring.datasource.testWhileIdle:#{null}}")
private Boolean testWhileIdle;
@Value("${spring.datasource.testOnBorrow:#{null}}")
private Boolean testOnBorrow;
@Value("${spring.datasource.testOnReturn:#{null}}")
private Boolean testOnReturn;
@Value("${spring.datasource.poolPreparedStatements:#{null}}")
private Boolean poolPreparedStatements;
@Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize:#{null}}")
private Integer maxPoolPreparedStatementPerConnectionSize;
@Value("${spring.datasource.filters:#{null}}")
private String filters;
@Value("{spring.datasource.connectionProperties:#{null}}")
private String connectionProperties;
@Bean(name="themeDataSource", destroyMethod="close") //声明其为Bean实例
@Primary //在同样的DataSource中,首先使用被标注的DataSource
public DataSource themeDataSource() {
//com.alibaba.druid.pool.DruidDataSource 使用druid的datasorce
//在此处可以定义任何类型的数据库连接池的datasource
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(this.themeDbUrl);
dataSource.setUsername(this.themeUsername);
dataSource.setPassword(this.themePassword);
dataSource.setDriverClassName(this.themeDriverClassName);
//configuration
if (initialSize != null) {
dataSource.setInitialSize(initialSize);
}
if (minIdle != null) {
dataSource.setMinIdle(minIdle);
}
if (maxActive != null) {
dataSource.setMaxActive(maxActive);
}
if (maxWait != null) {
dataSource.setMaxWait(maxWait);
}
if (timeBetweenEvictionRunsMillis != null) {
dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
}
if (minEvictableIdleTimeMillis != null) {
dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
}
if (validationQuery != null) {
dataSource.setValidationQuery(validationQuery);
}
if (testWhileIdle != null) {
dataSource.setTestWhileIdle(testWhileIdle);
}
if (testOnBorrow != null) {
dataSource.setTestOnBorrow(testOnBorrow);
}
if (testOnReturn != null) {
dataSource.setTestOnReturn(testOnReturn);
}
if (poolPreparedStatements != null) {
dataSource.setPoolPreparedStatements(poolPreparedStatements);
}
if (maxPoolPreparedStatementPerConnectionSize != null) {
dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
}
if (connectionProperties != null) {
dataSource.setConnectionProperties(connectionProperties);
}
List filters = new ArrayList<>();
filters.add(statFilter());
filters.add(wallFilter());
dataSource.setProxyFilters(filters); //此处添加了
return dataSource;
}
@Bean(name="activityDataSource", destroyMethod="close") //声明其为Bean实例
@Primary //在同样的DataSource中,首先使用被标注的DataSource
public DataSource activityDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(this.acitvityDbUrl);
dataSource.setUsername(this.acitvityUsername);
dataSource.setPassword(this.acitvityPassword);
dataSource.setDriverClassName(this.acitvityDriverClassName);
//configuration
if (initialSize != null) {
dataSource.setInitialSize(initialSize);
}
if (minIdle != null) {
dataSource.setMinIdle(minIdle);
}
if (maxActive != null) {
dataSource.setMaxActive(maxActive);
}
if (maxWait != null) {
dataSource.setMaxWait(maxWait);
}
if (timeBetweenEvictionRunsMillis != null) {
dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
}
if (minEvictableIdleTimeMillis != null) {
dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
}
if (validationQuery != null) {
dataSource.setValidationQuery(validationQuery);
}
if (testWhileIdle != null) {
dataSource.setTestWhileIdle(testWhileIdle);
}
if (testOnBorrow != null) {
dataSource.setTestOnBorrow(testOnBorrow);
}
if (testOnReturn != null) {
dataSource.setTestOnReturn(testOnReturn);
}
if (poolPreparedStatements != null) {
dataSource.setPoolPreparedStatements(poolPreparedStatements);
}
if (maxPoolPreparedStatementPerConnectionSize != null) {
dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
}
if (connectionProperties != null) {
dataSource.setConnectionProperties(connectionProperties);
}
List filters = new ArrayList<>();
filters.add(statFilter());
filters.add(wallFilter());
dataSource.setProxyFilters(filters); //此处设置该DruidDataSource的监控页面的servlet。
return dataSource;
}
@Bean
@Primary
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
servletRegistrationBean.setServlet(new StatViewServlet());
servletRegistrationBean.addUrlMappings("/druid/*");
//添加密码访问
Map initParameters = Maps.newHashMap();
initParameters.put("loginUsername","admin");
initParameters.put("loginPassword","admin");
initParameters.put("resetEnable", "false");// 禁用HTML页面上的“Reset All”功能
initParameters.put("allow", "127.0.0.1"); // IP白名单 (没有配置或者为空,则允许所有访问)
//initParameters.put("deny", "192.168.20.38");// IP黑名单 (存在共同时,deny优先于allow)
servletRegistrationBean.setInitParameters(initParameters);
return servletRegistrationBean;
}
@Bean
@Primary
public StatFilter statFilter() {
StatFilter statFilter = new StatFilter();
statFilter.setLogSlowSql(true);
statFilter.setMergeSql(true);
statFilter.setSlowSqlMillis(1000);
return statFilter;
}
@Bean
@Primary
public WallFilter wallFilter() {
WallFilter wallFilter = new WallFilter();
//允许执行多条SQL
WallConfig config = new WallConfig();
config.setMultiStatementAllow(true);
wallFilter.setConfig(config);
return wallFilter;
}
// @Bean
// @Primary
// public DataSourceTransactionManager transactionManager() {
// return new DataSourceTransactionManager(this.activityDataSource());
// }
}
上面的代码可以看出已经将配置的多个数据源信息注入,并生成datasource的bean供容器管理。
下面该配置mybatis的SqlSessionFactory,以及SqlSessionTemplate供mybatis框架进行管理。
@Configuration
public class DataSorceConfig {
@Autowired
@Qualifier("activityDataSource")
private DataSource activityDataSource;
@Autowired
@Qualifier("themeDataSource")
private DataSource themeDataSource;
@Bean(name="activitySqlSessionFactory")
//@ConditionalOnMissingBean //当容器里没有指定的Bean的情况下创建该对象
public SqlSessionFactory activitySqlSessionFactory() throws Exception {
//这里配置mybatis的SqlSessionFactory
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
//设置datasource
bean.setDataSource(activityDataSource);
//这里设置mybatis查询结果对应的对象地址
bean.setTypeAliasesPackage("com.qihoo.lottery.vo.dt");
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
//使用jdbc的getGeneratedKeys获取数据库自增主键值
configuration.setUseGeneratedKeys(true);
//使用列别名替换列名 select user as User
configuration.setUseColumnLabel(true);
//-自动使用驼峰命名属性映射字段 userId user_id
configuration.setMapUnderscoreToCamelCase(true);
bean.setConfiguration(configuration);
bean.setFailFast(true);
return bean.getObject();
}
@Bean(name="themeSqlSessionFactory")
//@ConditionalOnMissingBean //当容器里没有指定的Bean的情况下创建该对象
public SqlSessionFactory themeSqlSessionFactory() throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(themeDataSource);
bean.setTypeAliasesPackage("com.qihoo.lottery.vo.dt");
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
//使用jdbc的getGeneratedKeys获取数据库自增主键值
configuration.setUseGeneratedKeys(true);
//使用列别名替换列名 select user as User
configuration.setUseColumnLabel(true);
//-自动使用驼峰命名属性映射字段 userId user_id
configuration.setMapUnderscoreToCamelCase(true);
bean.setConfiguration(configuration);
bean.setFailFast(true);
return bean.getObject();
}
@Bean
public DataSourceTransactionManager activityDataSourceTransactionManager() {
return new DataSourceTransactionManager(activityDataSource);
}
//配置每个数据源对应的SqlSessionTemplate供框架进行管理
@Bean
public SqlSessionTemplate activitySqlSessionTemplate(@Qualifier("activitySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory);
return template;
}
@Bean
public DataSourceTransactionManager themeDataSourceTransactionManager() {
return new DataSourceTransactionManager(themeDataSource);
}
@Bean
public SqlSessionTemplate themeSqlSessionTemplate(@Qualifier("themeSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
SqlSessionTemplate template = new SqlSessionTemplate(sqlSessionFactory);
return template;
}
}
由以上代码可以看到两个数据源已经妥妥的被容器管理。
请问?请问可以SqlSessionFactoryBean可以直接加载mybatis的配置文件吗?那当然可以,样例代码给出的是程序方式配置。下面给出直接加载mybatis配置文件。
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource mybatisConfigXml = resolver.getResource("classpath:mybatis/mybatis-config.xml");
sqlSessionFactoryBean.setConfigLocation(mybatisConfigXml);
补充一点:本人的sql是通过注解注入,非xml文件。例如:
@Select("select count(*) from tb_qiku_activity_info")
public int selectActivityCount();
@UpdateProvider(type=ActivitySqlProvider.class, method="upActivity")
public int updateActivity(@Param("req") ActivityReq req);
sql通过注入方式因此无需加载xml文件。如果各位的sql是通过xml文件配置。需要设置mapper地址。
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/designer/*.xml"));
完了?否!
需要制定每个数据源对于的mapper,即指定每个SqlSessionTemplate对于的mapper路径。
@Configuration
@AutoConfigureAfter(DataSorceConfig.class) //这个注解很重要,必须是SqlSessionTemplate初始化完成,再初始化该maperrscanner
public class MapperScannerConfig {
@Bean
public MapperScannerConfigurer activityMapperScannerConfigurer() {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
//设置mapper对应template对应的mapper的代码路径。
configurer.setSqlSessionTemplateBeanName("activitySqlSessionTemplate");
configurer.setBasePackage("com.qihoo.lottery.dao.mapper.activity");
return configurer;
}
@Bean
public MapperScannerConfigurer themeMapperScannerConfigurer() {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setSqlSessionTemplateBeanName("themeSqlSessionTemplate");
configurer.setBasePackage("com.qihoo.lottery.dao.mapper.theme");
return configurer;
}
}
通过上面的简单配置,多数据源就被Druid池管理起来。当然单一连接也就是在代码中对bean的增减问题。
以上只是一些简单的配置,其实就是就application.xml中的bean信息搬到代码中而已。
各位看客完全可以把以上代码搬移到自己的项目中。