博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring boot配置mybatis多数据源
阅读量:4577 次
发布时间:2019-06-08

本文共 6185 字,大约阅读时间需要 20 分钟。

 根据业务要求,需要实现数据库的读写分离,即一个应用配置多个数据库。网上看了一些案例,总结了一个最简单的配置方法。

原理:mybatis通过SqlSessionFactory获取session从而执行sql语句,而SqlSessionFactory是从DataSource获取session的。spring boot提供了一个动态切换数据库的抽象类AbstractRoutingDataSource,我们只需继承该抽象类创建一个动态数据源,并配置到SqlSessionFactory即可。AbstractRoutingDataSource会根据determineCurrentLookupKey()方法返回的数据源key获取对应的数据源。

配置过程:

一、关闭数据源自动配置

  在@SpringBootApplication注解上加exclude= {DataSourceAutoConfiguration.class}即可。否则spring boot会启用自动配置数据源。

@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})

  如果不关闭会报异常:org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'dataSource': Requested bean is currently in creation: Is there an unresolvable circular reference?

二、继承AbstractRoutingDataSource创建动态数据源类

  只需实现determineCurrentLookupKey()一个方法即可。该方法是获取数据源的名字,AbstractRoutingDataSource要通过这个名字去找对应的数据源。这个方法怎么写,且看稍后解释。

public class DynamicDataSource extends AbstractRoutingDataSource {    @Override    protected Object determineCurrentLookupKey() {        return DynamicDataSourceHolder.getDataSourceKey();    }}

三、application.properties配置文件配置数据源。注意,mysql的连接串名字是jdbc-url,而不是url

spring.datasource.master.jdbc-url=jdbc:mysql://localhost:3306/testspring.datasource.master.username=rootspring.datasource.master.password=rootspring.datasource.slave.jdbc-url=jdbc:mysql://localhost:3306/test_slavespring.datasource.slave.username=rootspring.datasource.slave.password=root

四、配置bean

  1、用@ConfigurationProperties读取application.properties的数据库连接串、用户名、密码,配置每个DataSource的bean。使用DataSourceBuilder创建数据源时,如果有DBCP的jar包,则会自动启用DBCP连接池。如果需要使用druid等其他连接池也可以通过配置对应的连接池bean实现。

  2、创建动态数据源类。

  这个bean是动态数据源选择的核心。实例化DynamicDataSource,把上面配置的两个实际数据源以map的形式配置到动态数据源上。而上面第二步determineCurrentLookupKey()返回的值就是这个map的key,通过这个key就能定位到实际数据源。

   3、配置SqlSessionFactory

  把SqlSessionFactory的数据源设置为上一步配置的动态数据源。指定mapperLocations,即mapper对应的.xml的位置。如果不指定会报错找不到mapper对应的statement。

这一步整个bean配置如下:

@Configurationpublic class DynamicDataSourceConfig {     配置多个DataSource    @Bean    @ConfigurationProperties(prefix = "spring.datasource.master")    public DataSource masterDataSource() {        return DataSourceBuilder.create().build();    }    @Bean    @ConfigurationProperties(prefix = "spring.datasource.slave")    public DataSource slaveDataSource() {        return DataSourceBuilder.create().build();    }     创建动态数据源    @Bean    public DataSource dataSource() {        DynamicDataSource dynamicDataSource = new DynamicDataSource();        // 创建默认数据源        dynamicDataSource.setDefaultTargetDataSource(masterDataSource());        // 配置多数据源        Map
dataSourceMap = new HashMap<>(4); dataSourceMap.put("master", masterDataSource()); dataSourceMap.put("slave", slaveDataSource()); dynamicDataSource.setTargetDataSources(dataSourceMap); return dynamicDataSource; } 配置SqlSessionFactory @Bean public SqlSessionFactory sqlSessionFactory() throws Exception { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); //设置数据源为动态数据源 sqlSessionFactoryBean.setDataSource(dataSource()); //mapper的.xml文件位置 PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:/mapper/*.xml")); return sqlSessionFactoryBean.getObject(); }}

 五、数据源选择

