码迷,mamicode.com
首页 > 其他好文 > 详细

Mybatis通用Join的实现(最终版)

时间:2020-09-17 12:36:23      阅读:36      评论:0      收藏:0      [点我收藏+]

标签:rtt   关联查询   分页查询   返回   intercept   des   自定义   inand   table   

你是否还在为mybatis的多表关联查询而写xml烦恼,是否还在为动态组装查询条件烦恼,是否还在为此没有合适的解决方案烦恼?

mybatis-extension插件,解决开发过程中需要多表关联时需手写xml的烦恼,同样支持通过传入sql返回结果集。
纯mybatis原生支持,轻量级无侵入,可用于辅助mybatis-plus、tk.mybatis或者mybatis-generator使用。

1.运行依赖:
* mybatis>=3.5.2
* jdk>=1.8

2.特性:
2.1. 支持多表自定义join关联查询
2.2. 支持自定义AND/OR混合条件,排序,分页等
2.3. 支持GROUPBY/HAVING聚合查询
2.4. 支持自定义sql查询
2.5. 所有的列名选择功能支持lambda写法和字符串输入两种方式
2.6. 自动判断表名、列名与实体类名、字段名对应,多表关联时自动给表名起别名
2.7. 内置多种mybatis generator常用插件,例如批量新增、分页等

3.性能:
比mybatis-generator性能提高约30%,甚至比navicat中直接执行查询还快,与其他插件的对比待测试。

4.不足:
不支持单表多次重复关联
不支持复杂的三层嵌套AND/OR
不支持多表UNION

5.最佳实践:
轻量级(jar包小于100KB)无其他依赖,可辅助其他mybatis插件使用,为解决JOIN关联为生,并持续提供各种特性

6.使用说明(springboot示例,代码在本文下方下载)

6.1pom.xml中引入mybatis-extension的依赖(目前未放到maven中央仓库,可参考下方本地引入或者放入离线仓库)

<dependency>
    <groupId>priv.rexsheng</groupId>
    <artifactId>mybatis-extension</artifactId>
    <version>1.0.0</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/src/main/resources/templates/mybatis-extension-1.0.0.jar</systemPath>
</dependency>

6.2 在启动类或者配置类上加入扫描mapper包

@MapperScan(basePackages = {"priv.rexsheng.mybatis.mapper"})

6.3配置mybatis拦截器

import priv.rexsheng.mybatis.interceptor.ResultTypeInterceptor;

@Configuration
public class InterceptorConfig {
    @Bean
    public ResultTypeInterceptor resultTypeInterceptor() {
        return new ResultTypeInterceptor();
    }
}

6.4正常使用mapper接口查询即可

import priv.rexsheng.mybatis.extension.TableQueryBuilder;
import priv.rexsheng.mybatis.mapper.DynamicMapper;
import priv.rexsheng.mybatis.test.dto.UserRoleQueryDto;
import priv.rexsheng.mybatis.test.entity.TUser;
import priv.rexsheng.mybatis.test.entity.UserRole;

@SpringBootTest
public class MapperTest {
    @Autowired
    private DynamicMapper dao;
    
    /**
     * 单表简单查询
     */
    @Test
    public void simpleSelect() {
        //定义要查询的表的构建器
        TableQueryBuilder<TUser> userQuery=TableQueryBuilder.from(TUser.class);
        //定义要查询的字段
        userQuery.select(TUser::getUserId,TUser::getUserName).and().like(TUser::getUserName, "%王二小%");
        //执行查询
        List<TUser> userList=dao.selectByBuilder(userQuery.build());
        log.info("用户列表:{}",userList);
    }
}

7. 各种查询使用说明

7.1单表查询

    @Test
    public void simpleUserList() {
        TableQueryBuilder<TUser> userQuery=TableQueryBuilder.from(TUser.class);
        //只查询user_id与user_name两个字段,
        userQuery.select(TUser::getUserId,TUser::getUserName)
        .where().gt(TUser::getUserId, 3)
        .or().isNotNull(TUser::getUpdateUser).isNotNull(TUser::getCreateTime);
        //按照创建时间倒序取前10条
        userQuery.orderByDesc(TUser::getCreateTime).take(10);
        List<TUser> userList=dao.selectByBuilder(userQuery.build());
        logger.info("用户列表:{}",userList);
    }
