MyBatis增强工具

363 阅读4分钟

MyBatis-Plus

官网:mp.baomidou.com/ 官方示例:github.com/baomidou/my…

对MyBatis 增强,简化单表SQL CRUD参考官网;

Chain(重要)

service的链式操作,这个是实际使用中会用的比较频繁的API,让我们在写代码时,调用API的操作更加的优雅;

API列表

// 链式查询 普通
QueryChainWrapper<T> query();
// 链式查询 lambda 式。注意:不支持 Kotlin
LambdaQueryChainWrapper<T> lambdaQuery(); 

// 链式更改 普通
UpdateChainWrapper<T> update();
// 链式更改 lambda 式。注意:不支持 Kotlin 
LambdaUpdateChainWrapper<T> lambdaUpdate();

测试代码

@SpringBootTest
@Slf4j
public class ChainTest {
    @Autowired
    UserInfoService userInfoService;

    @Test
    void chainQuery() {
        List<UserInfo> userInfos = userInfoService
                .query()
                .eq("user_name", "一行Java 1")
                .list();
        log.info("流式查询:{}", JSON.toJSONString(userInfos));
    }

    @Test
    void chainLambdaQuery() {
        List<UserInfo> userInfos = userInfoService
                .lambdaQuery()
                .eq(UserInfo::getUserName, "一行Java 1")
                .list();
        log.info("流式查询:{}", JSON.toJSONString(userInfos));
    }
}

MybatisX插件

MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。一键生成ORM代码;结合MyBatis Plus,生成的代码就已经具备了数据库增删改查的基本功能,直接去开发业务功能就好了;

1.IDEA配置数据源,选中表(支持多选),右键选择“MybatisX-Generator

2.配置基础信息

image.png

3.属性、方法配置

image.png

生成后的效果

image.png

MyBatis Plus Join

MyBatis Plus Join一款专门解决MyBatis Plus 关联查询问题的扩展框架,他并不一款全新的框架,而是基于MyBatis Plus功能的增强,所以MyBatis Plus的所有功能MyBatis Plus Join同样拥有;框架的使用方式和MyBatis Plus一样简单,几行代码就能实现联表查询的功能

官方仓库:gitee.com/best_handso…

官网:MyBatis-Plus-Join (mybatisplusjoin.com)

使用

基础MyBatis Plus代码生成,参考MyBatisX的插件使用

MyBatis Plus Join 核心类说明

  • MPJBaseMapper

    扩展了MyBatis Plus的 BaseMapper 接口

public interface MPJBaseMapper<T> extends BaseMapper<T> {
    Integer selectJoinCount(@Param("ew") MPJBaseJoin var1);

    <DTO> DTO selectJoinOne(@Param("resultTypeClass_Eg1sG") Class<DTO> var1, @Param("ew") MPJBaseJoin var2);

    Map<String, Object> selectJoinMap(@Param("ew") MPJBaseJoin var1);

    <DTO> List<DTO> selectJoinList(@Param("resultTypeClass_Eg1sG") Class<DTO> var1, @Param("ew") MPJBaseJoin var2);

    List<Map<String, Object>> selectJoinMaps(@Param("ew") MPJBaseJoin var1);

    <DTO, P extends IPage<?>> IPage<DTO> selectJoinPage(P var1, @Param("resultTypeClass_Eg1sG") Class<DTO> var2, @Param("ew") MPJBaseJoin var3);

    <P extends IPage<?>> IPage<Map<String, Object>> selectJoinMapsPage(P var1, @Param("ew") MPJBaseJoin var2);
}
  • MPJBaseService

    扩展了MyBatis Plus的 IService 接口

public interface MPJBaseService<T> extends IService<T> {
    Integer selectJoinCount(MPJBaseJoin var1);

    <DTO> DTO selectJoinOne(Class<DTO> var1, MPJBaseJoin var2);

    <DTO> List<DTO> selectJoinList(Class<DTO> var1, MPJBaseJoin var2);

    <DTO, P extends IPage<?>> IPage<DTO> selectJoinListPage(P var1, Class<DTO> var2, MPJBaseJoin var3);

    Map<String, Object> selectJoinMap(MPJBaseJoin var1);

    List<Map<String, Object>> selectJoinMaps(MPJBaseJoin var1);

    <P extends IPage<Map<String, Object>>> IPage<Map<String, Object>> selectJoinMapsPage(P var1, MPJBaseJoin var2);
}
  • MPJBaseServiceImpl

    扩展了MyBatis Plus的 ServiceImpl 接口实现

public class MPJBaseServiceImpl<M extends MPJBaseMapper<T>, T> extends ServiceImpl<M, T> implements MPJBaseService<T> {
...
}

基础代码调整

简单的三处调整,就能完成整合工作

  • 将mapper改为继承MPJBaseMapper (必选)
public interface StudentInfoService extends BaseService<StudentInfo> { }
改成
public interface StudentInfoService extends MPJBaseService<StudentInfo> { }
  • 将serviceImpl改为继承MPJBaseServiceImpl (可选)
@Service
public class StudentInfoServiceImpl extends BaseServiceImpl<StudentInfoMapper, StudentInfo>
    implements StudentInfoService{
}
改成
@Service
public class StudentInfoServiceImpl extends MPJBaseServiceImpl<StudentInfoMapper, StudentInfo>
    implements StudentInfoService{
}

单记录联表查询

@Autowired
StudentInfoService sutdentInfoService;

