# Mybatis多数据源配置

# 介绍

多数据源配置是我们在业务开发中很容易碰到的场景,我们一般会将不同的业务类型数据放在不同的库中,比如用户与认证相关数据与普通业务信息数据,这些就可以分别放在不同的库中。当数据处于不同的库的时候,这个时候就需要我们能够配置多数据源,并且同时连接多个数据源,以下内容即是介绍如何配置Mybatis多数据源。

# 实现

接续着我们上篇介绍,对代码进行了一些改造,代码中有一些关于AOP记录用户行为日志的代码不做详细介绍,具体请听下回分解。

  1. 修改配置文件:添加新的数据库连接配置,并分别命名
spring:
  datasource:
    example:
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/example
      username: root
      password: 123456
    test:
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/test
      username: root
      password: 123456
  1. 添加数据源配置类 添加第一个数据源配置
@Configuration
@MapperScan(basePackages = ExampleDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "exampleSqlSessionFactory")
public class ExampleDataSourceConfig {

    // mysqldao扫描路径
    static final String PACKAGE = "com.example.demo.dao.example";
    //  若使用xml形式,则需要使用以下代码
    //  // mybatis mapper扫描路径
    //  static final String MAPPER_LOCATION = "classpath:mapper/mysql/*.xml";

    @Primary // 配置主数据源,可加可不加,添加以后启动会默认初始化主数据源
    @Bean(name = "exampleDataSource")
    @ConfigurationProperties("spring.datasource.example") // 依据指定配置初始化数据源
    public DataSource exampleDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Primary
    @Bean(name = "exampleTransactionManager")
    public DataSourceTransactionManager exampleTransactionManager(@Qualifier("exampleDataSource")DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Primary
    @Bean(name = "exampleSqlSessionFactory")
    public SqlSessionFactory exampleSqlSessionFactory(@Qualifier("exampleDataSource") DataSource dataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        //  //如果不使用xml的方式配置mapper,则可以省去下面这行mapper location的配置。
        //  sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
        //    .getResources(Test1DataSourceConfig.MAPPER_LOCATION));
        return sessionFactory.getObject();
    }
}

添加第二个数据源配置

@Configuration
@MapperScan(basePackages = TestDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "testSqlSessionFactory")
public class TestDataSourceConfig {

    // mysqldao扫描路径
    static final String PACKAGE = "com.example.demo.dao.test";
    //  若使用xml形式,则需要使用以下代码
    //  // mybatis mapper扫描路径
    //  static final String MAPPER_LOCATION = "classpath:mapper/mysql/*.xml";

    @Bean(name = "testDataSource")
    @ConfigurationProperties("spring.datasource.test") // 依据指定配置初始化数据源
    public DataSource testDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "testTransactionManager")
    public DataSourceTransactionManager testTransactionManager(@Qualifier("testDataSource")DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "testSqlSessionFactory")
    public SqlSessionFactory testSqlSessionFactory(@Qualifier("testDataSource") DataSource dataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        //  //如果不使用xml的方式配置mapper,则可以省去下面这行mapper location的配置。
        //  sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
        //    .getResources(Test1DataSourceConfig.MAPPER_LOCATION));
        return sessionFactory.getObject();
    }
}
  1. 在指定路径下实现dao层

第一个数据源mapper路径配置为com.example.demo.dao.example,在该路径下实现dao层代码

@Component
@Mapper
public interface StudentDao {

    @Insert("insert into student(sno,sname,ssex) values(#{sno},#{name},#{sex})")
    int add(Student student);

    @Update("update student set sname=#{name},ssex=#{sex} where sno=#{sno}")
    int update(Student student);

    @Delete("delete from student where sno=#{sno}")
    int deleteBysno(String sno);

    @Select("select * from student where sno=#{sno}")
    @Results(id = "student",value= {
            @Result(property = "sno", column = "sno", javaType = String.class),
            @Result(property = "name", column = "sname", javaType = String.class),
            @Result(property = "sex", column = "ssex", javaType = String.class)
    })
    Student queryStudentBySno(String sno);
}

第二个数据源mapper路径配置为com.example.demo.dao.test,在该路径下实现dao层代码

@Component
@Mapper
public interface SysLogDao {

    @Insert("insert into test.syslog(username,operation,time,method,params,ip,created_time) " +
            "values(#{username},#{operation},#{time},#{method},#{params},#{ip},#{createTime})")
    int add(SysLog sysLog);

    @Select("select * from test.syslog where username=#{username}")
    @Results(id = "sysLog",value= {
            @Result(property = "username", column = "username", javaType = String.class),
            @Result(property = "operation", column = "operation", javaType = String.class),
            @Result(property = "time", column = "time", javaType = Integer.class),
            @Result(property = "method", column = "method", javaType = String.class),
            @Result(property = "params", column = "params", javaType = String.class),
            @Result(property = "ip", column = "ip", javaType = String.class),
            @Result(property = "createTime", column = "created_time", javaType = LocalDateTime.class)
    })
    List<SysLog> querySyslogByUsername(String username);
}
  1. 在服务层或其他地方使用的地方注入指定dao
@Service("studentService")
public class StudentServiceImpl implements StudentService {

    // 注入主数据源配置的dao层对象
    @Autowired
    private StudentDao studentDao;

    @Override
    public int add(Student student) {
        return this.studentDao.add(student);
    }

    @Override
    public int update(Student student) {
        return this.studentDao.update(student);
    }

    @Override
    public int deleteBysno(String sno) {
        return this.studentDao.deleteBysno(sno);
    }

    @Override
    public Student queryStudentBySno(String sno) {
        return this.studentDao.queryStudentBySno(sno);
    }
}

第二个数据源的使用同上,只需要在使用处注入即可

# 总结

配置多数据源还是比较简单的,关键点在于配置类能够正确读取到数据库连接配置,然后正确对不同数据源实现不同的配置类即可。