2020-09-03 06:45:32.272 DEBUG 18496 --- [           main] p.r.m.m.D.selectByBuilder_TUser          : ==>  Preparing: SELECT user_id AS userId, user_name AS userName FROM t_user WHERE (user_id > ?) AND (update_user IS NOT NULL OR create_time IS NOT NULL) ORDER BY create_time DESC LIMIT ? 
2020-09-03 06:45:32.293 DEBUG 18496 --- [           main] p.r.m.m.D.selectByBuilder_TUser          : ==> Parameters: 3(Integer), 10(Integer)
2020-09-03 06:45:32.315 DEBUG 18496 --- [           main] p.r.m.m.D.selectByBuilder_TUser          : <==      Total: 10

7.2 单表分组聚合查询

    @Test
    public void simpleUserGroup() throws ParseException {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        Date minDate=sdf.parse("2000-10-01");
        
        TableQueryBuilder<TUser> userQuery=TableQueryBuilder.from(TUser.class);
        //select create_user,max(create_time)
        userQuery.select(TUser::getCreateUser).selectMax(TUser::getCreateTime, "createTime")
        .where().gt(TUser::getUserId, 3);
        //group by create_user having count(*)>1 and min(create_time)>=‘2020-10-01 00:00:00‘
        userQuery.groupBy(TUser::getCreateUser).havingCount(a->a.gt("*", 1)).havingMin(a->a.gte(TUser::getCreateTime,minDate));
        List<TUser> userList=dao.selectByBuilder(userQuery.build());
        logger.info("用户列表:{}",userList);
    }    
2020-09-03 06:20:27.178 DEBUG 1280 --- [           main] p.r.m.m.D.selectByBuilder_TUser          : ==>  Preparing: SELECT create_user AS createUser, MAX(create_time) AS createTime FROM t_user WHERE (user_id > ?) GROUP BY create_user HAVING (COUNT(*) > ? AND MIN(create_time) >= ?) 
2020-09-03 06:20:27.204 DEBUG 1280 --- [           main] p.r.m.m.D.selectByBuilder_TUser          : ==> Parameters: 3(Integer), 1(Integer), 2000-10-01 00:00:00.0(Timestamp)
2020-09-03 06:20:27.242 DEBUG 1280 --- [           main] p.r.m.m.D.selectByBuilder_TUser          : <==      Total: 10
2020-09-03 06:20:27.250  INFO 1280 --- [           main] priv.rexsheng.mybatis.test.JoinTest      : 用户列表:[TUser [userId=null, userName=null, createTime=Mon Aug 31 15:37:59 CST 2020, createUser=5, updateTime=null, updateUser=null], TUser [userId=null, userName=null, createTime=Mon Aug 31 15:37:59 CST 2020, createUser=6, updateTime=null, updateUser=null], TUser [userId=null, userName=null, createTime=Mon Aug 31 15:37:59 CST 2020, createUser=7, updateTime=null, updateUser=null], TUser [userId=null, userName=null, createTime=Mon Aug 31 15:37:59 CST 2020, createUser=8, updateTime=null, updateUser=null], TUser [userId=null, userName=null, createTime=Mon Aug 31 15:37:59 CST 2020, createUser=9, updateTime=null, updateUser=null], TUser [userId=null, userName=null, createTime=Mon Aug 31 15:37:59 CST 2020, createUser=10, updateTime=null, updateUser=null], TUser [userId=null, userName=null, createTime=Mon Aug 31 15:37:59 CST 2020, createUser=1, updateTime=null, updateUser=null], TUser [userId=null, userName=null, createTime=Mon Aug 31 15:37:59 CST 2020, createUser=2, updateTime=null, updateUser=null], TUser [userId=null, userName=null, createTime=Mon Aug 31 15:37:59 CST 2020, createUser=3, updateTime=null, updateUser=null], TUser [userId=null, userName=null, createTime=Mon Aug 31 15:37:59 CST 2020, createUser=4, updateTime=null, updateUser=null]]

