前言

  1. 前几天写我的漫画存储项目时遇到个问题,因为设计的表结构主键自增的关系,在每次新插入漫画或章节信息时数据库会给每一个元组添加主键,每次我要按漫画信息->章节信息->图片信息的顺序插入时都要插入新数据后根据当前属性name值查一下id值才能根据id值进行下一步的插入,这样每次插入都多了一次查询操作,十分影响性能。后来通过mybatis的官方文档找到了解决方案,mybatis的insert、update方法可以通过设置useGeneratedKeys=truekeyProperty="id"实现主键回传功能然后在每次操作后返回操作元组的主键。这样一来每次操作完上一步的插入之后可以根据同一对象回传的id值进行下一步操作。
  2. 之前写批量的插入删除操作时都是对单条语句重复执行,极大地浪费性能,批量处理的语句可以通过动态sql的foreach来传值处理
  3. 查询分页通常分为物理分页和逻辑分页两种方法。物理分页就是在sql语句构建时候使用limit关键字进行查询,这一过程在数据库中已经完成。而逻辑分页通常是把所有结果集都查出来,然后在对应接口方法中添加指定了起始与长度的RowBounds对象,对所有数据再一次进行截获。所以,逻辑分页内存开销比较大,在数据量比较小的情况下效率比物理分页高;在数据量很大的情况下,内存开销过大,容易内存溢出。使用哪种分页要看具体情况来定夺。

内容

  1. 主键回传
  2. mapper的动态sql
  3. 物理分页和逻辑分页

主键回传

mapper文件方式:给insert或update方法添加属性值

<!--插入漫画-->
<insert id="insertComic" parameterType="com.example.kbcomic.entity.Comic"
useGeneratedKeys="true" keyColumn="comic_id" keyProperty="comicId">
insert into all_comic (comic_name,comic_description,comic_cover,create_time,update_time)
values ('${comicName}','${comicDescription}','${comicCover}','${createTime}','${updateTime}')
</insert>

注解形式:在mapper接口对应方法上添加@Options注解并设属性值

//插入漫画
@Options(useGeneratedKeys = true,keyProperty = "comicId")
Integer insertComic(Comic comic);

动态sql

  • if
  • choose(when,otherwise)
  • foreach

下面的大部分内容直接搬mybatis文档= =(懒得自己再写一遍)

if
使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。比如:

<select id="findActiveBlogWithTitleLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>

这条语句提供了可选的查找文本功能。如果不传入 “title”,那么所有处于 “ACTIVE” 状态的 BLOG 都会返回;如果传入了 “title” 参数,那么就会对 “title” 一列进行模糊查找并返回对应的 BLOG 结果

如果希望通过 “title” 和 “author” 两个参数进行可选搜索该怎么办呢?首先,我想先将语句名称修改成更名副其实的名称;接下来,只需要加入另一个条件即可。

<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>

choose、when、otherwise
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

还是上面的例子,但是策略变为:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG。

<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>

foreach
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符
使用我自己项目的例子

<!--批量删除磁力-->
<delete id="batchDeleteMagnet">
delete from magnet
where name in
<foreach collection="nameList" item="magnetName" index="index" open="(" separator="," close=")">
#{magnetName}
</foreach>
</delete>

假如namelist列表的值为(1,2,3)则该语句相当于

<delete id="batchDeleteMagnet">
delete from magnet
where name in
(1,2,3)
</delete>

即是把name值为1,2,3的元组都删除,这个sql优化比之前重复操作同一条删除语句要更方便高效

script
要在带注解的映射器接口类中使用动态 SQL,可以使用 script 元素。比如:

@Update({"<script>",
"update Author",
" <set>",
" <if test='username != null'>username=#{username},</if>",
" <if test='password != null'>password=#{password},</if>",
" <if test='email != null'>email=#{email},</if>",
" <if test='bio != null'>bio=#{bio}</if>",
" </set>",
"where id=#{id}",
"</script>"})
void updateAuthorValues(Author author);

分页

物理分页例子

<select id="pagingQueryMagnet" resultType="com.message.entity.Magnet" parameterType="java.lang.Integer">
select *
from magnet
limit #{currentPage},#{pageNum}
</select>

逻辑分页例子

@Select("select * from book")
@Results(id = "book",value = {
@Result(id = true,column = "id",property = "bookId"),
@Result(column = "bookname",property = "bookName"),
@Result(column = "author",property = "bookAuthor"),
@Result(column = "publicationdate",property = "publicTime"),
@Result(column = "price",property = "bookPrice")
})
List<Book>queryAll(RowBounds rowBounds);
//从第一条开始查询两条数据
RowBounds rowBounds=new RowBounds(0,2);
List<Book> books = mapper.queryAll(rowBounds);

总结

  1. 主键回传使用useGeneratedKeys=truekeyProperty="id"
  2. 动态sql在操作参数多的时候十分好用
  3. 使用哪种分页要根据实际情况来选择