下面案例源码可参考:

  1. springboot-dydamic-datasources分包方式实现多数据源
  2. springboot-dydamic-datasources自定义注解实现多数据源

    1.为什么微服务还要使用多数据源

    :::tips 我们知道面对微服务化的拆分,我们希望一个微服务能做到小而精(做到只干一件事,比如账单服务,库存服务)。但是有些时候拆分不是很测地,需要在一个微服务项目中使用多数据源的情形(eg:如果满足a条件入a库,满足b条件入b库)。基于此,这里简单采用springboot分包方式实现多数据源。仅供参考。 :::

    2.分包方式实现多数据源切换

    2.1 项目目录结构

    我们在进行分包的方式来实现多数据源的动态切换,重点就是分包。项目分包如下:
    1. ├─src
    2. ├─main
    3. ├─java
    4. └─com
    5. └─itmck
    6. ├─config 多数据源配置包
    7. ├─dao
    8. ├─master 主数据源mapper
    9. └─slave 从数据源mapper
    10. ├─entity 实体
    11. └─service 接口
    12. └─resources
    13. └─mapper
    14. ├─master 主数据源mapper.xml
    15. └─slave 从数据源mapper.xml
    16. └─test

    2.2 数据源配置清单

    ```yaml spring: datasource: master: url: jdbc:mysql://localhost:3306/spring_db?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8 driver-class-name: com.mysql.cj.jdbc.Driver username: root password: 123456 slave: url: jdbc:mysql://localhost:3306/spring_db2?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8 driver-class-name: com.mysql.cj.jdbc.Driver username: root password: 123456 type: com.zaxxer.hikari.HikariDataSource hikari: connection-timeout: 30000 idle-timeout: 30000 auto-commit: ‘true’ minimum-idle: 5 maximum-pool-size: 15 pool-name: HikariCP connection-test-query: SELECT 1 FROM DUAL max-lifetime: 1800000

mybatis-plus: mapper-locations: ‘classpath:mapper//*Mapper.xml’ type-aliases-package: com.itmck.entity configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

  1. <a name="PLVX3"></a>
  2. ## 2.3 master数据源
  3. :::info
  4. @MapperScan(basePackages = "com.itmck.dao.master", sqlSessionTemplateRef = "primarySqlSessionTemplate")<br />basePackages代表要扫描的mapper接口,这是分包切换数据源的关键
  5. :::
  6. ```java
  7. package com.itmck.filterconfig;
  8. import com.baomidou.mybatisplus.core.MybatisConfiguration;
  9. import com.baomidou.mybatisplus.core.config.GlobalConfig;
  10. import com.baomidou.mybatisplus.extension.incrementer.OracleKeyGenerator;
  11. import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
  12. import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
  13. import com.zaxxer.hikari.HikariDataSource;
  14. import lombok.extern.slf4j.Slf4j;
  15. import org.apache.ibatis.session.SqlSessionFactory;
  16. import org.mybatis.spring.SqlSessionTemplate;
  17. import org.mybatis.spring.annotation.MapperScan;
  18. import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
  19. import org.springframework.boot.context.properties.ConfigurationProperties;
  20. import org.springframework.context.annotation.Bean;
  21. import org.springframework.context.annotation.Configuration;
  22. import org.springframework.context.annotation.Primary;
  23. import org.springframework.jdbc.datasource.DataSourceTransactionManager;
  24. import javax.sql.DataSource;
  25. /**
  26. * 太阳当空照,花儿对我笑
  27. * <p>
  28. * Create by M ChangKe 2021/11/17 15:07
  29. **/
  30. @Slf4j
  31. @Configuration
  32. @MapperScan(basePackages = "com.itmck.dao.master", sqlSessionTemplateRef = "primarySqlSessionTemplate")
  33. public class PrimaryDataSourceConfig {
  34. @Bean
  35. @ConfigurationProperties(prefix = "spring.datasource.master")
  36. public DataSourceProperties primaryDataSourceProperties() {
  37. return new DataSourceProperties();
  38. }
  39. @Bean
  40. @Primary
  41. public DataSource primaryDateSource() {
  42. return primaryDataSourceProperties()
  43. .initializeDataSourceBuilder()
  44. .type(HikariDataSource.class)
  45. .build();
  46. }
  47. @Bean
  48. @Primary
  49. public SqlSessionFactory primarySqlSessionFactory() throws Exception {
  50. MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
  51. mybatisSqlSessionFactoryBean.setPlugins(new PaginationInterceptor());
  52. mybatisSqlSessionFactoryBean.setDataSource(primaryDateSource());
  53. // mybatisSqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/master/*.xml"));
  54. // mybatisSqlSessionFactoryBean.setConfiguration(this.mybatisConfiguration());//解决oracle下不能使用sequence问题
  55. return mybatisSqlSessionFactoryBean.getObject();
  56. }
  57. private MybatisConfiguration mybatisConfiguration() {
  58. GlobalConfig globalConfig = new GlobalConfig();
  59. GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig().setKeyGenerator(new OracleKeyGenerator());
  60. globalConfig.setDbConfig(dbConfig);
  61. MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
  62. mybatisConfiguration.setGlobalConfig(globalConfig);
  63. return mybatisConfiguration;
  64. }
  65. @Bean
  66. @Primary
  67. public DataSourceTransactionManager primaryDataSourceTransactionManager() {
  68. return new DataSourceTransactionManager(primaryDateSource());
  69. }
  70. @Bean
  71. @Primary
  72. public SqlSessionTemplate primarySqlSessionTemplate() throws Exception {
  73. return new SqlSessionTemplate(primarySqlSessionFactory());
  74. }
  75. }