7.3单表分页查询并转换返回类型

    @Test
    public void simpleUserPageWithConvert() throws ParseException {
        TableQueryBuilder<TUser> userQuery=TableQueryBuilder.from(TUser.class);
        //查询第4页数据,并将查询的结果转换为实体类UserInfoDto
        userQuery.select(TUser::getUserId,TUser::getCreateTime)
        .selectAs(TUser::getUserName, "trueName")
        .page(4, 10);
        List<UserInfoDto> userPagedList=dao.selectByBuilder(userQuery.build(UserInfoDto.class));
        logger.info("用户列表:{}",userPagedList);
    }
2020-09-03 06:30:13.542 DEBUG 9944 --- [           main] p.r.m.m.D.selectByBuilder_UserInfoDto    : ==>  Preparing: SELECT user_id AS userId, create_time AS createTime, user_name AS trueName FROM t_user LIMIT ? OFFSET ? 
2020-09-03 06:30:13.565 DEBUG 9944 --- [           main] p.r.m.m.D.selectByBuilder_UserInfoDto    : ==> Parameters: 10(Integer), 30(Integer)
2020-09-03 06:30:13.587 DEBUG 9944 --- [           main] p.r.m.m.D.selectByBuilder_UserInfoDto    : <==      Total: 10
2020-09-03 06:30:13.596  INFO 9944 --- [           main] priv.rexsheng.mybatis.test.JoinTest      : 用户列表:[UserInfoDto [userId=31, trueName=用户31, createTime=2020-08-31T15:35:47], UserInfoDto [userId=32, trueName=用户32, createTime=2020-08-31T15:35:47], UserInfoDto [userId=33, trueName=用户33, createTime=2020-08-31T15:35:47], UserInfoDto [userId=34, trueName=用户34, createTime=2020-08-31T15:35:47], UserInfoDto [userId=35, trueName=用户35, createTime=2020-08-31T15:35:47], UserInfoDto [userId=36, trueName=用户36, createTime=2020-08-31T15:35:47], UserInfoDto [userId=37, trueName=用户37, createTime=2020-08-31T15:35:47], UserInfoDto [userId=38, trueName=用户38, createTime=2020-08-31T15:35:47], UserInfoDto [userId=39, trueName=用户39, createTime=2020-08-31T15:35:47], UserInfoDto [userId=40, trueName=用户40, createTime=2020-08-31T15:35:47]]
public class UserInfoDto {

    private Integer userId;
    
    private String trueName;
    
    private LocalDateTime createTime;
}

7.4多个表的关联查询

