1, 数据库类型
package com.mine.cloakroom.config; / * 采用枚举的方法列出所有的数据源key(常用数据库名称来命名) * 数据源个数和数据库个数保持一致 */ public enum DatabaseType {
firstdb,seconddb }
讯享网
2,动态数据源ContextHolder(需要继承AbstractRoutingDataSource)
讯享网package com.mine.cloakroom.config; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; // 动态数据源(需要继承AbstractRoutingDataSource) public class DynamicDataSourceContextHolder extends AbstractRoutingDataSource {
//定义一个线程安全的DatabaseType容器 private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>(); public static DatabaseType getDatabaseType() {
return contextHolder.get(); } public static void setDatabaseType(DatabaseType type) {
contextHolder.set(type); } //获取当前线程的DatabaseType @Override protected Object determineCurrentLookupKey() {
return getDatabaseType(); } public static void removeDataSource() {
contextHolder.remove(); } }
3,动态数据源配置
package com.mine.cloakroom.config; import com.zaxxer.hikari.HikariDataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; / * 动态数据源配置 */ @Configuration @MapperScan(basePackages = "com.mine.cloakroom.dao,com.mine.cloakroom.dao3", sqlSessionFactoryRef = "dynamicSqlSessionFactory")// sqlSessionFactoryRef 一定要加上, 指定用哪个sqlSessionFactory扫描dao public class DynamicDataSourceConfig {
@Bean(name = "primaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.primary") public DataSource primaryDataSource() {
return new HikariDataSource(); } @Bean(name = "secondDataSource") @ConfigurationProperties(prefix = "spring.datasource.second") public DataSource secondDataSource() {
return new HikariDataSource(); } / * 注入数据源 */ @Bean(name = "dynamicDataSource") public DynamicDataSourceContextHolder dataSource(@Qualifier("primaryDataSource") DataSource primaryDataSource, @Qualifier("secondDataSource") DataSource secondDataSource) {
Map<Object, Object> targetDataSources = new HashMap<Object, Object>(); targetDataSources.put(DatabaseType.firstdb, primaryDataSource); targetDataSources.put(DatabaseType.seconddb, secondDataSource); DynamicDataSourceContextHolder dataSource = new DynamicDataSourceContextHolder(); dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法 dataSource.setDefaultTargetDataSource(primaryDataSource);// 默认的datasource设置为myTestDbDataSource return dataSource; } / * 根据数据源创建SqlSessionFactory */ @Bean(name = "dynamicSqlSessionFactory") public SqlSessionFactory testSqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper3/*/*Mapper.xml")); return bean.getObject(); } / * 配置事务管理器 */ @Bean public DataSourceTransactionManager testTransactionManager(@Qualifier("dynamicDataSource") DynamicDataSourceContextHolder dataSource) throws Exception {
return new DataSourceTransactionManager(dataSource); } }
4,定义一个注解(使用dao方法上)
讯享网package com.mine.cloakroom.config; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({
ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface TargetDataSource {
DatabaseType value(); }
5,对注解切面到方法
package com.mine.cloakroom.config; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import java.lang.reflect.Method; @Component @Aspect @Slf4j public class DataSourceAspect {
//切换放在mapper接口的方法上,所以这里要配置AOP切面的切入点 // @Pointcut("execution( * com.mine.cloakroom.service.*.*(..))") @Pointcut("@annotation(com.mine.cloakroom.config.TargetDataSource)") public void dataSourcePointCut() {
} @Before("dataSourcePointCut()") public void before(JoinPoint joinPoint) {
//获得切面当中方法签名 MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature(); //获得签名方法 Method method = methodSignature.getMethod(); //获得在方法上面的注解 TargetDataSource targetDataSource = method.getAnnotation(TargetDataSource.class); try {
if(DatabaseType.firstdb.equals(targetDataSource.value()) || DatabaseType.seconddb.equals(targetDataSource.value())){
DatabaseType type = targetDataSource.value(); DynamicDataSourceContextHolder.setDatabaseType(type); log.debug("current thread " + Thread.currentThread().getName() + " add " + type + " to ThreadLocal"); }else{
log.debug("switch datasource fail,use default"); } } catch (Exception e) {
log.error("current thread " + Thread.currentThread().getName() + " add data to ThreadLocal error", e); } } //执行完切面后,将线程共享中的数据源名称清空 @After("dataSourcePointCut()") public void after(JoinPoint joinPoint){
DynamicDataSourceContextHolder.removeDataSource(); } }
6, dao层示例
讯享网package com.mine.cloakroom.dao3.user; import com.mine.cloakroom.bean.entity.user.UserDO; import com.mine.cloakroom.config.DatabaseType; import com.mine.cloakroom.config.TargetDataSource; import java.util.Map; public interface UserDao3 {
int deleteByPrimaryKey(Integer id); int insert(UserDO record); int insertSelective(UserDO record); @TargetDataSource(DatabaseType.seconddb) UserDO selectByPrimaryKey(Integer id); int updateByPrimaryKeySelective(UserDO record); int updateByPrimaryKey(UserDO record); Map<String, String> selectUserMap(); }
7,application.yml 配置
spring: datasource: primary: jdbc-url: jdbc:mysql://localhost:3306/cloakroom_business?characterEncoding=utf8&serverTimezone=GMT%2b8&connectTimeout=5000&socketTimeout=30000&allowMultiQueries=true username: root password: driver-class-name: com.mysql.cj.jdbc.Driver type: com.zaxxer.hikari.HikariDataSource poolName: testOneDB maximum-pool-size: 15 max-lifetime: idle-timeout: 50000 connection-timeout: 10000 minimum-idle: 5 connection-test-query: SELECT 1 second: jdbc-url: jdbc:mysql://198.101.566.66:3306/cloakroom_business?characterEncoding=utf8&serverTimezone=GMT%2b8&connectTimeout=5000&socketTimeout=30000&allowMultiQueries=true username: root password: driver-class-name: com.mysql.cj.jdbc.Driver type: com.zaxxer.hikari.HikariDataSource poolName: testSecondDB maximum-pool-size: 15 max-lifetime: idle-timeout: 50000 connection-timeout: 10000 minimum-idle: 5 connection-test-query: SELECT 1
8,测试类
讯享网public class UserServiceTest {
@Autowired private UserDao3 userDao3; // @Autowired // private UserDao2 userDao2; @Test public void mapTest() {
// DynamicDataSource.setDatabaseType(DatabaseType.seconddb);// 可以直接在代码中设计数据源,也可通过注解实现 UserDO userDO2 = userDao3.selectByPrimaryKey(2); System.out.println(userDO2); //设置数据源 // DynamicDataSource.setDatabaseType(DatabaseType.firstdb); UserDO userDO = userDao3.selectByPrimaryKey(2); System.out.println(userDO.toString()); } }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/122941.html