Mybatis自动生成中的XXXExample
Mybati自动生成XXXExample类说明
Mybatis-generator会为每个字段产生Criterion,为底层的mapper.xml创建动态sql。如果表的字段比较多,产生的example类会十分庞大。
理论上通过example类可以构造你想到的任何筛选条件。在mybatis-generator中加以配置,配置数据表的生成操作就可以自动生成example了。
1、XXXExample结构
所以直接去看一下类结构:
public class ReviewContentExample {
/**
* 升序还是降序,可以连接多个。因为只会有一个,所以直接在这里连接了
* eg: 字段+空格+asc(desc)
*/
protected String orderByClause;
/**
* 去除重复,因为只会有一个,所以直接在这里设置
*
* true是选择不重复记录
*/
protected boolean distinct;
/**
* 自定义查询条件
* Criteria的集合,集合中对象是由or连接
*/
protected List<Criteria> oredCriteria;
/**
* 将oredCriteria中的条件按照or连接起来
*/
public ReviewContentExample() {
oredCriteria = new ArrayList<>();
}
.........
}
2、GeneratedCriteria类
mybatis提供的模板类:
/**
* 自动生成的模板类
*/
protected abstract static class GeneratedCriteria {
// 针对的是一个criteria中保存的条件
protected List<Criterion> criteria;
// 构造函数,创建条件表示当前where中的条件是什么
protected GeneratedCriteria() {
super();
criteria = new ArrayList<>();
}
// 校验是否有条件,没有条件判断的,就是非法的,也就是没有条件
// 如果有条件,就是和法的
public boolean isValid() {
return criteria.size() > 0;
}
// 获取得到条件集合
public List<Criterion> getAllCriteria() {
return criteria;
}
// 获取得到条件集合
public List<Criterion> getCriteria() {
return criteria;
}
// 添加条件
protected void addCriterion(String condition) {
// 无数据库中字段
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
// 如果存在条件,将对应的条件存入到集合中
criteria.add(new Criterion(condition));
}
// 添加条件、判断条件的值以及对应的处理器
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
public Criteria andIdEqualTo(Integer value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
.........
}
下面来看一下添加条件的底层源码,针对单个的判断:
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
// 返回自身,自身
return (Criteria) this;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
对于某一个单一条件来说,这里需要来进行设置:
protected Criterion(String condition) {
super();
// 设置条件
this.condition = condition;
// 没有对应的类型处理器
this.typeHandler = null;
// 没有值设置为true
this.noValue = true;
}
看一下有值的:
public Criteria andIdEqualTo(Integer value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
加了条件的判断
public Criteria andIdEqualTo(Integer value) {
// 外界给的值
addCriterion("id =", value, "id");
return (Criteria) this;
}
protected void addCriterion(String condition, Object value, String property) {
// 首先对value来进行判断
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
将当前条件和对应的值设置到条件集合中来
protected Criterion(String condition, Object value, String typeHandler) {
super();
// 设置条件
this.condition = condition;
// 设置值
this.value = value;
// 设置类型处理器,默认为null
this.typeHandler = typeHandler;
// 判断对应的值只不是集合类型
if (value instanceof List<?>) {
// 集合值
this.listValue = true;
} else {
// 单值
this.singleValue = true;
}
}
3、Criterion
这个类是针对每个条件来判断,某个条件中是否给了值,如果没有值,那么表示的是静态SQL;如果给了值,表示的是动态SQL。
针对于动态SQL来说,需要进行判断
- 1、是否是集合
- 2、是否是between这种类型的值;
- 3、是否是集合
public static class Criterion {
// 数据库中对应的条件,如:id =
private String condition;
// 条件对应的判断的值,如:id = 2,这个2就是值
private Object value;
// 针对的是between...and...情况
private Object secondValue;
// 没有值,如:id is not null
private boolean noValue;
// 是否是单值。如果是
private boolean singleValue;
// 是否是between
private boolean betweenValue;
// value是否是list集合
private boolean listValue;
// 对应的类型转换器是哪个类型的
private String typeHandler;
......
}
4、动态SQL分析
1、首先对集合来做判断,是否有多个元素,每个元素之间利用or来进行链接
2、针对集合中的某个条件,判断是否符合条件,也就是对valid字段来做校验。如果符合条件的话,那么遍历集合中的每个字段对应的条件。
【注意】:注意这里的遍历条件,因为是按照for循环添加的顺序来进行遍历的,所以必须考虑
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
注意test中的判断,判断的是对象中的属性判断信息。
1、首先对最外层的结合判断,使用or来进行拼接;
2、然后是对每个字段中的判断条件来进行选择;
3、最终来对如果要是集合中的数据来进行使用的话,可以选择对应的使用方式。
再来看一些:
<select id="selectByExample" parameterType="com.turing.draw.model.dto.DrawTaskExample" resultMap="BaseResultMap">
<!--@mbg.generated-->
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from draw_task
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
最终会将这里的orderByClause的值拷贝出来,所以在这里,如果需要多个条件的话,那么需要来写对应的条件即可。
如以下判断语句:
order by id desc , name asc
看到这样一行判断:
TaskRecordExample recordExample = new TaskRecordExample();
recordExample.setOrderByClause(" created_time desc");
TaskRecordExample.Criteria criteria = recordExample.createCriteria();
criteria.andIsDelEqualTo(0);
if (!StringUtils.isEmpty(searchVO.getSearchName())) {
criteria.andTaskNameLike("%" + searchVO.getSearchName() + "%");
}
if (!StringUtils.isEmpty(searchVO.getTemplateId())) {
criteria.andTemplateIdEqualTo(searchVO.getTemplateId());
}
利用这种if判断的方式来进行书写,虽然代码上不美观,但是很少用。
在这里看到一行SQL语句:
<select id="selectByExample" resultMap="BaseResultMap" parameterType="com.turing.procedure.model.dto.task.TaskRecordExample" >
select
<if test="distinct" >
distinct
</if>
'true' as QUERYID,
<include refid="Base_Column_List" />
from task_record
<if test="_parameter != null" >
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null" >
order by ${orderByClause}
</if>
</select>
这里可以看到一个比较奇葩的功能,如果没有去重条件的话,那么这里将会是select from ,中间什么语句也没有。
但是这里为了防止出现这种情况,所以使用了一种类似where 1 = 1的情况来进行使用。
这里运用到了ObjectMetadata来进行解析。
上面的判断是比较简单的使用方式了。
// 审核内容查询
ReviewContentExample contentExample = new ReviewContentExample();
ReviewContentExample.Criteria criteria = contentExample.createCriteria();
criteria.andTaskSnEqualTo(taskSn);
criteria.andVersionEqualTo(version);
//子场景要素判断
if (Tools.isNotEmpty(selectElements)) {
criteria.andEleIdIn(selectElements);
}
ForAnalyzeExample queryI = new ForAnalyzeExample();
queryI.createCriteria()
.andTaskSnEqualTo( cTaskSn )
.andEleIdEqualTo( cEleId )
.andParentTaskEqualTo( cParentTaskSn )
.andVersionEqualTo( -1 );
List< ForAnalyze > oriVs = forAnalyzeMapper.selectByExample( queryI );
下面来看下各种使用方式
int deleteByExample( DrawTaskExample example );
5、总结
判断是查询,还是增伤改,只需要看里面对应的SQL语句即可。
其实本质上还是需要对各种条件的判断熟烂于心,不懂的话可以去看一下源码。这样子来写代码事半功倍。