2025年动态数据源配置(基于注解)

动态数据源配置(基于注解)1 数据库类型 package com mine cloakroom config 采用枚举的方法列出所有的数据源 key 常用数据库名称来命名 数据源个数和数据库个数保持一致 public enum DatabaseType firstdb seconddb

大家好,我是讯享网,很高兴认识大家。

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()); } } 
小讯
上一篇 2025-03-29 23:58
下一篇 2025-01-28 13:25

相关推荐

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