  为了使用方便,我们使用注解+AOP的方式来实现数据源的选择。

  1、创建一个存放数据源key的ThreadLocal,DynamicDataSourceHolder

public class DynamicDataSourceHolder {    private static final ThreadLocal
dataSourceThreadLocal = new ThreadLocal
(); private static Set
dataSourceKeys = new HashSet
(); static { dataSourceKeys.add("master"); dataSourceKeys.add("slave"); } public static void setDataSourceKey(String dataSourceKey) { dataSourceThreadLocal.set(dataSourceKey); } public static String getDataSourceKey() { return dataSourceThreadLocal.get(); } public static void clearDataSourceKey() { dataSourceThreadLocal.remove(); } public static boolean containsDataSourceKey(String dataSourceKey) { return dataSourceKeys.contains(dataSourceKey); }}

  2、创建注解,value值为数据源的key,用于选择数据源

@Target({ ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface TargetDataSource {    String value() default "master";}

  3、aop读取注解,把注解的value设置到DynamicDataSourceHolder的线程上下文上。对应上面第二步的determineCurrentLookupKey()方法,选择数据源就是从这个线程上下文中取得这一步设置的数据源key。数据源必须在事务执行之前设置好,所以这一步的aop的优先级必须在@Transctional之前。

@Aspect@Order(-10) // 保证该AOP在@Transactional之前执行@Componentpublic class DynamicDataSourceAspect {    private static final Logger log = LoggerFactory.getLogger(DynamicDataSourceAspect.class);        @Before("@annotation(targetDataSource)")    public void changeDataSource(JoinPoint point, TargetDataSource targetDataSource) throws Throwable {        // 获取当前的指定的数据源;        String dataSourceKey = targetDataSource.value();        // 如果不在我们注入的所有的数据源范围之内,那么输出警告信息,系统自动使用默认的数据源。        if (!DynamicDataSourceHolder.containsDataSourceKey(dataSourceKey)) {            log.info("数据源[{}]不存在,使用默认数据源 > {}", targetDataSource.value(), point.getSignature());        } else {            log.info("Use DataSource : {} > {}", targetDataSource.value(), point.getSignature());            // 找到的话,那么设置到动态数据源上下文中。            DynamicDataSourceHolder.setDataSourceKey(targetDataSource.value());        }    }    @After("@annotation(targetDataSource)")    public void restoreDataSource(JoinPoint point, TargetDataSource targetDataSource) {        log.info("Revert DataSource : {} > {}", targetDataSource.value(), point.getSignature());        // 方法执行完毕之后,销毁当前数据源信息,进行垃圾回收。        DynamicDataSourceHolder.clearDataSourceKey();    }}

六、使用

  在方法上加@TargetDataSource注解即可。如果不加注解或者注解上的value不存在,则使用默认数据源。

@TargetDataSource("master")    public BookItem getByIdMaster(Long id){        return userMapper.selectByPrimaryKey(id);    }        @TargetDataSource("slave")    public BookItem getByIdSlave(Long id){        return userMapper.selectByPrimaryKey(id);    }

 

转载于:https://www.cnblogs.com/guods/p/9071749.html

你可能感兴趣的文章
C#-CLR各版本特点
查看>>
css3背景透明文字不透明
查看>>
《java JDK7 学习笔记》之接口与多态
查看>>
LeetCode 96:Unique Binary Search Trees
查看>>
kernel-char设备的建立
查看>>
DVWA-CSRF
查看>>
ubuntu common software introduction
查看>>
资源相互引用时 需添加 PerformSubstitution=True
查看>>
MapRedece(单表关联)
查看>>
蒲公英App开发之检测新版本
查看>>
【安卓基础】倒计时按钮封装(验证码倒计时按钮)
查看>>
configparser模块
查看>>
SelectQueryBuilder的用法
查看>>
android的用户定位(一)
查看>>
creat-react-app搭建的项目中按需引入antd以及配置Less和如何修改antd的主题色
查看>>
IIS安装
查看>>
html块级元素和行级元素的区别和使用
查看>>
for循环嵌套
查看>>
寒冬夜行人
查看>>
poj1151 Atlantis
查看>>