2.4 slave数据源

:::info @MapperScan(basePackages = “com.itmck.dao.slave”,sqlSessionTemplateRef = “slaveSqlSessionTemplate”)
basePackages代表要扫描的mapper接口,这是分包切换数据源的关键 :::

  1. package com.itmck.filterconfig;
  2. import com.baomidou.mybatisplus.core.MybatisConfiguration;
  3. import com.baomidou.mybatisplus.core.config.GlobalConfig;
  4. import com.baomidou.mybatisplus.extension.incrementer.OracleKeyGenerator;
  5. import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
  6. import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
  7. import com.zaxxer.hikari.HikariDataSource;
  8. import lombok.extern.slf4j.Slf4j;
  9. import org.apache.ibatis.session.SqlSessionFactory;
  10. import org.mybatis.spring.SqlSessionTemplate;
  11. import org.mybatis.spring.annotation.MapperScan;
  12. import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
  13. import org.springframework.boot.context.properties.ConfigurationProperties;
  14. import org.springframework.context.annotation.Bean;
  15. import org.springframework.context.annotation.Configuration;
  16. import org.springframework.jdbc.datasource.DataSourceTransactionManager;
  17. import javax.sql.DataSource;
  18. /**
  19. * 太阳当空照,花儿对我笑
  20. * <p>
  21. * Create by M ChangKe 2021/11/17 15:07
  22. * <p>
  23. * 从数据源
  24. **/
  25. @Slf4j
  26. @Configuration
  27. @MapperScan(basePackages = "com.itmck.dao.slave",sqlSessionTemplateRef = "slaveSqlSessionTemplate")
  28. public class SlaveDataSourceConfig {
  29. @Bean
  30. @ConfigurationProperties(prefix = "spring.datasource.slave")
  31. public DataSourceProperties slaveDataSourceProperties() {
  32. return new DataSourceProperties();
  33. }
  34. @Bean
  35. public DataSource slaveDateSource() {
  36. return slaveDataSourceProperties()
  37. .initializeDataSourceBuilder()
  38. .type(HikariDataSource.class)
  39. .build();
  40. }
  41. @Bean
  42. public SqlSessionFactory slaveSqlSessionFactory() throws Exception {
  43. MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
  44. mybatisSqlSessionFactoryBean.setPlugins(new PaginationInterceptor());
  45. mybatisSqlSessionFactoryBean.setDataSource(slaveDateSource());
  46. // mybatisSqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/slave/*.xml"));
  47. // mybatisSqlSessionFactoryBean.setConfiguration(this.mybatisConfiguration());//解决oracle下不能使用sequence问题
  48. return mybatisSqlSessionFactoryBean.getObject();
  49. }
  50. private MybatisConfiguration mybatisConfiguration() {
  51. GlobalConfig globalConfig = new GlobalConfig();
  52. GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig().setKeyGenerator(new OracleKeyGenerator());
  53. globalConfig.setDbConfig(dbConfig);
  54. MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
  55. mybatisConfiguration.setGlobalConfig(globalConfig);
  56. return mybatisConfiguration;
  57. }
  58. @Bean
  59. public DataSourceTransactionManager slaveDataSourceTransactionManager() {
  60. return new DataSourceTransactionManager(slaveDateSource());
  61. }
  62. @Bean
  63. public SqlSessionTemplate slaveSqlSessionTemplate() throws Exception {
  64. return new SqlSessionTemplate(slaveSqlSessionFactory());
  65. }
  66. }

