SpringBoot(十二)MyBatisPlus的多数据源和分页
为什么需要多数据源
同一个项目有时会涉及到多个数据库,这时我们就要配置多个数据源。配置多数据源的常见情况有以下两种:
1)同一个项目中涉及两个或多个业务数据库,它们之间相互独立,这种情况也可以作为两个或多个项目来开发
2)两个或多个数据库之间是主从关系,主库负责写,从库负责读 多数据源的配置
1、pom.xml配置
在pom.xml中增加MyBatis-Plus多数据源依赖: com.baomidou dynamic-datasource-spring-boot-starter 3.2.1
2、配置文件配置
在配置文件application.yml中配置我们需要连接的数据库:blog和user,默认为blog spring: datasource: dynamic: # 设置默认数据源 primary: blog # 设置严格模式,false为不启动,启动后在未匹配到指定数据源时会抛出异常,不启动则使用默认数据源 strict: false datasource: blog: url: jdbc:mysql://localhost:3306/blog username: root password: 123456 type: com.alibaba.druid.pool.DruidDataSource druid: initialSize: 5 minIdle: 5 maxActive: 20 maxWait: 2000 validationQuery: select "x" testOnBorrow: false testOnReturn: false testWhileIdle: true user: url: jdbc:mysql://localhost:3306/user username: root password: 123456 type: com.alibaba.druid.pool.DruidDataSource druid: initialSize: 5 minIdle: 5 maxActive: 20 maxWait: 2000 validationQuery: select "x" testOnBorrow: false testOnReturn: false testWhileIdle: true mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3、启动类配置
在@SpringBootApplication注解上增加exclude = DruidDataSourceAutoConfigure.class配置: @SpringBootApplication(scanBasePackages = "com.tn222.springboot.article12.**", exclude = DruidDataSourceAutoConfigure.class) @MapperScan(basePackages = "com.tn222.springboot.article12.dao") public class Article12Application { public static void main(String[] args) { SpringApplication.run(Article12Application.class, args); } }
这个配置的作用是去掉对DruidDataSourceAutoConfigure的自动配置,否则程序会报错: Failed to configure a DataSource: "url" attribute is not specified and no embedded datasource could be configured. Reason: Failed to determine a suitable driver class
原因:
DruidDataSourceAutoConfigure在DynamicDataSourceAutoConfiguration之前,其会注入一个DataSourceWrapper,会在原生的spring.datasource下找url, username, password等,而我们动态数据源的配置路径是变化的。
4、实体类和dao层配置
在po文件夹下创建blog和user文件夹,分别用于存储blog数据库和user数据库的实体: @TableName(value = "article") public class ArticlePo { @TableId(type = IdType.AUTO) private Integer id; private String articleId; private String title; // get、set... } @TableName(value = "user_info") public class UserInfoPo { @TableId(type = IdType.AUTO) private Integer id; private String userId; private String name; // get、set... }
注解:
@TableName: 表名注解,标识实体类对应的表
@TableId: 主键注解,当type = IdType.AUTO时,表示这个主键是自增主键
在dao文件夹下创建blog和user文件夹,分别用于存储blog和user的dao: @Repository public interface ArticleDao extends BaseMapper { } @Repository @DS("user") public interface UserInfoDao extends BaseMapper { }
注解:
@Repository: 将数据访问层(DAO层)的类标识为Spring Bean
@DS: 配置非默认数据源,本示例中blog为默认数据源,user为非默认数据源,在使用@DS注解时,有如下注意事项:
1)不能使用事务,否则数据源不会切换,使用的还是第一次加载的数据源
2)第一次加载数据源之后,第二次,第三次……操作其他数据源,如果数据源不存在,使用的还是第一次加载的数据源
3)数据源名称不要包含下划线,否则不能切换
5、测试验证
编写ArticleController和UserInfoController: @RestController @RequestMapping("/article") public class ArticleController { @Resource private ArticleDao articleDao; @GetMapping(value = "/get") public ArticlePo get(@RequestParam("articleId") String articleId) { ArticlePo articlePo = articleDao.selectOne(Wrappers.lambdaQuery() .eq(ArticlePo::getArticleId, articleId)); return articlePo; } @PostMapping(value = "/insert") public Boolean insert(@RequestBody ArticlePo articlePo) { articleDao.insert(articlePo); Boolean res = false; if (articlePo.getId() > 0) { res = true; } return res; } } @RestController @RequestMapping("/user") public class UserInfoController { @Resource private UserInfoDao userInfoDao; @GetMapping(value = "/get") public UserInfoPo get(@RequestParam("userId") String userId) { UserInfoPo res = userInfoDao.selectOne(Wrappers.lambdaQuery().eq(UserInfoPo::getUserId, userId)); return res; } @PostMapping(value = "/insert") public Boolean insert(@RequestBody UserInfoPo userInfoPo) { userInfoDao.insert(userInfoPo); Boolean res = false; if (userInfoPo.getId() > 0) { res = true; } return res; } }
注 : 业务逻辑复杂时,Controller和Mapper中间会有Service层来处理业务逻辑,现在我们就简单的测试一下多数据源,所以直接使用Controller调用Mapper了 MyBatis-Plus的分页
1、配置分页插件 @Configuration @MapperScan("com.tn222.springboot.article12.dao") public class MybatisPlusConfig { /** * 分页插件 */ @Bean public PaginationInterceptor paginationInterceptor(){ return new PaginationInterceptor(); } }
2、分页方法
1)使用MyBatis-Plus的selectPage方法 @GetMapping("/listByLambda") public Object listByLambda(@RequestParam("title") String title, @RequestParam("pageIndex") Integer pageIndex, @RequestParam("pageSize") Integer pageSize) { IPage thisPage = new Page<>(pageIndex, pageSize); LambdaQueryWrapper eq = Wrappers.lambdaQuery() .eq(ArticlePo::getTitle, title).orderByDesc(ArticlePo::getId); thisPage = articleDao.selectPage(thisPage, eq); return thisPage; }
使用MyBatis-Plus的selectPage方法,返回了IPage,示例: { "records": [ { "id": 7, "articleId": "f68c5ccf9e3b4a719b369f9a84316635", "title": "Mybatis-Plus update" }, { "id": 2, "articleId": "1eabc4f8ce0711ec9b05979114b13a0f", "title": "Mybatis-Plus update" } ], "total": 3, "size": 2, "current": 1, "orders": [], "searchCount": true, "pages": 2 }
2)sql分页
有时候有些分页需要关联多张表,使用LambdaQueryWrapper不太方便,这时候可以自己写sql来实现分页,主要有两种:纯sql自己实现分页和使用IPage实现分页
注 : 这里的sql示例就使用单表查询了,具体的可根据业务场景使用多表查询
A、纯sql自己实现分页
分页的数据list和总条数单独调用方法返回 : @Select("select * from article where title=#{title} order by id desc limit #{offset}, #{pageSize}") List listByTitle(@Param("title") String title, @Param("offset") Integer offset, @Param("pageSize") Integer pageSize); @Select("select count(id) from article where title=#{title}") int countByTitle(@Param("title") String title);
B、使用IPage实现分页(常用) @Select("select * from article where title=#{title} order by id desc") IPage listByPage(IPage thisPage, @Param("title") String title);
返回IPage,返回值的数据结构见" 1)使用MyBatis-Plus的selectPage方法 "
本文简单介绍了一下MyBatis-Plus的多数据源和分页,本文示例代码, 详见https://gitee.com/tunan222/spring-boot-demo
若您觉得还可以,请帮忙点个 "赞" ,谢谢