赞
踩
MybatisPlus多数据源配置主要解决的是多数据库连接和切换的问题。在一些大型应用中,由于数据量的增长或者业务模块的增多,可能需要访问多个数据库。这时,就需要配置多个数据源。
坐标依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
application.yml配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
配置类
@Configuration
@MapperScan(basePackages = {"com.xx.**.mapper"})
public class MybatisPlusConfig {
public MybatisPlusInterceptor mybatisPlusInterceptor(){
//新的分页插件配置方法(Mybatis Plus 3.4.0版本及其之后的版本)
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}
坐标依赖【新增】:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
application.yml配置
spring:
datasource:
db1:
url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
db2:
url: jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
@DS(“db1”)是一个MyBatis的注解,用于动态数据源切换。在MyBatis中,我们可以通过在mapper.xml文件或者Java接口上使用@DS注解来指定数据源。
实体类
@Data
@TableName("tb_user")
public class User {
@TableId(type = IdType.AUTO)
private Integer id;
@TableField("name")
private String name;
}
Service
@Service @DS("db1") public class UserServiceImpl implements UserService { @Autowired private JdbcTemplate jdbcTemplate; public List selectAll() { return jdbcTemplate.queryForList("select * from user"); } @Override @DS("db1_1") public List selectByCondition() { return jdbcTemplate.queryForList("select * from user where age >10"); } }
@DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。
多配置类【根据自己需要使用的插件进行配置、不需要的可以删除】
@Configuration @MapperScan(basePackages = "com.xx.xx.mapper.db1", sqlSessionFactoryRef = "db1SqlSessionFactory") public class db1DataSourceConfig { // 将这个对象放入Spring容器中 @Bean(name = "db1DataSource") @ConfigurationProperties(prefix = "spring.datasource.db1") public DataSource getDateSource() { return DruidDataSourceBuilder.create().build(); } @Bean(name = "db1SqlSessionFactory") public SqlSessionFactory db1SqlSessionFactory(@Qualifier("db1DataSource") DataSource datasource) throws Exception { MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean(); //configuration配置bean //MybatisConfiguration configuration = new MybatisConfiguration(); //configuration.setMapUnderscoreToCamelCase(true); //configuration.setCacheEnabled(false); // 配置打印sql语句s //configuration.setLogImpl(StdOutImpl.class); // 添加自定义SQL注入 //bean.setConfiguration(configuration); //插件对象 MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); //动态表名 //DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor(); //可以传多个表名参数,指定哪些表使用MonthTableNameHandler处理表名称 //dynamicTableNameInnerInterceptor.setTableNameHandler(new MonthTableNameHandler("t_table_name")); //以拦截器的方式处理表名称 //可以传递多个拦截器,即:可以传递多个表名处理器TableNameHandler //mybatisPlusInterceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor); //分页插件 mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); bean.setDataSource(datasource); // 设置mybatis的xml所在位置 bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/db1/*.xml")); bean.setPlugins(mybatisPlusInterceptor); return bean.getObject(); } @Bean("db1SqlSessionTemplate") public SqlSessionTemplate db1SqlSessionTemplate( @Qualifier("db1SqlSessionFactory") SqlSessionFactory sessionFactory) { return new SqlSessionTemplate(sessionFactory); } @Bean("db1TransactionManager") public PlatformTransactionManager db1TransactionManager(@Qualifier("db1DataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }
@Configuration @MapperScan(basePackages = "com.xx.xx.mapper.db2", sqlSessionFactoryRef = "db2SqlSessionFactory") public class db2DataSourceConfig { // 将这个对象放入Spring容器中 @Bean(name = "db2DataSource") @ConfigurationProperties(prefix = "spring.datasource.db2") public DataSource getDateSource() { return DruidDataSourceBuilder.create().build(); } @Bean(name = "db2SqlSessionFactory") public SqlSessionFactory db2SqlSessionFactory(@Qualifier("db2DataSource") DataSource datasource) throws Exception { MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean(); // 设置mybatis的xml所在位置 bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/db2/*.xml")); bean.setPlugins(mybatisPlusInterceptor); return bean.getObject(); } @Bean("db2SqlSessionTemplate") public SqlSessionTemplate db2SqlSessionTemplate( @Qualifier("db2SqlSessionFactory") SqlSessionFactory sessionFactory) { return new SqlSessionTemplate(sessionFactory); } @Bean("db2TransactionManager") public PlatformTransactionManager db2TransactionManager(@Qualifier("db2DataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }
数据源为db1
package com.xx.xx.mapper.db1;
/**
Mapper 接口
*/
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
启动类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class DynamicApplication{
public static void main(String[] args) {
SpringApplication.run(DynamicApplication.class, args);
}
}
动态数据源切换类
@NoArgsConstructor public class DynamicDataSource extends AbstractRoutingDataSource { private static final ThreadLocal<String> DB_CONTEXT_HOLDER = new ThreadLocal<>(); /** * 取得当前使用的数据源 * @return 当前使用的数据源 */ @Override protected Object determineCurrentLookupKey() { return getDataSource(); } /** * 设置数据源 * @param dataSource 数据源 */ public static void setDataSource(String dataSource) { DB_CONTEXT_HOLDER.set(dataSource); } /** * 获取当前数据源 * @return 数据源 */ public static String getDataSource() { return DB_CONTEXT_HOLDER.get(); } /** * 清除上下文 */ public static void clearDataSource() { DB_CONTEXT_HOLDER.remove(); } /** * 设置默认数据源,和可切换的数据源Map * @param defaultTargetDataSource 默认数据源 * @param targetDataSources 可切换的数据源Map */ public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) { super.setDefaultTargetDataSource(defaultTargetDataSource); super.setTargetDataSources(targetDataSources); super.afterPropertiesSet(); } }
多数据源配置类
@Component @Configuration public class DataSourceConfig { /** * 创建数据源db1 * @return 数据源db1 */ @Bean(name = "db1") @ConfigurationProperties(prefix = "spring.datasource.dynamic.datasource.db1") public DataSource db1DataSource() { return DataSourceBuilder.create().build(); } /** * 创建数据源db2 * @return 数据源db2 */ @Bean(name = "db2") @ConfigurationProperties(prefix = "spring.datasource.dynamic.datasource.db2") public DataSource db2DataSource() { return DataSourceBuilder.create().build(); } /** * 数据源配置 * @param db1数据源db1 * @param db2数据源db2 * @return 动态数据源切换对象。 * @Description @Primary赋予该类型bean更高的优先级,使至少有一个bean有资格作为autowire的候选者。 */ @Bean @Primary public DataSource dataSource(@Qualifier("db1") DataSource db1, @Qualifier("db2") DataSource db2) { Map<Object, Object> dsMap = new HashMap<>(2); dsMap.put("db1", db1); dsMap.put("db2", db2); return new DynamicDataSource(db1, dsMap); } }
启动类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@Import({DataSourceConfig.class})
public class DynamicApplication{
public static void main(String[] args) {
SpringApplication.run(DynamicApplication.class, args);
}
}
创建自定义注解【用来指定使用哪个数据源】
/**
* @Description 在方法上使用,用于指定使用哪个数据源
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String name() default "";
}
创建AOP【根据注解的参数切换数据源】
/** * @Description 多数据源切换AOP,@Order(-100)是为了保证AOP在事务注解之前生效,Order的值越小,优先级越高 */ @Aspect @Component @Order(-100) @Slf4j public class DataSourceAspect { @Pointcut("execution(* com.xx.xx.service..*.*(..))") private void dsPointCut() { } @Around("dsPointCut()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { // 获取当前指定的数据源 MethodSignature ms = (MethodSignature) joinPoint.getSignature(); Method method = ms.getMethod(); DataSource dataSource = method.getAnnotation(DataSource.class); if (Objects.isNull(dataSource)) { // 使用默认数据源 DynamicDataSource.setDataSource("db1"); log.info("默认数据源启动"); } else { // 匹配到的话,设置到动态数据源上下文中 DynamicDataSource.setDataSource(dataSource.name()); log.info("匹配到数据源:{}", dataSource.name()); } try { // 执行目标方法,返回值即为当前方法的返回值 return joinPoint.proceed(); } finally { // 方法执行完毕之后,销毁当前数据源信息,进行垃圾回收 DynamicDataSource.clearDataSource(); log.info("清空数据源"); } } }
Service
@Service public class UserServiceImpl implements UserService { @Autowired private JdbcTemplate jdbcTemplate; @DataSource(name = "db1") public List selectAll() { return jdbcTemplate.queryForList("select * from user"); } @Override @DataSource(name = "db2") public List selectByCondition() { return jdbcTemplate.queryForList("select * from user where age >10"); } }
1、三种数据源配置的方法可根据实际需要选择
2、使用 @DS 注解切换数据源时,使用springboot数据源的自动配置,需要将DataSourceConfig配置注释掉
3、使用 @DataSource 自定义注解时,排除springboot数据源的自动配置,引入DataSourceConfig配置
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。