2.5 启动类 :::tips 启动类上exclude排除默认的数据源自动装配配置类。否则会出现无法确认数据源的错误。 :::

  1. package com.itmck;
  2. import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  6. import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
  7. import org.springframework.transaction.annotation.EnableTransactionManagement;
  8. /**
  9. * 太阳当空照,花儿对我笑
  10. * <p>
  11. * Create by M ChangKe 2021/11/17 15:03
  12. **/
  13. @SpringBootApplication(
  14. //排除默认的数据源自动装配配置类
  15. exclude = {
  16. DataSourceAutoConfiguration.class,
  17. DataSourceTransactionManagerAutoConfiguration.class,
  18. MybatisPlusAutoConfiguration.class
  19. }
  20. )
  21. @EnableTransactionManagement
  22. public class SpringbootMultipartDataSourcesApplication {
  23. public static void main(String[] args) {
  24. SpringApplication.run(SpringbootMultipartDataSourcesApplication.class, args);
  25. }
  26. }

3.自定义注解方式实现多数据源

:::tips 使用多数据源也可以完成的.这里简单自定义注解实现多数据源切换.
场景:针对动态数据源的切换操作可以扩展成读写分离.举例:如果读写分离可以使用中间件mycat. :::

3.1 项目目录结构

  1. ├─src
  2. ├─main
  3. ├─java
  4. └─com
  5. └─itmck
  6. ├─annotation 自定义数据源切换注解
  7. ├─config 切面以及配置类
  8. ├─dao
  9. ├─entity
  10. ├─enums
  11. ├─handler
  12. └─service
  13. └─resources
  14. └─test
  15. └─java
  16. └─com
  17. └─itmck
  18. └─service

3.2 项目所需依赖

  1. <dependency>
  2. <groupId>mysql</groupId>
  3. <artifactId>mysql-connector-java</artifactId>
  4. <scope>runtime</scope>
  5. </dependency>
  6. <dependency>
  7. <groupId>com.baomidou</groupId>
  8. <artifactId>mybatis-plus-boot-starter</artifactId>
  9. <version>3.2.0</version>
  10. </dependency>
  11. <!--这里引入aop目的自定义注解实现切面-->
  12. <dependency>
  13. <groupId>org.springframework.boot</groupId>
  14. <artifactId>spring-boot-starter-aop</artifactId>
  15. </dependency>

3.3 application.yml配置

