原创

Java架构师方案—多数据源开发详解及原理(二)(附完整项目代码)

1. mybatis下数据源开发工作

在properties文件中配置两个数据库连接参数

demo项目使用的是hikari数据源,配置 数据库地址,用户名,密码,数据库驱动等参数,在DataSource1Config类中通过@ConfigurationProperties(prefix = "spring.datasource.hikari.db1")的方式将参数注入到DataSource对象中。DataSource1Config类和DataSource2Config类分别创建了两个数据源对象。

server.port=8080


# 数据库myutilproject0
spring.datasource.hikari.db1.jdbc-url=jdbc:mysql://ip:port/myutilproject0?characterEncoding=GBK&useSSL=false
spring.datasource.hikari.db1.username=root
spring.datasource.hikari.db1.password=
spring.datasource.hikari.db1.driver-class-name=com.mysql.cj.jdbc.Driver

# 数据库myutilproject1
spring.datasource.hikari.db2.jdbc-url=jdbc:mysql://ip:port/myutilproject1?characterEncoding=GBK&useSSL=false
spring.datasource.hikari.db2.username=root
spring.datasource.hikari.db2.password=
spring.datasource.hikari.db2.driver-class-name=com.mysql.cj.jdbc.Driver
配置Dao层需要的工具对象:DataSource,SqlSessionFactory,SqlSessionTemplate(SqlSession),DataSourceTransactionManager

DataSource: 数据源对象,封装与数据库交互的connection对象,通过spring的@ConfigurationProperties注解方式获取配置参数并创建该对象。

SqlSessionFactory:SqlSession对象的创建工厂,关联Dao层的代理对象,代理对象需要的SqlSession从这里获取。

SqlSession:负责与数据库进行数据传输和交互并维护会话状态,这里使用了SqlSessionTemplate代理mybatis默认的SqlSession实现类,其实动态切换多数据源的方案也可以通过覆盖SqlSession来实现。

DataSourceTransactionManager:开启并配置数据源对象的事务管理器,开启事务机制。

@MapperScan工作目标创建mapper接口的代理对象,关联配置的SqlSessionFactory对象,使用了该注解就不需要在mapper接口上使用@Mapper了

@Mapper:告诉spring及mybatis,这个是mapper接口,需要创建代理对象。

注意:@MapperScan(basePackages = "jackdking.dao.db2", sqlSessionTemplateRef = "db2SqlSessionTemplate")这个地方有个关键点:这里生成的mapper接口代理对象与数据交互使用的sqlsession指定为db2SqlSessionTemplate,因此你选择db2中的对象就相当于选择了对应的数据库。

package jackdking.config;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

/**
 * 数据源1配置
 * @author YI
 * @date 2018-12-6 09:35:36
 */
@Configuration
@MapperScan(basePackages = "jackdking.dao.db1", sqlSessionTemplateRef = "db1SqlSessionTemplate")
public class DataSource1Config {

    /**
     * 生成数据源.  @Primary 注解声明为默认数据源
     */
    @Bean(name = "db1DataSource")
    @ConfigurationProperties(prefix = "spring.datasource.hikari.db1")
    @Primary
    public DataSource testDataSource() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 创建 SqlSessionFactory
     */
    @Bean(name = "db1SqlSessionFactory")
    @Primary
    public SqlSessionFactory testSqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        // 如果使用xml请放开下面配置
        // bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/db1/*.xml"));
        return bean.getObject();
    }

    /**
     * 配置事务管理
     */
    @Bean(name = "db1TransactionManager")
    @Primary
    public DataSourceTransactionManager testTransactionManager(@Qualifier("db1DataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    /**
     * 配置数据库操作模板
     * @param sqlSessionFactory
     * @return
     * @throws Exception
     */
    @Bean(name = "db1SqlSessionTemplate")
    @Primary
    public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("db1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

}

Mapper接口


import org.springframework.beans.factory.annotation.Qualifier;

import jackdking.bean.User;

@Qualifier("db1SqlSessionTemplate")
public interface User1Mapper {

    User selectByPrimaryKey(Integer id);

}

2. 数据源与DAO的关系原理模型

从Dao层到DataSource的上下层级依赖关系

alt

而我们对这些模型对象的依赖配置是由DataSource往Dao层方向进行的,从上图来看,DAO与数据源的关系模型非常明了。

3. 为什么要配置SqlSessionTemplate类的bean

我们Dao层直接打交道的是SQLSession,mybatis默认的是DefaultSqlSession,这里使用了SqlSessionTemplate来替代它。

以下是使用SqlSessionTemplate的好处

  • SqlSessionTemplate是MyBatis-Spring的核心。这个类负责管理MyBatis的SqlSession,调用MyBatis的SQL方法。SqlSessionTemplate是线程安全的,可以被多个DAO所共享使用。
  • 当调用SQL方法时,包含从映射器getMapper()方法返回的方法,SqlSessionTemplate将会保证使用的SqlSession是和当前Spring的事务相关的。此外,它管理session的生命周期,包含必要的关闭,提交或回滚操作。
  • SqlSessionTemplate实现了SqlSession,这就是说要对MyBatis的SqlSession进行简易替换。
  • SqlSessionTemplate通常是被用来替代默认的MyBatis实现的DefaultSqlSession,因为它不能参与到Spring的事务中也不能被注入,因为它是线程不安全的。相同应用程序中两个类之间的转换可能会引起数据一致性的问题。

4. 多数据源应用测试

多数据源应用和原理的分析,我之前的一篇文章也剖析过,是需要通过注解的形式来选择数据源:Java架构师方案—多数据源原理及应用(一)(附完整项目代码)

而这篇文章介绍的应用是不需要使用注解方式的,因为DAO层的dao对象是绑定了数据源的,你选择不同的dao就选择了不同的数据源。

测试类MyApplicationRunner


@Component
public class MyApplicationRunner implements ApplicationRunner{

    @Autowired
    User1Mapper  user1Mapper;

    @Autowired
    User2Mapper  user2Mapper;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        // TODO Auto-generated method stub

        System.out.println("从db1数据库中查询数据");

              //从db1中查出数据
        User user1 = user1Mapper.selectByPrimaryKey(11);
        System.out.println(user1.toString());

        System.out.println("从db2数据库中查询数据");

        //从db2中查出数据
        User user2 = user2Mapper.selectByPrimaryKey(11);
        System.out.println(user2.toString());


    }

}

db1:myutilproject0 的user表数据
alt

db2:myutilproject1 的user表数据
alt

启动项目,测试数据如下

从db1数据库中查询数据
2020-09-16 11:13:22.679  INFO 20064 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2020-09-16 11:13:23.230  INFO 20064 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
User [id=11, name=jackdking-master, gender=male]
从db2数据库中查询数据
2020-09-16 11:13:23.305  INFO 20064 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Starting...
2020-09-16 11:13:23.746  INFO 20064 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Start completed.
User [id=11, name=jackdking-slave, gender=male]

从测试数据可以得出结论,不同的dao从不同的库中查询出数据,因此这个项目通过将不同dao绑定到不同的数据源来实现多数据源场景。

关注共图社,有更多惊喜。


转载这篇文章需要标注作者和出处:空白-bittechblog

欢迎加入技术群:获得更多java,springboot,redis,kafka圈的好友,共图技术未来
点击获取技术群二维码

还要配置状态转移信息以及事件处理器逻辑的开发。完整的demo项目,请关注公众号“前沿科技bot“并发送"多数据源"获取。

alt

正文到此结束
本文目录