一、mybatis动态查询(分页排序搜索)
mybatis框架分页实现,有几种方式,最简单的就是利用原生的sql关键字limit来实现,还有一种就是利用interceptor来拼接sql,实现和limit一样的功能,再一个就是利用PageHelper来实现。
因为我是使用的limit实现,有分页,排序,搜索功能,这里记录一下:
//Mapper.xml
<select id="findXxx" resultType="com.Xxx">
SELECT
*
FROM
Xxx
<where>
有其他条件加在这里,先搜索,再排序,最后分页。limit要放最后
<include refid="SearchCond"/>
<include refid="SortCond"/>
<include refid="PageCond"/>
</where>
</select>
<sql id="PageCond">
<if test="@java.util.Objects@nonNull(pageInfo)">
limit #{pageInfo.offset, jdbcType = INTEGER}, #{pageInfo.pageSize, jdbcType = INTEGER}
</if>
</sql>
<sql id="SearchCond">
<if test="@java.util.Objects@nonNull(searchRequest)">
<if test="searchRequest.fields != null and searchRequest.fields.size() != 0">
<foreach collection="searchRequest.fields" item="field" index="index" open="and (" close=")" separator="or">
${field} like concat ('%', #{searchRequest.keyword,jdbcType=VARCHAR} ,'%')
</foreach>
</if>
</if>
</sql>
<sql id="SortCond">
<if test="@java.util.Objects@nonNull(sortRequest) and @java.util.Objects@nonNull(sortRequest.field)">
order by
${field}
<choose>
<when test="@java.util.Objects@nonNull(sortRequest.order) and sortRequest.order.toString.equals('DESC')">
desc
</when>
<otherwise/>
</choose>
</if>
</sql>
//dao层
List<TagSet> findXxx(
@Param("pageInfo") PageInfo pageInfo,
@Param("searchRequest") SearchRequest searchRequest,
@Param("sortRequest") SortRequest sortRequest);
//通用类,这个getOffset注意一下,如果不这样写也可以,就在Mapper.xml自己写。
public class PageInfo {
private Integer pageIndex;
private Integer pageSize;
private Integer getOffset () {
return (this.pageIndex - 1) * this.pageSize;
}
}
public class SearchRequest {
/**
* 搜索字段名称
* 可多选
*/
private Set<String> fields;
/**
* 搜索关键字
*/
private String keyword;
}
public class SortRequest {
private String field;
private String order;
public Sort.Direction getOrder() {
if ("ascending".equalsIgnoreCase(order)) {
return Sort.Direction.ASC;
}
return Sort.Direction.DESC;
}
}
代码很简单,但是还是有很多细节需要注意,比如pageCond中的。如果我不是用的getOffset去获取的话,就只有用类似${(page-1)*size}的方式,当然这就没法防止sql注入。还有就是要考虑好各种情况,有时候参数不传的情况下自己的sql语句是否有语法错误等。
遗留问题:比如排序的时候,我们可能得到前端传过来的是updateTime
,但是数据库字段是update_time
。这就要自己写if判断然后转换了吗?有没有通用性更好的办法呢?
参考: mybatis三种分页方法
二、分解关联查询
《高性能sql》中有提到:分解了关联查询后,可以让缓存的效率更高;执行单个查询可以减少锁的竞争;在应用层做关联可以更容易做到高性能和可扩展;本身查询效率更高;减少冗余记录等优势。所以我应该减少关联查询。
三、logback 日志配置
日志级别:TRACE < DEBUG < INFO < WARN < ERROR < FATAL
springboot默认情况下是利用logback把info级别打印到控制台:
root标签可以改变你想打印的级别,比如debug,就会打印等于和大于该级别的日志。
<root level="DEBUG">
当然,想打印sql语句就需要用到logger标签,把dao层设为:
<logger name="com.xxx.dao" level="DEBUG" />
最后,如果设置了过滤级别,也需要同步修改,不然不生效
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>info</level>
</filter>
参考:
SpringBoot项目的logback日志配置(包括打印mybatis的sql语句)
四、mybatis新增记录后返回自增的id。批量
单个自增id
这个好理解,直接加上useGeneratedKeys=“true” keyProperty=“user.Id”,就可以。
<insert id="insertXxx" useGeneratedKeys="true" keyProperty="xxx.id">
取这个id的话就:xxx.getId()
不过网上说有坑需要注意:主键要设自增,dao层不要用@param。
批量
我遇到的问题是:批量插入数据,永远只返回最后一个id。
解决:问题出在xml文件的写法上。我写成了<foreach>insert XXXXXX</foreach>
。这样会导致只返回最后一个自增id。应该写成insertXXX<foreach>(XX,XX,XX)</foreach>
。简单来说就是一个insert就够了,foreach标签位置要放对。如果很多insert的话感觉就会把前面的覆盖掉了。。。(不太懂底层是怎样的)
<insert id="insertList" useGeneratedKeys="true" keyProperty="dbId" keyColumn="dbId">
INSERT INTO `aity`.`xxx`(`name`, `color`)
<foreach collection="list" item="c" index="index" open="VALUES" separator=",">
(#{c.name, jdbcType=VARCHAR},
#{c.color, jdbcType=VARCHAR})
</foreach>
</insert>
//dao层
void insertList(List<Xxx> list);
取的话也好取,同样什么传入的就什么接收id,这里就是list了。for(Xxx l : list){l.getDbId()}