- pom.xml檔案引入
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
- application.properties檔案配置
## master db config begin
spring.datasource.druid.master.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.master.url= jdbc:mysql://localhost:3306/dbname?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.druid.master.username=root
spring.datasource.druid.master.password=123456
# Druid configuration
# Druid其他配置
spring.datasource.druid.master.initial-size=5
spring.datasource.druid.master.max-active=20
spring.datasource.druid.master.min-idle=10
spring.datasource.druid.master.max-wait=10
spring.datasource.druid.master.filters=stat,wall
spring.datasource.druid.master.filter.stat.log-slow-sql=true
spring.datasource.druid.master.filter.stat.slow-sql-millis=2000
# 配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接配接,機關是毫秒
spring.datasource.druid.master.time-between-eviction-runs-millis=60000
#配置一個連接配接在池中的最小生存時間,機關是毫秒
spring.datasource.druid.master.min-evictable-idle-time-millis=300000
spring.datasource.druid.master.validation-query=SELECT 1
spring.datasource.druid.master.test-while-idle=true
spring.datasource.druid.master.test-on-borrow=false
spring.datasource.druid.master.test-on-return=false
#打開PSCache,并且指定每個連接配接上PSCache的大小
spring.datasource.druid.master.pool-prepared-statements=false
spring.datasource.druid.master.max-pool-prepared-statement-per-connection-size=20
## slave db config begin
spring.datasource.druid.slave.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.slave.url= jdbc:mysql://localhost:3306/dbname2?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.druid.slave.username=root
spring.datasource.druid.slave.password=123456
# Druid configuration
# Druid其他配置
spring.datasource.druid.slave.initial-size=5
spring.datasource.druid.slave.max-active=20
spring.datasource.druid.slave.min-idle=10
spring.datasource.druid.slave.max-wait=10
spring.datasource.druid.slave.filters=stat,wall
spring.datasource.druid.slave.filter.stat.log-slow-sql=true
spring.datasource.druid.slave.filter.stat.slow-sql-millis=2000
# 配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接配接,機關是毫秒
spring.datasource.druid.slave.time-between-eviction-runs-millis=60000
#配置一個連接配接在池中的最小生存時間,機關是毫秒
spring.datasource.druid.slave.min-evictable-idle-time-millis=300000
spring.datasource.druid.slave.validation-query=SELECT 1
spring.datasource.druid.slave.test-while-idle=true
spring.datasource.druid.slave.test-on-borrow=false
spring.datasource.druid.slave.test-on-return=false
#打開PSCache,并且指定每個連接配接上PSCache的大小
spring.datasource.druid.slave.pool-prepared-statements=false
spring.datasource.druid.slave.max-pool-prepared-statement-per-connection-size=20
- 定義資料源類型DataSourceType.java
資料源類型
詳細代碼:DataSourceType.java
/**
* @author 光州大少爺
* @version 1.0
*/
public enum DataSourceType {
MASTER, SLAVE
}
- 多資料源連接配接配置DynamicDataSourceConfig.java
資料源連接配接配置
詳細代碼:DynamicDataSourceConfig.java
/**
* @author 光州大少爺
* @version 1.0
*/
@Configuration
public class DynamicDataSourceConfig {
@Bean(name = "masterDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.druid.master")
public DataSource masterDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "slaveDataSource") // 聲明其為Bean執行個體
@ConfigurationProperties(prefix = "spring.datasource.druid.slave")
public DataSource slaveDataSource() {
return DruidDataSourceBuilder.create().build();
}
/**
* @return
* @desc 動态配置多資料源
*/
@Bean(name = "dynamicDataSource")
public DynamicDataSource multipleDataSource(@Qualifier("masterDataSource") DataSource masterDb, @Qualifier("slaveDataSource") DataSource slaveDb) {
DynamicDataSource multipleDataSource = new DynamicDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceType.MASTER, masterDb);
targetDataSources.put(DataSourceType.SLAVE, slaveDb);
//添加資料源
multipleDataSource.setTargetDataSources(targetDataSources);
//設定預設資料源
multipleDataSource.setDefaultTargetDataSource(masterDb);
multipleDataSource.afterPropertiesSet();
return multipleDataSource;
}
@Bean(name = "sqlSessionFactory")
@Primary
public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
VFS.addImplClass(SpringBootVFS.class);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mappers/mysql/*.xml"));
return bean.getObject();
}
@Bean(name = "transactionManager")
@Primary
public DataSourceTransactionManager transactionManager(@Qualifier("dynamicDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "sqlSessionTemplate")
@Primary
public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory);
//解決mybatis查詢過濾掉為空字段的問題
sqlSessionTemplate.getConfiguration().setCallSettersOnNulls(true);
return sqlSessionTemplate;
}
}
- 動态資料源配置DynamicDataSourceContextHolder.java
動态資料源配置
詳細代碼:DynamicDataSourceContextHolder.java
/**
* @author 光州大少爺
* @version 1.0
*/
public class DynamicDataSourceContextHolder {
/**
* 線程獨立
*/
private static final ThreadLocal<DataSourceType> contextHolder = new ThreadLocal<>();
public static DataSourceType getDataSourceType() {
DataSourceType dataSourceType = contextHolder.get() == null ? DataSourceType.MASTER : contextHolder.get();
return dataSourceType;
}
public static void setDataSourceType(DataSourceType dataSourceType) {
if (dataSourceType == null) throw new NullPointerException("未設定資料源");
contextHolder.set(dataSourceType);
}
public static void clearDataSourceType() {
contextHolder.remove();
}
}
- 動态資料源切換實作DynamicDataSource.java
動态資料源切換實作
詳細代碼:DynamicDataSource.java
/**
* @author 光州大少爺
* @version 1.0
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
DataSourceType dataSourceType = DynamicDataSourceContextHolder.getDataSourceType();
return dataSourceType;
}
}
- 定義多資料源注解DataSource.java
資料源注解
詳細代碼:DataSource.java
/**
* @author 光州大少爺
* @version 1.0
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface DataSource {
DataSourceType value() default DataSourceType.MASTER;
}
- AOP攔截多資料源注解DynamicDataSourceAspect.java
AOP攔截資料源注解
詳細代碼:DynamicDataSourceAspect.java
/**
* @author 光州大少爺
* @version 1.0
*/
@Aspect
@Component
public class DynamicDataSourceAspect {
private Logger LOG = LoggerFactory.getLogger(this.getClass());
/**
* 在Mapper層添加注解,實作切換資料源
*/
@Pointcut("execution(public * com..*.dao.*.*(..))")
public void dataSourcePointCut() {
}
@Before("dataSourcePointCut()")
public void before(JoinPoint joinPoint) {
Object target = joinPoint.getTarget();
String method = joinPoint.getSignature().getName();
Class<?>[] clazz = target.getClass().getInterfaces();
Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes();
try {
Method m = clazz[0].getMethod(method, parameterTypes);
//如果方法上存在切換資料源的注解,則根據注解内容進行資料源切換
if (m != null && m.isAnnotationPresent(DataSource.class)) {
DataSource data = m.getAnnotation(DataSource.class);
DataSourceType dataSourceType = data.value();
DynamicDataSourceContextHolder.setDataSourceType(dataSourceType);
LOG.debug("current thread " + Thread.currentThread().getName() + " add " + dataSourceType + " to ThreadLocal");
} else {
LOG.debug("no data source specified, so use the default data source.");
}
} catch (Exception e) {
LOG.error("switch datasource fail,current thread " + Thread.currentThread().getName() + " add data to ThreadLocal error", e);
}
}
@After("dataSourcePointCut()")
public void after(JoinPoint joinPoint) {
DynamicDataSourceContextHolder.clearDataSourceType();
}
}
- Dao層動态切換資料源UserDao.java
Dao層實作
詳細代碼:UserDao.java
/**
* @author 光州大少爺
* @version 1.0
*/
@Repository
@Mapper
public interface UserDao {
@DataSource(DataSourceType.MASTER)
void saveUser(DataModel saveModel);
}
- 本篇文章完結,感謝你的觀看!