:::tips 注意: url改成 jdbc-url 否则报错: jdbcUrl is required with driverClassName 原文链接:解决方案 :::

  1. server:
  2. port: 8080
  3. spring:
  4. datasource:
  5. master:
  6. #这里url必须改为:jdbc-url 用来重写自定义连接池
  7. jdbc-url: jdbc:mysql://localhost:3306/spring_db?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
  8. driver-class-name: com.mysql.cj.jdbc.Driver
  9. username: root
  10. password: 123456
  11. slave:
  12. jdbc-url: jdbc:mysql://localhost:3306/spring_db2?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
  13. driver-class-name: com.mysql.cj.jdbc.Driver
  14. username: root
  15. password: 123456
  16. type: com.zaxxer.hikari.HikariDataSource
  17. hikari:
  18. connection-timeout: 30000
  19. idle-timeout: 30000
  20. auto-commit: 'true'
  21. minimum-idle: 5
  22. maximum-pool-size: 15
  23. pool-name: HikariCP
  24. connection-test-query: SELECT 1 FROM DUAL
  25. max-lifetime: 1800000
  26. mybatis-plus:
  27. mapper-locations: 'classpath*:mapper/*/*Mapper.xml'
  28. type-aliases-package: com.itmck.entity
  29. configuration:
  30. log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3.4 自定义注解

  1. package com.itmck.annotation;
  2. import com.itmck.enums.DataSourceType;
  3. import java.lang.annotation.*;
  4. /**
  5. * 自定义多数据源切换注解
  6. *
  7. * @author miaochangke
  8. */
  9. @Target({ElementType.METHOD,ElementType.TYPE})
  10. @Retention(RetentionPolicy.RUNTIME)
  11. @Documented
  12. public @interface Ds
  13. {
  14. /**
  15. * 切换数据源名称
  16. */
  17. public DataSourceType value() default DataSourceType.MASTER;
  18. }
  1. package com.itmck.enums;
  2. /**
  3. * 太阳当空照,花儿对我笑
  4. * <p>
  5. * Create by M ChangKe 2021/11/22 14:28
  6. * <p>
  7. * 定义数据源枚举
  8. **/
  9. public enum DataSourceType {
  10. /**
  11. * 主库
  12. */
  13. MASTER,
  14. /**
  15. * 从库
  16. */
  17. SLAVE
  18. }

3.5 自定义DynamicDataSourceContextHolder

:::tips 用来管理线程变量,根据线程进行数据源切换 :::

  1. package com.itmck.handler;
  2. import lombok.extern.slf4j.Slf4j;
  3. /**
  4. * 太阳当空照,花儿对我笑
  5. * <p>
  6. * Create by M ChangKe 2021/11/22 14:31
  7. **/
  8. @Slf4j
  9. public class DynamicDataSourceContextHolder {
  10. /**
  11. * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
  12. * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
  13. */
  14. private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
  15. /**
  16. * 设置数据源的变量
  17. */
  18. public static void setDateSourceType(String dsType) {
  19. log.info("切换到{}数据源", dsType);
  20. CONTEXT_HOLDER.set(dsType);
  21. }
  22. /**
  23. * 获得数据源的变量
  24. */
  25. public static String getDateSourceType() {
  26. return CONTEXT_HOLDER.get();
  27. }
  28. /**
  29. * 清空数据源变量
  30. */
  31. public static void clearDateSourceType() {
  32. CONTEXT_HOLDER.remove();
  33. }
  34. }

3.6 自定义DynamicDataSource

:::tips 通过自定义DynamicDataSource extends AbstractRoutingDataSource 重写determineCurrentLookupKey()来选择当前线程对应数据源 :::

  1. package com.itmck.handler;
  2. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
  3. import javax.sql.DataSource;
  4. import java.util.Map;
  5. /**
  6. * 太阳当空照,花儿对我笑
  7. * <p>
  8. * Create by M ChangKe 2021/11/22 14:37
  9. * <p>
  10. * 动态数据源
  11. **/
  12. public class DynamicDataSource extends AbstractRoutingDataSource {
  13. public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
  14. super.setDefaultTargetDataSource(defaultTargetDataSource);//设置默认数据源
  15. super.setTargetDataSources(targetDataSources);//设置目标数据源
  16. super.afterPropertiesSet();
  17. }
  18. @Override
  19. protected Object determineCurrentLookupKey() {
  20. return DynamicDataSourceContextHolder.getDateSourceType();//选择数据源
  21. }
  22. }

