mybatis-generator优化:SqlExample

本文探讨了MyBatis Generator的局限性,并提出了一种改进方案,通过自定义Example类实现更灵活的代码生成,避免硬编码字段名,提供代码提示,支持复杂查询条件和字段选择。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

缘由

最近使用mybatis接触到了mybatis-generator,感觉蛮好用的,但是example部分限制较大:

  • 为每一个实体类构建了一个example类,代码量冗余度极高
  • 条件或只能构建成(A and B) or (C and D)的形式
  • 指定查询字段为setFields("id, name"),即参数为字符串(虽然fields是通过插件添加上去的)
  • 设置order by子句为setOrderByClause("create_time desc"),参数依然为字符串

我强调后两条参数为字符串,是因为这种设计不太理想:

  • 一旦数据库字段变更,重新生成文件后手写的字段名是改不过来的
  • 手写字段名称没有代码提示易出现错误

看来generator的example是需要改进的。

方针

边界:单表操作

example类只为单表操作设计,复杂sql语句在mapper中编写。若复杂的sql语句使用代码编写会带来很大的复杂度,得不偿失。

目的:全代码提示

最大限度保证使用example过程中,不出现字段名称的字符串形式,不需要修改已经编写的代码或有代码提示错误。

期望

setDistinct
BrandQuery brandQuery = new BrandQuery();
brandQuery.setDistinct(true);

assertTrue(brandQuery.isDistinct());

其实BrandQuery继承了SqlExample,建议使用SqlExample<Brand>替换BrandQuery

SqlExample<Brand> example = new SqlExample<Brand>().setDistinct(true);

assertTrue(example.isDistinct());
setFields

setFields用于设置查询字段,每次调用会覆盖上次的值。

SqlExample<Brand> example = new SqlExample<Brand>()
        .setFields(Brand.ID, Brand.FIRST_CHAR.as("first"));

assertEquals("id, first_char as first", example.getFields());

使用addFields用于对字段进行追加

SqlExample<Brand> example = new SqlExample<Brand>()
        .setFields(Brand.ID)
        .addFields(Brand.FIRST_CHAR.as("first"));

assertEquals("id, first_char as first", example.getFields());

使用FastExample写法

SqlExample<Brand> example =
        FastExample.fields(Brand.ID).addFields(Brand.FIRST_CHAR.as("first"));

assertEquals("id, first_char as first", example.getFields());
orderBy

orderBy用于设置order by子句,每次调用会覆盖上次的值。

SqlExample<Brand> example = new SqlExample<Brand>()
        .orderBy(Brand.FIRST_CHAR.desc(), Brand.NAME.asc());

assertEquals("first_char desc, name asc", example.getOrderByClause());

使用andOrderBy用于对排序字段进行追加

SqlExample<Brand> example = new SqlExample<Brand>()
        .orderBy(Brand.FIRST_CHAR.desc())
        .andOrderBy(Brand.NAME.asc());

assertEquals("first_char desc, name asc", example.getOrderByClause());

使用FastExample写法

SqlExample<Brand> example =
        FastExample.orderBy(Brand.FIRST_CHAR.desc()).andOrderBy(Brand.NAME.asc());

assertEquals("first_char desc, name asc", example.getOrderByClause());
where

where用于设置条件查询,每次调用会覆盖上次的值。

简单查询

SqlExample<Brand> example = new SqlExample<Brand>().where(Brand.ID.equal(1L));

List<Criterion<Brand>> criterionList = example.getCriterionList();

assertEquals("id = ", criterionList.get(0).getPrefix());
assertEquals(1L, criterionList.get(0).getValue());

使用FastExample写法

SqlExample<Brand> example = FastExample.where(Brand.ID.equal(1L));

List<Criterion<Brand>> criterionList = example.getCriterionList();

assertEquals("id = ", criterionList.get(0).getPrefix());
assertEquals(1L, criterionList.get(0).getValue());

字段与字段间的条件

SqlExample<Brand> example = new SqlExample<Brand>();
example.where(Brand.NAME.equal(Brand.FIRST_CHAR));

List<Criterion<Brand>> criterionList = example.getCriterionList();

assertEquals("name = first_char", criterionList.get(0).getPrefix());

使用表达式进行多条件查询

SqlExample<Brand> example = new SqlExample<Brand>().where(c -> c
        .and(Brand.NAME.like("%abc%"))
        .and(Brand.FIRST_CHAR.like("%A%")));
        
List<Criterion<Brand>> criterionList = example.getCriterionList();

assertEquals("(", criterionList.get(0).getPrefix());
assertEquals("name like ", criterionList.get(1).getPrefix());
assertEquals("%abc%", criterionList.get(1).getValue());
assertEquals(" and ", criterionList.get(2).getPrefix());
assertEquals("first_char like ", criterionList.get(3).getPrefix());
assertEquals("%A%", criterionList.get(3).getValue());
assertEquals(")", criterionList.get(4).getPrefix());

