第一种方式:springboot + mybatis
1、yml配置文件
#端口
server.port: 7788
spring.application.name: bddemo
# mysql
spring.datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
#数据库1
db1:
jdbc-url: jdbc:mysql://127.0.0.1:3306/db1?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: 123456
#数据库2
db2:
jdbc-url: jdbc:mysql://127.0.0.1:3306/db2?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: 123456
# mybatis
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml
type-aliases-package: ccom.example.demo.*.entity
2、动态数据源类
import com.example.demo.utils.DataSourceUtil;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 动态数据源类
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceUtil.getDB();
}
}
3、多数据源配置类
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* 数据库配置
*/
@Configuration
public class DataSourceConfig {
/**
* 数据源1
* spring.datasource.db1:application.properteis中对应属性的前缀
* @return
*/
@Bean(name = "db1")
@ConfigurationProperties(prefix = "spring.datasource.db1")
public DataSource dataSourceOne() {
return DataSourceBuilder.create().build();
}
/**
* 数据源2
* spring.datasource.db2:application.properteis中对应属性的前缀
* @return
*/
@Bean(name = "db2")
@ConfigurationProperties(prefix = "spring.datasource.db2")
public DataSource dataSourceTwo() {
return DataSourceBuilder.create().build();
}
/**
* 动态数据源: 通过AOP在不同数据源之间动态切换
* @return
*/
@Primary
@Bean(name = "dynamicDataSource")
public DataSource dynamicDataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
// 默认数据源
dynamicDataSource.setDefaultTargetDataSource(dataSourceOne());
// 配置多数据源
Map<Object, Object> dsMap = new HashMap<>();
dsMap.put("db1", dataSourceOne());
dsMap.put("db2", dataSourceTwo());
dynamicDataSource.setTargetDataSources(dsMap);
return dynamicDataSource;
}
/**
* 配置多数据源后IOC中存在多个数据源了,事务管理器需要重新配置,不然器不知道选择哪个数据源
* 事务管理器此时管理的数据源将是动态数据源dynamicDataSource
* 配置@Transactional注解
* @return
*/
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dynamicDataSource());
}
}
4、切换工具类:DataSourceUtil
/**
* 数据源切换工具
*/
public class DataSourceUtil {
/**
* 默认数据源
*/
public static final String DEFAULT_DS = "db1";
/**
* 数据源属于一个公共的资源
* 采用ThreadLocal可以保证在多线程情况下线程隔离
*/
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
/**
* 设置数据源名
* @param dbType
*/
public static void setDB(String dbType) {
contextHolder.set(dbType);
}
/**
* 获取数据源名
* @return
*/
public static String getDB() {
return (contextHolder.get());
}
/**
* 清除数据源名
*/
public static void clearDB() {
contextHolder.remove();
}
}
4、启动:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
//移除默认数据库配置类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class DbDemoApplication {
public static void main(String[] args) {
SpringApplication.run(DbDemoApplication.class, args);
}
}
5、测试:
DataSourceUtil.setDB("db2");
第二种方式:springboot + durid + mybatis
1、yml配置文件:
spring:
profile: dev
datasource:
db1:
url: jdbc:oracle:thin:@ip:1521/center
username: xxx
password: xxx
initialSize: 1
minIdle: 1
maxActive: 5
driverClassName: oracle.jdbc.driver.OracleDriver
db2:
url: jdbc:mysql://xxx:3306/xxx?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&autoReconnect=true&autoReconnectForPools=true&allowMultiQueries=true
username: xxx
password: xxx
initialSize: 1
minIdle: 1
maxActive: 5
driverClassName: com.mysql.cj.jdbc.Driver
2、DruidProperties1 配置类(加载yml中的数据库配置)
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Version 1.0
*/
@Component
@ConfigurationProperties(
prefix = "spring.datasource.db1"
)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DruidProperties1 {
/**
* mysql地址
*/
private String url;
/**
* mysql用户名
*/
private String username;
/**
* mysql加密密码
*/
private String password;
/**
* mysql类加载器
*/
private String driverClassName;
private int initialSize;
private int minIdle;
private int maxActive;
}
3、DataSourceConfig1配置类 (durid连接池配置)
import com.alibaba.druid.pool.DruidDataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
@MapperScan(basePackages = "xxx.dao1.**", sqlSessionFactoryRef = "firstSqlSessionFactory")
public class DataSourceConfig1 {
@Autowired
private DruidProperties1 druidProperties1;
@Bean
DataSource firstDataSource() throws SQLException {
log.info("=================start init dataSource1===================");
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(this.druidProperties1.getUrl());
druidDataSource.setUsername(this.druidProperties1.getUsername());
druidDataSource.setPassword(this.druidProperties1.getPassword());
druidDataSource.setDriverClassName(this.druidProperties1.getDriverClassName());
druidDataSource.setInitialSize(this.druidProperties1.getInitialSize());
druidDataSource.setMinIdle(this.druidProperties1.getMinIdle());
druidDataSource.setMaxActive(this.druidProperties1.getMaxActive());
return druidDataSource;
}
@Bean("firstSqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("firstDataSource")DataSource dataSource) throws Exception {
List<Resource> list = new ArrayList<Resource>();
list.addAll(Arrays.asList(new PathMatchingResourcePatternResolver().getResources("classpath:mapper1/*.xml")));
Resource[] mapperLocations = new Resource[list.size()];
for (int i=0;i<list.size();i++) {
mapperLocations[i]= list.get(i);
}
SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dataSource);
sqlSessionFactory.setMapperLocations(mapperLocations);
sqlSessionFactory.setConfigLocation(new PathMatchingResourcePatternResolver().getResource("classpath:/mybatis-config.xml"));
return sqlSessionFactory.getObject();
}
@Primary
@Bean("firstSqlSessionTemplate")
public SqlSessionTemplate systemSqlSessionTemplate(@Qualifier("firstSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
return new SqlSessionTemplate(sqlSessionFactory);
}
}
注解说明:
- @EnableTransactionManagement(proxyTargetClass = true)
Spring提供的AOP功能有两种实现方式,可选值有PROXY 和 ASPECTJ,默认值为AdviceMode.PROXY。
一种是Spring自带的AOP功能,主要靠JDK代理和CGLIB代理实现,另外一种是通过第三方框架ASPECTJ实现。
@EnableTransactionManagement中的mode选项就是设定Spring用哪种方式提供AOP功能。
AdviceMode.PROXY表示用Spring自带的AOP功能,AdviceMode.ASPECTJ表示使用ASPECTJ提供AOP功能。
需要注意的是Spring自带的AOP功能不支持本地调用的代理功能,也就是说同一个类中的方法互相调用不会“触发”代理方法。
如果想让自调用触发代理,可以考虑使用ASPECTJ。
- @Qualifier:起到了一个筛选的作用只有Bean上加有@Qualifier注解的Bean才会被收集注入。
@FK
@Bean
public Date d1() {
return new Date() ;
}
@Bean
public Date d2() {
return new Date() ;
}
@Resource
@FK
private List<Date> dates = Collections.emptyList() ;
- @Bean:是一个方法级别上的注解,主要用在@Configuration和@Compoment注解的类里
- @Primary :在配置文件中使用@Bean注解标注方法,来注册bean,可以在@Bean标注的方法上加上@Primary,标注这个bean为主要候选bean
4、动态多数据源DynamicDataSource
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.Map;
/**
* @Description: 动态多数据源
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return getDataSource();
}
public static void setDataSource(String dataSource) {
contextHolder.set(dataSource);
}
public static String getDataSource() {
return contextHolder.get();
}
public static void clearDataSource() {
contextHolder.remove();
}
}
5、多数据源事务管理
@Configuration
public class TransactionConfig {
public final static String DEFAULT_TX = "defaultTx";
public final static String SECOND_TX = "secondTx";
@Bean(name=TransactionConfig.DEFAULT_TX)
@Primary
public DataSourceTransactionManager transaction(@Qualifier("firstDataSource")DataSource firstDataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(firstDataSource);
return dataSourceTransactionManager;
}
@Bean(name=TransactionConfig.SECOND_TX)
public DataSourceTransactionManager secondTransaction(@Qualifier("secondDataSource") DataSource secondDataScoure){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(secondDataScoure);
return dataSourceTransactionManager;
}
}