3.7 创建DynamicDataSourceConfig

:::tips 初始化扫描数据源 :::

  1. package com.itmck.filterconfig;
  2. import com.itmck.enums.DataSourceType;
  3. import com.itmck.handler.DynamicDataSource;
  4. import com.zaxxer.hikari.HikariDataSource;
  5. import org.mybatis.spring.annotation.MapperScan;
  6. import org.springframework.boot.context.properties.ConfigurationProperties;
  7. import org.springframework.boot.jdbc.DataSourceBuilder;
  8. import org.springframework.context.annotation.Bean;
  9. import org.springframework.context.annotation.Configuration;
  10. import org.springframework.context.annotation.Primary;
  11. import javax.sql.DataSource;
  12. import java.util.HashMap;
  13. import java.util.Map;
  14. /**
  15. * 太阳当空照,花儿对我笑
  16. * <p>
  17. * Create by M ChangKe 2021/11/22 14:43
  18. **/
  19. @Configuration
  20. @MapperScan("com.itmck.dao")
  21. public class DynamicDataSourceConfig {
  22. @Bean
  23. @ConfigurationProperties(prefix = "spring.datasource.master")
  24. public DataSource primaryDateSource() {
  25. return DataSourceBuilder.create()
  26. .type(HikariDataSource.class)
  27. .build();
  28. }
  29. @Bean
  30. @ConfigurationProperties(prefix = "spring.datasource.slave")
  31. public DataSource slaveDateSource() {
  32. return DataSourceBuilder.create()
  33. .type(HikariDataSource.class)
  34. .build();
  35. }
  36. @Bean(name = "dynamicDataSource")
  37. @Primary
  38. public DynamicDataSource dataSource() {
  39. Map<Object, Object> targetDataSources = new HashMap<>();
  40. targetDataSources.put(DataSourceType.MASTER.name(), primaryDateSource());
  41. targetDataSources.put(DataSourceType.SLAVE.name(), slaveDateSource());
  42. return new DynamicDataSource(primaryDateSource(), targetDataSources);
  43. }
  44. }

3.8 创建切面

使用切面针对使用了注解@Ds的方法进行数据源的切换

  1. package com.itmck.filterconfig;
  2. import com.itmck.annotation.Ds;
  3. import com.itmck.handler.DynamicDataSourceContextHolder;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.aspectj.lang.ProceedingJoinPoint;
  6. import org.aspectj.lang.annotation.Around;
  7. import org.aspectj.lang.annotation.Aspect;
  8. import org.aspectj.lang.annotation.Pointcut;
  9. import org.aspectj.lang.reflect.MethodSignature;
  10. import org.springframework.core.annotation.Order;
  11. import org.springframework.stereotype.Component;
  12. import java.lang.reflect.Method;
  13. /**
  14. * 太阳当空照,花儿对我笑
  15. * <p>
  16. * Create by M ChangKe 2021/11/22 14:39
  17. **/
  18. @Slf4j
  19. @Aspect
  20. @Order(1)
  21. @Component
  22. public class DataSourceAspect {
  23. @Pointcut("@annotation(com.itmck.annotation.Ds)")
  24. public void dsPointCut() {
  25. }
  26. @Around("dsPointCut()")
  27. public Object around(ProceedingJoinPoint point) throws Throwable {
  28. MethodSignature signature = (MethodSignature) point.getSignature();
  29. Method method = signature.getMethod();
  30. Ds ds = method.getAnnotation(Ds.class);
  31. if (null != ds) {
  32. DynamicDataSourceContextHolder.setDateSourceType(ds.value().name());
  33. }
  34. try {
  35. return point.proceed();
  36. } finally {
  37. // 销毁数据源 在执行方法之后
  38. DynamicDataSourceContextHolder.clearDateSourceType();
  39. }
  40. }
  41. }