@Test
public void joinAndGroup() {
    long startTime=System.currentTimeMillis();
    TableQueryBuilder<TUser> userQuery=TableQueryBuilder.from(TUser.class);
    userQuery.selectAs(TUser::getCreateUser,"userId").selectCount("*","count")
    .groupBy(TUser::getCreateUser).havingCount(a->a.gt("*", 0)).havingMin(a->a.gte(TUser::getUserId, 1));
    userQuery.where().gt(TUser::getUserId, 3).or().isNotNull(TUser::getCreateTime).isNotNull(TUser::getCreateUser);
    
    TableQueryBuilder<TRole> roleQuery=TableQueryBuilder.from(TRole.class);
    roleQuery.selectMax(TRole::getRoleId, "roleId")
    .where().isNull(TRole::getUpdateTime).and().isNotNull(TRole::getCreateUser);
    roleQuery.groupBy(TRole::getRoleId).havingMax(a->a.gt(TRole::getRoleId, -1));
    
    TableQueryBuilder<UserRole> userRoleQuery=TableQueryBuilder.from(UserRole.class);
    userRoleQuery.and().isNotNull("user_id").isNotNull("role_id");
    userRoleQuery.leftJoin(roleQuery).on(UserRole::getRoleId, TRole::getRoleId);
    
    userQuery.orderByCount("*").leftJoin(userRoleQuery).on(TUser::getUserId, UserRole::getUserId);
    
    List<UserCountDto> userList=dao.selectByBuilder(userQuery.build(UserCountDto.class));
    long endTime=System.currentTimeMillis();
    logger.info("复杂聚合:{}ms,data:{}",endTime-startTime,userList);
    TestCase.assertNotNull(userList);
    TestCase.assertTrue(userList.size()>0);
    TestCase.assertNotNull(userList.get(0));
}
2020-09-03 06:45:52.626 DEBUG 8928 --- [           main] p.r.m.m.D.selectByBuilder_UserCountDto   : ==>  Preparing: SELECT a.create_user AS userId, COUNT(*) AS count, MAX(c.role_id) AS roleId FROM t_user AS a LEFT OUTER JOIN t_user_role AS b on a.user_id=b.user_id LEFT OUTER JOIN t_role AS c on b.role_id=c.role_id WHERE (a.user_id > ?) AND (a.create_time IS NOT NULL OR a.create_user IS NOT NULL) AND (b.user_id IS NOT NULL AND b.role_id IS NOT NULL) AND (c.update_time IS NULL) AND (c.create_user IS NOT NULL) GROUP BY a.create_user, c.role_id HAVING (COUNT(*) > ? AND MIN(a.user_id) >= ?) AND (MAX(c.role_id) > ?) ORDER BY COUNT(*) 
2020-09-03 06:45:52.627 DEBUG 8928 --- [           main] p.r.m.m.D.selectByBuilder_UserCountDto   : ==> Parameters: 3(Integer), 0(Integer), 1(Integer), -1(Integer)
2020-09-03 06:45:52.630 DEBUG 8928 --- [           main] p.r.m.m.D.selectByBuilder_UserCountDto   : <==      Total: 39
2020-09-03 06:45:52.631  INFO 8928 --- [           main] priv.rexsheng.mybatis.test.JoinTest      : 复杂聚合:6ms,data:[UserCountDto [userId=9, count=1, roleId=1], UserCountDto [userId=7, count=1, roleId=5], UserCountDto [userId=6, count=1, roleId=1], UserCountDto [userId=10, count=1, roleId=7], UserCountDto [userId=9, count=1, roleId=6], UserCountDto [userId=8, count=1, roleId=4], UserCountDto [userId=7, count=1, roleId=1], UserCountDto [userId=5, count=1, roleId=1], UserCountDto [userId=10, count=1, roleId=3], UserCountDto [userId=9, count=1, roleId=2], UserCountDto [userId=7, count=1, roleId=6], UserCountDto [userId=6, count=1, roleId=2], UserCountDto [userId=10, count=1, roleId=8], UserCountDto [userId=9, count=1, roleId=7], UserCountDto [userId=8, count=1, roleId=5], UserCountDto [userId=7, count=1, roleId=2], UserCountDto [userId=5, count=1, roleId=2], UserCountDto [userId=10, count=1, roleId=4], UserCountDto [userId=9, count=1, roleId=3], UserCountDto [userId=8, count=1, roleId=1], UserCountDto [userId=6, count=1, roleId=3], UserCountDto [userId=10, count=1, roleId=9], UserCountDto [userId=9, count=1, roleId=8], UserCountDto [userId=8, count=1, roleId=6], UserCountDto [userId=7, count=1, roleId=3], UserCountDto [userId=5, count=1, roleId=3], UserCountDto [userId=10, count=1, roleId=5], UserCountDto [userId=9, count=1, roleId=4], UserCountDto [userId=8, count=1, roleId=2], UserCountDto [userId=6, count=1, roleId=4], UserCountDto [userId=10, count=1, roleId=1], UserCountDto [userId=8, count=1, roleId=7], UserCountDto [userId=7, count=1, roleId=4], UserCountDto [userId=5, count=1, roleId=4], UserCountDto [userId=10, count=1, roleId=6], UserCountDto [userId=9, count=1, roleId=5], UserCountDto [userId=8, count=1, roleId=3], UserCountDto [userId=6, count=1, roleId=5], UserCountDto [userId=10, count=1, roleId=2]]

 

7.5 sql查询

