mybatis 基础知识
动态标签
-
<select> , <insert> , <update> , <delete> -
sql 标签
复用sql语句
<sql id="all_columns">
country.Code as country_code,
city.Population as city_population
</sql>
<select id="selectCountryAndCity" parameterType="map" resultMap="countryAndCity1">
SELECT <include refid="all_columns" />
From country LEFT JOIN city ON country.code=city.countrycode WHERE country.code=#{code} AND city.name=#{name}
</select>
where 标签
反例:
<select id="findActiveBlogLike" resultType="Blog">
SELECT * FROM BLOG
WHERE
<if test="state != null">
state = #{state}
</if>
<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>
正例:
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
set 标签用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列
<update id="updateAuthorIfNecessary">
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}
</update>
trim 标签
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE
<if test="state != null">
state = #{state}
</if>
<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>
如果没有匹配的条件会怎么样?最终这条 SQL 会变成这样:
SELECT * FROM BLOG
WHERE
这会导致查询失败。如果匹配的只是第二个条件又会怎样?这条 SQL 会是这样:
SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’
prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
foreach 标签动态 SQL 的另一个常见使用场景是对集合进行遍历尤其是在构建 IN 条件语句的时候
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
</select>
bind 标签元素允许你在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。比如:
<select id="selectBlogsLike" resultType="Blog">
<bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
SELECT * FROM BLOG
WHERE title LIKE #{pattern}
</select>
choose when otherwish 标签
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句
<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>
mybatis 的缓存机制
- 一级缓存
每个SqlSession中持有了Executor,每个Executor中有一个LocalCache。当用户发起查询时,MyBatis根据当前执行的语句生成MappedStatement,在Local Cache进行查询,如果缓存命中的话,直接返回结果给用户,如果缓存没有命中的话,查询数据库,结果写入Local Cache,最后返回结果给用户。
MyBatis一级缓存内部设计简单,只是一个没有容量限定的HashMap,在缓存的功能性上有所欠缺 MyBatis的一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为Statement。
- 二级缓存
MyBatis的二级缓存相对于一级缓存来说,实现了SqlSession之间缓存数据的共享,同时粒度更加的细,能够到namespace级别,通过Cache接口实现类不同的组合,对Cache的可控性也更强。
MyBatis在多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用二级缓存的条件比较苛刻。
SQL注入
- {}设置值时,不加引号存在sql注入的现象 编译之后的效果
SELECT * FROM BLOG WHERE state = ?
SELECT * FROM BLOG WHERE state = 'ONELINE'
- #{} 是预编译的方式,相当于jdbc的占位符PrepareStatement,一个#{}就是一个占位符 mybatis在为#{}设置值时,会加引号。 拼接:
SELECT * FROM BLOG WHERE state = ONELINE
SQL 注入 如果传入的变量是 ONELINE OR 1 = 1
SELECT * FROM BLOG WHERE state = ONELINE OR 1 = 1
查询排序的处理 需要列名的地方,在原生jdbc开发中,不可以预编译 因为预编译会给值加上引号,需要列名的是直接进行拼接的
批量更新&新增和循环新增更新的区别
-
循环遍历
-
动态sql
<insert id="InsertOrUpdate_Info" parameterType="MyInfo">
insert into movieinfo
(id,title,type)
values
(#{id},#{title},#{type})
ON DUPLICATE KEY UPDATE
title = #{title},type = #{type}
</insert>
- 批处理 可以在一次批处理中处理不同语义的SQL语句
//Statement实现批处理操作
public static void main(String[] args) {
//try-with-resource
try (Connection conn = JDBCUtils.getConnection();
Statement stat = conn.createStatement()) {
//添加进批
stat.addBatch("create table t1(id int,name varchar(20))");
stat.addBatch("insert into t1 values(1,'a')");
stat.addBatch("insert into t1 values(2,'b')");
stat.addBatch("insert into t1 values(3,'c')");
//执行批
int[] counts = stat.executeBatch();
//long[] longs = stat.executeLargeBatch();
System.out.println(Arrays.toString(counts));
} catch (SQLException e) {
e.printStackTrace();
}
}
将多条SQL添加到一个批中,一次性将批发送给数据库,数据库依次执行SQL语句,减少SQL语句发送的次数,提升程序运行的效率
快速开发工具
- mybatis plus
- tk mybatis