mul-table-query

本文项目链接:超级好用的多数据源,多表联查工具, 专注 java 原生语法,零硬编码,零 xml

基于 mybatis-plus的多数据源配置,多表联查工具

效果:不改写任何的 mapper 和 mapper.xml,轻松实现 crud

多数据源配置

  1. 多数据源使用了 mybatis、mybatis-plus 以及 druid,mybatis相关的配置在 IMybatisPlusConfig.java 中,只有数据源和 druid 的配置需要单独配置。

  2. 为了支持多数据源,使用了单独的数据源配置,前缀为system.jdbc.datasource, 见 MultiDatasourceProperties.java

     spring:datasource:# 使用alibaba的druid作为数据库连接池type: com.alibaba.druid.pool.DruidDataSourcedruid:# 连接池初始化连接数量initial-size: 5# 最小空闲连接数量min-idle: 5# 最大连接数量max-active: 20# 最大等待时间max-wait: 60000time-between-eviction-runs-millis: 60000# 单个连接在池中最小生存的时间,单位是毫秒min-evictable-idle-time-millis: 300000# 单个连接在池中最大生存的时间,单位是毫秒max-evictable-idle-time-millis: 900000# 以系统资源换稳定,连接空闲时检查有效性test-while-idle: true# 以系统资源换稳定,申请连接时检查有效性test-on-borrow: false# 以系统资源换稳定,回收连接时检查有效性test-on-return: false# 缓存statement,用本机内存换效率,但是通常可以关闭pool-prepared-statements: false# max-pool-prepared-statement-per-connection-size: 20# 监控过滤器web-stat-filter:enabled: trueexclusions:- "*.js"- "*.gif"- "*.jpg"- "*.png"- "*.css"- "*.ico"- "/druid/*"# druid 监控页面stat-view-servlet:enabled: trueurl-pattern: /druid/*reset-enable: falselogin-username: rootlogin-password: rootsystem:security:gateway-auth: truegateway-open: jdbc:datasource:filters: stat,wallcustomConfig: icu.helltab.fpi.pure.common.web.config.CustomJdbcConfigconnections:mysql:validationQuery: SELECT 1scanPackages: icu.helltab.fpi.pure.module.system.web.mapperdriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://172.16.40.153:3306/fpi-pure?allowMultiQueries=true&createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=trueusername: {pldd}password: {password}
  3. 使用数据源和设置事务管理,默认数据源只需要继承 DefaultBaseService.java ,事务管理默认也是添加好的

     @Servicepublic class UserService extends DefaultBaseService<UserMapper, UserInfo> {​}List<UserInfo> objects = userService.exList(sql -> {sql.select(UserInfo::getUsername).from(UserInfo.class);}, UserInfo.class);
  4. 自定义数据源配置修改钩子

    1. 在配置中指定钩子处理类

     system:jdbc:datasource:# 配置钩子处理类customConfig: icu.helltab.fpi.pure.common.web.config.CustomJdbcConfig
    1. 编写钩子处理类, 下面这个例子中,我们修改了数据配置中的元数据注入策略

      1. 继承 MultiDatasourceProperties.java ,这里主要调用 register 将钩子注册到数据源初始化的生命周期里面去

      2. 通过 MybatisConfiguration configuration = factory.getConfiguration(); 获取到配置,可以做自定义配置

      
      
      package icu.helltab.fpi.pure.common.web.config;​import cn.hutool.core.date.LocalDateTimeUtil;import com.baomidou.mybatisplus.core.MybatisConfiguration;import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;import icu.helltab.fpi.pure.common.web.config.security.HttpContextHolder;import icu.helltab.itool.multablequery.config.db.handler.MyMetaObjectHandler;import icu.helltab.itool.multablequery.config.db.multi.MultiDatasourceProperties;import org.apache.ibatis.reflection.MetaObject;import org.springframework.context.annotation.Configuration;import org.springframework.stereotype.Component;​import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest;​/*** @author Helltab* @mail helltab@163.com* @date 2023/4/18 13:45* @desc 这是数据源自定义配置的钩子, 在这里可以更改 mybatis 的 MybatisSqlSessionFactoryBean 配置* @see*/public class CustomJdbcConfig extends MultiDatasourceProperties {static  {// 注册数据源对应的回调函数, 可以修改 MybatisSqlSessionFactoryBean 的属性register("mysql", factory->{MybatisConfiguration configuration = factory.getConfiguration();GlobalConfigUtils.getGlobalConfig(configuration).setMetaObjectHandler(new CusMetaObjectHandler());});}​public static class CusMetaObjectHandler extends MyMetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {this.setFieldValByName("createBy", HttpContextHolder.getUserNo(), metaObject);this.setFieldValByName("updateBy", HttpContextHolder.getUserNo(), metaObject);super.insertFill(metaObject);}​​@Overridepublic void updateFill(MetaObject metaObject) {this.setFieldValByName("updateBy", HttpContextHolder.getUserNo(), metaObject);super.updateFill(metaObject);}}}​
  1. 新增数据源:

    1. 在配置文件中添加数据源,参见 ScanConfig.java

       jdbc:datasource:filters: stat,wallcustomConfig: icu.helltab.fpi.pure.common.web.config.CustomJdbcConfigconnections:other_db: # 这里添加新数据源validationQuery: SELECT 1scanPackages: icu.helltab.fpi.pure.module.system.web.mapperdriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://172.16.40.153:3306/fpi-pure?allowMultiQueries=true&createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=trueusername: {pldd}password: {password}
    1. 添加数据源操作基类,参考 DefaultBaseService.java , 该数据源的操作都需要集成这个类

       package icu.helltab.itool.multablequery.config.db.multi;​import javax.annotation.Resource;​import icu.helltab.itool.multablequery.config.db.CusBaseService;import org.springframework.transaction.annotation.Transactional;import com.baomidou.mybatisplus.core.mapper.BaseMapper;​/*** 多数据源示例* todo* 所有的该数据源的 service 都需要继承本 Service*/@Transactional(transactionManager = "这里需要替换: ${数据源名}_TM", rollbackFor = Throwable.class)public class DemoBaseServiceDontUseMe<M extends BaseMapper<T>, T> extends CusBaseService<M, T> {​/*** todo*/@Resource(name = "这里需要替换:${数据源名}_RUNNER")MySqlRunner mySqlRunner;​protected MySqlRunner getMySqlRunner() {return mySqlRunner;}}

多表联查工具的使用

Startup

  1. 配置完数据源之后,即可使用多表联查了,当然也可以直接使用 MySqlRunner 中的方法,为了统一,推荐继承相关数据源的 Service,使用提供的查询能力。

    1. 继承相关数据源 Service

       
      @Servicepublic class UserService extends DefaultBaseService<UserMapper, UserInfo> {​}List<UserInfo> objects = userService.exList(sql -> {sql.select(UserInfo::getUsername).from(UserInfo.class);}, UserInfo.class);
  1. 直接使用 MysqlRunner

    @Resource(name = DSConfig01.CONF.SQL_RUNNER)MySqlRunner mySqlRunner;​List<Map<String, Object>> maps = mySqlRunner.selectLambda(sql -> {sql.select(UserInfo::getUsername).from(UserInfo.class);});

API 说明

特别说明:因为 lambda 表达式的原理是推断表名,因此无法优雅的自定义某个表的别名:这里采取一个策略:别名自动生成,但是如果一个表在环境中出现两次以上,则需要指定其编号,如第一次出现的表是 0,第二次出现是 1,默认为 0;

select

// 单个字段查询
1. select(UserInfo::getUsername);
2. select(UserInfo::getUsername, q.Alias(1));
// 多个字段查询
1. select(UserInfo::getUsername, UserInfo::getPasswrod);//类型检测预警
2. select(UserInfo::getUsername).select(UserInfo::getPassword);
3. select(UserInfo::getUsrname, q.Alias(1)).select(UserInfo::getPasswrod,q.Alias(2));
//子查询
1. sql.select(inner->{inner.selectCount(UserInfo::getId, q.Alias(1)).from(UserInfo.class).eq(UserInfo::getUsername, "张三");}, UserInfo::getCount);
// 原始查询
1. sql.selectRaw("Ada username", "1 password");

from

// 多表 inner join
sql.from(UserInfo.class, UserInfo.class, UserInfo.class, UserInfo.class);
// 子查询
sql.from(inner->{sql.select(UserInfo::getUsername, 0).from(UserInfo.class);
});

join

// left, 第二个参数使用 lambda 来做条件设置
sql.leftJoin(RoleInfo.class, j -> {j.eq(RoleInfo::getId, UserInfo::getRoleId);})
// right full 类似

where

条件判断第一个参数前面可以添加一个 nullJudge 的布尔值,默认为 true

true: 如果值为空,则不添加判断条件;

false: 如果值不为空,则添加判断条件,如 eq 会变为 is null, neq 会变为 is not null

// eq
sql.eq(UserInfo::getUsername, "张三");
sql.neq(UserInfo::getUsername, "张三");
// 小于等于
sql.le(UserInfo::getAge, 20);
// 小于
sql.lt(UserInfo::getAge, 20);
// 大于等于
sql.ge(UserInfo::getAge, 20);
// 大于
sql.gt(UserInfo::getAge, 20);
sql.in(UserInfo::getAge, 20, 18);
sql.notIn(UserInfo::getAge, 20, 18);
sql.notIn(UserInfo::getAge, inner->inner.selectRaw("1"));
sql.exists(UserInfo::getAge, inner->inner.selectRaw("1"));
sql.like(UserInfo::getUsername, "尚");
sql.notLike(UserInfo::getAge, "尚");

group

sql.group(UserInfo::getId).group(UserInfo::getAge).group(UserInfo::getUsername);// having
sql.having(UserInfo::getUsername, "='张三'");

sort

// true 正序, false 倒序
sql.order(UserInfo::getAge, true);
sql.order(UserInfo::getAge, 0, true);

function

// select count(a.id) from user_info a;
sql.selectCount(UserInfo::getId).from(UserInfo.class);
sql.selectCount(UserInfo::getId, 0).from(UserInfo.class);// select sum(a.id) from user_info a;
sql.selectSum(UserInfo::getId).from(UserInfo.class);
sql.selectSum(UserInfo::getId, 0).from(UserInfo.class);// 使用 concat({}, {}) 表达式来申明函数原型
// 使用 .bind(UserInfo::getAge).bind(UserInfo::getUsername) 来绑定参数
sql.eq(false, sql.fun("concat({}, {})").bind(UserInfo::getAge).bind(UserInfo::getUsername), "23")

CusBaseService 的能力

CusBaseService.java

新增

save;
saveBatch;

修改

updateById;
updateByIdBatch;

新增或修改

saveOrUpdate;
saveOrUpdateBatch;

删除

remove;
removeById;
removeByIds;

查询

特别说明,分页返回结果为 HttpPagedInfo.java

包含 count 和 list 两个值

// 查询单个
getOne(sql->sql.select(UserInfo::getUsername));
// 查询数量getCount(sql->sql.eq(UserInfo::getUsername, "张三"));
// 查询是否存在has(sql->sql.eq(UserInfo::getUsername, "张三"));
// 查询列表list(sql->sql.eq(UserInfo::getUsername, "张三"));
// 查询分页, 默认接口传参 params: pageNum: 当前页数, pageSize: 分页大小(最大为 100)page(sql->sql.eq(UserInfo::getUsername, "张三"));// 多表联查能力, 需要指定 from 和返回值接收对象exOne(sql->sql.select(UserInfo::getUsername).from(UserInfo.class), UserInfoVo.class);
// 列表exList(sql->sql.select(UserInfo::getUsername).from(UserInfo.class), UserInfoVo.class);
// 分页exPage(sql->sql.select(UserInfo::getUsername).from(UserInfo.class), UserInfoVo.class);

零 XML 多表联查相关推荐

  1. 【mybatis】mybatis多表联查,存在一对多关系的,实体中使用List作为字段接收查询结果的写法...

    实体如下: IntegralGoods  积分商品 IntegralGoodsImg 积分商品图片 ShelfLog 积分商品自动上架记录 IntegralGoods :IntegralGoodsIm ...

  2. SSM多表联查,原来如此方便,快捷!!!

    SSM多表联查(注解/配置文件) 第一步:实体类 public class Contract {private Integer cid;private Integer lid;private Inte ...

  3. 使用mybatis进行四表联查

    文章目录 一.问题背景 二.实际问题 三.问题解决 四.sql语句与XML映射文件 五.测试 一.问题背景 先数据库有用户表user.角色表role.菜单表menu.功能表funs和角色菜单关系表ro ...

  4. 健康管理系统第六天(移动端开发之体检预约_经典五表联查_调用阿里云提供的短信服务进行短信验证码发送)

    一.移动端开发 1.移动端开发方式 随着移动互联网的兴起和手机的普及,目前移动端应用变得愈发重要,成为了各个商家的必争之地.例如,我们可以使用手机购物.支付.打车.玩游戏.订酒店.购票等, 以前只能通 ...

  5. MySQL单表查询与多表联查

    1. 创建表 数据表的每行称为一条记录(record):每一列称为一个字段(field)[列之间以英文逗号隔开]. 简单语法:在当前数据库中创建一张表CREATE TABLE 表名(列名 列数据类型, ...

  6. 关于Mybatis-plus多表联查自定义sql分页查询

    问题描述: 使用mybatis-plus进行开发过程中,单表得增删改查等都可以利用封装好的方法,而一些场景设计多表联合查询,且需要自定义字段的,就需要进行自定义sql 使用方法: 1.service中 ...

  7. MyBatis如何实现多表联查

    目录 一.什么是级联 二.实现多表联查的方式 方式一:通过xml配置文件 1.一对一级联步骤 2.一对多联步骤 方式二:使用映射器注解方式 1.一对一映射 2.一对多映射 三.级联的缺陷 一.什么是级 ...

  8. Mybatis多表联查简简单单

    Mybatis多表联查 1.一对一关系`association` 2.一对多关系`collection` 3.多对多关系 Mybatis中实现了对数据库中的数据进行封装,那么进行多表查询时就会遇到查询 ...

  9. 数据库多表查询 myBatis四表联查

    查询目标 user表 role表 角色和菜单的关系 menu表 funs表(功能) 表和表的关系 1.user对role 是多对一role对user是一对多即一个user对应一个role 一个role ...

最新文章

  1. 信息资源管理的标准与法规
  2. OpenBSD 6.0 将移除 Linux 子系统以改进安全
  3. Nginx出现这么几个500怎么解决?
  4. Django,Ajax,文件上传,ajax发送json数据,基于Ajax的文件上传
  5. angularjs与PHP,我应该混合AngularJS与PHP框架吗?
  6. SAP CDS view的文本格式的源代码是如何被ABAP后台解析的
  7. 记一次转不过弯的递归
  8. vb.net编写函数应该在哪里_编写代码时清晰至上
  9. 探讨微软团队开发利器VSTS安装及部署篇
  10. JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(三):两个Viewmodel搞定增删改查
  11. Directed Minimum Spanning Tree: Chu-Liu/Edmonds Algorithm
  12. [转]HTTP消息格式
  13. 最小割最大流算法matlab,matlab练习程序(最大流/最小割)
  14. 计算机求百钱买百鸡问题采用,5.5 百钱买百鸡问题
  15. QFD质量机能展开,了解一下呀!
  16. 青春使命网页制作html,青春的使命初中作文
  17. 交易原则Jesse Livermore 杰西·利弗莫尔
  18. USB摄像头测试网址
  19. swap()函数实现变量值的交换
  20. 计算机基础三: 二进制减法实现

热门文章

  1. Linux定时任务与开机自启动脚本
  2. mysql常用汉字库_MYSQL 常用总结【基础】
  3. cocos creator 3D | 拇指投篮 | 3D项目入门实战
  4. [原创] 在MFC中大家都习惯用CStdioFile来处理文本文件,可是为什么CStdioFile不叫CTextFile?
  5. 关闭浏览器后退出登录_升级后的相互宝要不要退出?相互宝怎么关闭?
  6. 云服务商将占据 80% CDN 市场份额,传统CDN或将终结
  7. 软件测试面试要注意的细节以及处理(自我介绍篇)
  8. 树莓派3B+如何完成对产品的升级改造
  9. Scrapy第十五篇:后起之秀-Playwright
  10. 人工智能会话代理在医疗保健中的有效性:系统综述