@Test
public void testCountSql() {
    List<Long> countList = dao.selectBySql("Select Count(*) from t_user", Long.class);

    logger.info("countList:{}", countList);
    TestCase.assertNotNull(countList);
    TestCase.assertTrue(countList.get(0)>0);
    logger.info("countList.0:{}", countList.get(0));
}

@Test
public void testSelectSql() {
    List<TUser> userList = dao.selectBySql("Select user_id as userId,user_name as userName,create_time as createTime from t_user where user_id>10 limit 3", TUser.class);

    logger.info("userList:{}", userList);
    TestCase.assertNotNull(userList);
    TestCase.assertNotNull(userList.get(0).getCreateTime());
    logger.info("userList.0:{}", userList.get(0));
}
2020-09-03 06:52:33.860 DEBUG 20716 --- [           main] p.r.m.m.DynamicMapper.selectBySql_TUser  : ==>  Preparing: Select user_id as userId,user_name as userName,create_time as createTime from t_user where user_id>10 limit 3 
2020-09-03 06:52:33.884 DEBUG 20716 --- [           main] p.r.m.m.DynamicMapper.selectBySql_TUser  : ==> Parameters: 
2020-09-03 06:52:33.912 DEBUG 20716 --- [           main] p.r.m.m.DynamicMapper.selectBySql_TUser  : <==      Total: 3
2020-09-03 06:52:33.921  INFO 20716 --- [           main] priv.rexsheng.mybatis.test.SqlTest       : userList:[TUser [userId=11, userName=用户11, createTime=Mon Aug 31 15:35:47 CST 2020, createUser=null, updateTime=null, updateUser=null], TUser [userId=12, userName=用户12, createTime=Mon Aug 31 15:35:47 CST 2020, createUser=null, updateTime=null, updateUser=null], TUser [userId=13, userName=用户13, createTime=Mon Aug 31 15:35:47 CST 2020, createUser=null, updateTime=null, updateUser=null]]
2020-09-03 06:52:33.924  INFO 20716 --- [           main] priv.rexsheng.mybatis.test.SqlTest       : userList.0:TUser [userId=11, userName=用户11, createTime=Mon Aug 31 15:35:47 CST 2020, createUser=null, updateTime=null, updateUser=null]
2020-09-03 06:52:33.930 DEBUG 20716 --- [           main] p.r.m.m.DynamicMapper.selectBySql_Long   : ==>  Preparing: Select Count(*) from t_user 
2020-09-03 06:52:33.930 DEBUG 20716 --- [           main] p.r.m.m.DynamicMapper.selectBySql_Long   : ==> Parameters: 
2020-09-03 06:52:33.935 DEBUG 20716 --- [           main] p.r.m.m.DynamicMapper.selectBySql_Long   : <==      Total: 1
2020-09-03 06:52:33.936  INFO 20716 --- [           main] priv.rexsheng.mybatis.test.SqlTest       : countList:[10000]
2020-09-03 06:52:33.936  INFO 20716 --- [           main] priv.rexsheng.mybatis.test.SqlTest       : countList.0:10000

 7.6 实体类结构

public class TUser {
    private Integer userId;

    private String userName;

    private Date createTime;

    private Integer createUser;

    private Date updateTime;

    @ColumnName("update_user")
    private Integer updateUser;
}
    
public class TRole {
    private Integer roleId;

    private String roleName;

    private String roleRemark;
     
    private LocalDateTime createTime;

    private Integer createUser;

    private Date updateTime;

    private Integer updateUser;
}
    
@TableName("t_user_role")
public class UserRole {
    private Integer Id;

    private Integer userId;

    private Integer roleId;
}

public class UserInfoDto {

    private Integer userId;
    
    private String trueName;
    
    private LocalDateTime createTime;
}

public class UserCountDto {

    private Integer userId;
    
    private Long count;
    
    private Integer roleId;
}

 mybatis-extension-test.rar

Mybatis通用Join的实现(最终版)

标签:rtt   关联查询   分页查询   返回   intercept   des   自定义   inand   table   

原文地址:https://www.cnblogs.com/RexSheng/p/mybatis-extension.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!