/**
 * 联表查询单个
 */
@Test
public void selectJoinOne() {
    StudentInfoDTO studentInfoDTO = sutdentInfoService.selectJoinOne(StudentInfoDTO.class,
            new MPJLambdaWrapper<StudentInfo>()
                    .selectAll(StudentInfo.class)
                    .select(SchoolInfo::getSchoolName)
                    .selectAs(SchoolInfo::getSchoolAddr, StudentInfoDTO::getScAddr)
                    .select(ClassInfo::getClassName)
                    .leftJoin(SchoolInfo.class, SchoolInfo::getId, StudentInfo::getSchoolId)
                    .leftJoin(ClassInfo.class, ClassInfo::getId, StudentInfo::getClassId)
                    .eq(StudentInfo::getId, 1));
    log.info("selectJoinOne:{}", JSON.toJSONString(studentInfoDTO));
}

简单说明

StudentInfoDTO.class:表示resultType,用于接收联表查询之后的数据库返回

selectAll:指明查询实体对应的所有字段

select:指定查询列,同一个select只能指明单个表的列,所以多表关联时需要使用多个select去指明不同表的列

selectAs:重命名,表现在sql层面是会给字段加上as(别名);主要用在数据库字段名也实体对象的名称不一致的情况;

leftJoin、rightJoin、innerJoin: 左链接、右连接、等值连接;不懂这三种连接方式的

  • 参数一:参与联表的对象
  • 参数二:on关联的指定,此属性必须是第一个对象中的值
  • 参数三:参与连表的ON的另一个实体类属性

条件构造器:联表后可能会存在各种筛选条件,可以根据上面对条件构造器的介绍,指明所需要的筛选条件,比如上面.eq(StudentInfo::getId, 1)),就是用来指明ID为1的学生信息。

表名:

  • 默认主表别名是t,其他的表别名以先后调用的顺序使用t1,t2,t3…;
  • 需要直接apply语句的时候,就得知道对应的表面是什么再进行添加,所以不到万不得已的时候,不建议直接追加语句。

等价SQL

SELECT 
	t.id,
	t.name,
	t.age,
	t.class_id,
	t.school_id,
	t1.school_name,
	t1.school_addr AS scAddr,
	t2.class_name
FROM 
	student_info t
	LEFT JOIN school_info t1 ON (t1.id = t.school_id)
	LEFT JOIN class_info t2 ON (t2.id = t.class_id)
WHERE (t.id = ?)

联表查多条

@Autowired
StudentInfoService sutdentInfoService;

/**
 * 联表查询批量
 */
@Test
public void selectJoinList() {
    List<StudentInfoDTO> studentInfoDTOS = sutdentInfoService.selectJoinList(StudentInfoDTO.class,
            new MPJLambdaWrapper<StudentInfo>()
                    .selectAll(StudentInfo.class)
                    .select(SchoolInfo::getSchoolName)
                    .selectAs(SchoolInfo::getSchoolAddr, StudentInfoDTO::getScAddr)
                    .select(ClassInfo::getClassName)
                    .leftJoin(SchoolInfo.class, SchoolInfo::getId, StudentInfo::getSchoolId)
                    .leftJoin(ClassInfo.class, ClassInfo::getId, StudentInfo::getClassId)
            //.eq(StudentInfo::getId, 1)
    );
    log.info("selectJoinList:{}", JSON.toJSONString(studentInfoDTOS));
}

等价SQL

SELECT 
	t.id,
	t.name,
	t.age,
	t.class_id,
	t.school_id,
	t1.school_name,
	t1.school_addr AS scAddr,
	t2.class_name
FROM 
	student_info t
	LEFT JOIN school_info t1 ON (t1.id = t.school_id)
	LEFT JOIN class_info t2 ON (t2.id = t.class_id)

联表分页查询

@Autowired
StudentInfoService sutdentInfoService;

/**
 * 分页查询
 */
@Test
public void selectJoinPage() {
    IPage<StudentInfoDTO> studentInfoDTOIPage = sutdentInfoService.selectJoinListPage(new Page<>(1, 2), StudentInfoDTO.class,
            new MPJLambdaWrapper<StudentInfo>()
                    .selectAll(StudentInfo.class)
                    .select(SchoolInfo::getSchoolName)
                    .selectAs(SchoolInfo::getSchoolAddr, StudentInfoDTO::getScAddr)
                    .select(ClassInfo::getClassName)
                    .leftJoin(SchoolInfo.class, SchoolInfo::getId, StudentInfo::getSchoolId)
                    .leftJoin(ClassInfo.class, ClassInfo::getId, StudentInfo::getClassId)
                    .orderByAsc(StudentInfo::getId)
    );
    log.info("selectJoinPage:{}", JSON.toJSONString(studentInfoDTOIPage));
}

等价SQL

SELECT 
	t.id,
	t.name,
	t.age,
	t.class_id,
	t.school_id,
	t1.school_name,
	t1.school_addr AS scAddr,
	t2.class_name
FROM 
	student_info t
	LEFT JOIN school_info t1 ON (t1.id = t.school_id)
	LEFT JOIN class_info t2 ON (t2.id = t.class_id)
ORDER BY 
	t.id ASC 
LIMIT 2

MyBatis-Flex

2023年开源免费的工具,功能强大,效率高,只依赖mybatis,稳定性有待观察; MyBatis-Flex - MyBatis-Flex 官方网站