3.9 注解使用

:::tips 参考DsChangeImpl#getStudentList() 切换数据源: @Ds(value = DataSourceType.SLAVE) :::

  1. package com.itmck.service;
  2. import com.baomidou.mybatisplus.extension.service.additional.query.impl.LambdaQueryChainWrapper;
  3. import com.itmck.annotation.Ds;
  4. import com.itmck.dao.StudentMapper;
  5. import com.itmck.dao.UserMapper;
  6. import com.itmck.entity.Student;
  7. import com.itmck.entity.User;
  8. import com.itmck.enums.DataSourceType;
  9. import org.springframework.stereotype.Service;
  10. import javax.annotation.Resource;
  11. import java.util.List;
  12. /**
  13. * 太阳当空照,花儿对我笑
  14. * <p>
  15. * Create by M ChangKe 2021/11/17 15:49
  16. **/
  17. @Service
  18. public class DsChangeImpl implements DsChange {
  19. @Resource
  20. private UserMapper userMapper;
  21. @Resource
  22. private StudentMapper studentMapper;
  23. //使用默认数据源
  24. @Override
  25. public List<User> getUserList() {
  26. return new LambdaQueryChainWrapper<>(userMapper).list();
  27. }
  28. //使用从数据源
  29. @Override
  30. @Ds(value = DataSourceType.SLAVE)
  31. public List<Student> getStudentList() {
  32. return new LambdaQueryChainWrapper<>(studentMapper).list();
  33. }
  34. }

3.10 启动类排除数据源自动注册

:::tips @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) 排除数据源自动配置类 :::

  1. package com.itmck;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  5. import org.springframework.transaction.annotation.EnableTransactionManagement;
  6. /**
  7. * 太阳当空照,花儿对我笑
  8. * <p>
  9. * Create by M ChangKe 2021/11/17 15:03
  10. **/
  11. //@Import(DynamicDataSourceConfig.class)
  12. @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
  13. @EnableTransactionManagement
  14. public class SpringbootDynamicDataSourcesApplication {
  15. public static void main(String[] args) {
  16. SpringApplication.run(SpringbootDynamicDataSourcesApplication.class, args);
  17. }
  18. }

3.11 测试

  1. package com.itmck.service;
  2. import com.itmck.entity.Student;
  3. import com.itmck.entity.User;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.junit.Test;
  6. import org.junit.runner.RunWith;
  7. import org.springframework.boot.test.context.SpringBootTest;
  8. import org.springframework.test.context.junit4.SpringRunner;
  9. import javax.annotation.Resource;
  10. import java.util.List;
  11. /**
  12. * 太阳当空照,花儿对我笑
  13. * <p>
  14. * Create by M ChangKe 2021/11/17 15:49
  15. **/
  16. @Slf4j
  17. @RunWith(SpringRunner.class)
  18. @SpringBootTest
  19. public class DsChangeImplTest {
  20. @Resource
  21. private DsChange dsChange;
  22. @Test
  23. public void userMapper() {
  24. List<User> list = dsChange.getUserList();
  25. log.info("list:{}", list);
  26. }
  27. @Test
  28. public void studentMapper() {
  29. List<Student> list = dsChange.getStudentList();
  30. log.info("list:{}", list);
  31. }
  32. }

分别输出:

==> Preparing: SELECT id,name,email,age FROM user ==> Parameters: <== Columns: id, name, email, age <== Row: 1, mck, 1735580535, 26 <== Total: 1 list:[User(id=1, name=mck, age=26, email=1735580535)]

==> Preparing: SELECT id,name,age FROM student ==> Parameters: <== Columns: id, name, age <== Row: 1, wxp, 25 <== Total: 1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@51b01550] list:[Student(id=1, name=wxp, age=25)]