为了避免无嵌套的多条件查询也会被括号包裹,使用andWhereorWhere来追加条件

SqlExample<Brand> example = new SqlExample<Brand>()
        .andWhere(Brand.NAME.like("%abc%"))
        .orWhere(Brand.FIRST_CHAR.like("%A%"));
        
List<Criterion<Brand>> criterionList = example.getCriterionList();

assertEquals("name like ", criterionList.get(0).getPrefix());
assertEquals("%abc%", criterionList.get(0).getValue());
assertEquals(" or ", criterionList.get(1).getPrefix());
assertEquals("first_char like ", criterionList.get(2).getPrefix());
assertEquals("%A%", criterionList.get(2).getValue());

使用表达式进行嵌套条件查询

SqlExample<Person> example = new SqlExample<Person>().where(c -> c
        .and(c -> c
                .and(Person.AGE.equal(13))
                .or(Person.NAME.like("%abc%")))
        .or(c -> c
                .and(Person.AGE.equal(13))
                .or(Person.NAME.like("%abc%")));

List<Criterion<Person>> criterionList = example.getCriterionList();

assertEquals("(", criterionList.get(0).getPrefix());
assertEquals("age = ", criterionList.get(1).getPrefix());
assertEquals(13, criterionList.get(1).getValue());
assertEquals(" or ", criterionList.get(2).getPrefix());
assertEquals("name like ", criterionList.get(3).getPrefix());
assertEquals("%abc%", criterionList.get(3).getValue());
assertEquals(")", criterionList.get(4).getPrefix());
assertEquals(" or ", criterionList.get(5).getPrefix());
assertEquals("(", criterionList.get(6).getPrefix());
assertEquals("age = ", criterionList.get(7).getPrefix());
assertEquals(13, criterionList.get(7).getValue());
assertEquals(" or ", criterionList.get(8).getPrefix());
assertEquals("name like ", criterionList.get(9).getPrefix());
assertEquals("%abc%", criterionList.get(9).getValue());
assertEquals(")", criterionList.get(10).getPrefix());

真实案例中if判断进行条件添加

Criteria<Brand> criteria = new Criteria<>();

if(!StringUtils.isNullOrEmpty(searchInput.getName())) {
    criteria.and(Brand.NAME.like("%"+searchInput.getName()+"%"));
}
if(!StringUtils.isNullOrEmpty(searchInput.getFirstChar())) {
    criteria.and(Brand.FIRST_CHAR.like("%"+searchInput.getFirstChar()+"%"));
}

SqlExample<Brand> example = new SqlExample<Brand>().where(criteria);

return brandDao.selectByExample(example);

使用andWhere可以不创建Criteria实例

SqlExample<Brand> example = new SqlExample<Brand>();

if(!StringUtils.isNullOrEmpty(searchInput.getName())) {
    example.andWhere(Brand.NAME.like("%"+searchInput.getName()+"%"));
}
if(!StringUtils.isNullOrEmpty(searchInput.getFirstChar())) {
    example.andWhere(Brand.FIRST_CHAR.like("%"+searchInput.getFirstChar()+"%"));
}

return brandDao.selectByExample(example);

SqlExample支持所有原查询操作,如下

equal(value)
notEqual(value)
greaterThan(value)
greaterAndEqualThan(value)
lessThan(value)
lessAndEqualThan(value)
isNull()
isNotNull()
in(list)
notIn(list)
between(value1, value2)
notBetween(value1, value2)
like(string)
notLike(string)

引入

文件生成
  • 打开generator_for_sqlexample工程
  • 在工程中打开generatorConfig.xml文件修改配置信息
  • 执行src中的GeneratorSqlmap类入口函数即可生成文件
安装jar包到本地maven

generator_for_sqlexample工程lib中的mybatis-generator-sqlexample-1.1.jar包需要引入到项目中。

打开命令行工具键入并运行下面的命令,将mybatis-generator-sqlexample-1.1.jar包所在位置换成自己包所在的位置。

mvn install:install-file -Dfile=包所在位置\mybatis-generator-sqlexample-1.1.jar -DgroupId=org.mybatis.generator -DartifactId=mybatis-generator-sqlexample -Dversion=1.1 -Dpackaging=jar

显示BUILD SUCCESS后,就可在自己的maven工程中添加依赖了

<dependency>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-sqlexample</artifactId>
    <version>1.1</version>
</dependency>

需要注意的是,要使用mybatis-generator-sqlexample需要将Java语言级别设为8。

源码地址:https://github.com/amuliang/generator

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值