动态SQL
if标签
if标签中的test属性是必须的,if标签中test属性的值是true或者false
如果值是true,那么if标签中的sql语句就会拼接,反之则不会拼接
test的值的取值:
-
当使用@Param注解,那么要出现的是@Param注解指定的参数名,
-
当没有使用@Param注解要使用param1,param2,arg0,arg1...
-
当使用了pojo的实体类,那么test中出现的是pojo的属性名
<if test=""></if>
要给where加上一个恒等的条件,然后在拼接的每个sql语句当中加上and
sql语句当中是对应的字段名=#{}
List<Car> selectByMultiCondition(@Param("id") Long id, @Param("brand") String brand, @Param("guidePrice") Double guidePrice);
}
<select id="selectByMultiCondition" resultType="Car">
select *
from t_car
where 1=1
<if test="id != null and id !=''">
and id=#{id}
</if>
<if test="brand !=null and brand !=''">
and brand=#{brand}
</if>
<if test="guidePrice !=null and guidePrice !=''">
and guide_price=#{guidePrice}
</if>
</select>
where标签
where标签的作用:
-
所有条件都为空时,where标签保证不会生成where子句
-
自动去除某些条件前面多余的and或or
<select id="selectByMultiCondition" resultType="Car"> select * from t_car <where> <if test="id != null and id !=''"> id=#{id} </if> <if test="brand !=null and brand !=''"> and brand=#{brand} </if> <if test="guidePrice !=null and guidePrice !=''"> and guide_price=#{guidePrice} </if> </where> </select>
trim标签
trim标签的属性:
- prefix:在trim标签的语句前添加内容
- suffix:在trim标签的语句后添加内容
- prefixOverrides:前缀去掉
- suffixOverrides:后缀去掉
所有语句都为空就不加where
// prefix或suffix是在所有语句前面添加前缀或后缀
// 把trim标签语句内的and去掉
<trim prefix="where" suffixOverrides="and|or">
<if test="id != null and id !=''">
id=#{id} and
</if>
<if test="brand !=null and brand !=''">
brand=#{brand} and
</if>
<if test="guidePrice !=null and guidePrice !=''">
guide_price=#{guidePrice}
</if>
</trim>
set标签
当所有条件都为空的时候,不会添加set,会自动去除多余的","
<update id="UpdateBySet">
update t_car
<set>
<if test="carNum !=null and carNum!=''">car_num=#{carNum},</if>
<if test="brand !=null and brand!=''">brand=#{brand},</if>
<if test="guidePrice!=null and guidePrice!=''">guide_price=#{guidePrice},</if>
<if test="produceTime !=null and produceTime!=''">produce_time = #{produceTime},</if>
<if test="carType !=null and carType!=''">car_type = #{carType},</if>
</set>
where
id = #{id}
</update>
choose when otherwise
这三个标签是在一起使用的,相当于if else if else if else
只有一个分支会被选择
<select id="selectByChoose" resultType="Car">
select *
from t_car
<where>
<choose>
<when test="brand!=null and brand!=''">
and brand like "%"#{brand}"%"
</when>
<when test="guidePrice!=null and guidePrice !=''">
and guide_price = #{guidePrice}
</when>
<when test="carType !=null and carType !=''">
and car_type = #{carType}
</when>
</choose>
</where>
</select>
forEach标签
forEach底层是map存储的数组,collection的值可以是注解的值或者array,arg0
<!-- forEach标签的属性
collection:指定的数组或集合
item:代表集合或数组中的元素
separator:代表循环之间的分隔符
open:是forEach所有语句的最前面以什么开始
close:是forEach所有语句的最前面以什么结束
-->
int deleteByIds(@Param("ids") Long[] ids);
<delete id="deleteByIds">
delete from t_car
where id in (
<foreach collection="ids" item="id" separator=",">
#{id}
</foreach>
)
</delete>
批量添加
// #{}中的内容是pojo类的属性名
<insert id="insertByCars">
insert into t_car
values
<foreach collection="cars" item="car" separator=",">
(null,#{car.carNum},#{car.brand},#{car.guidePrice},#{car.produceTime},#{car.carType})
</foreach>
</insert>
sql标签与include标签
sql标签用来声明sql片段
include标签将声明的sql片段包含到某个sql语句当中
作用:提高代码的复用性,易于维护
<sql id="carColumNameSql">
id,
car_num as carNum,
brand,
guide_price as guidePrice,
produce_time as produceTime,
car_type as carType
</sql>
<select id="selectByIdResBigMap" resultType="java.util.Map">
select
<include refid="carColumNameSql"></include>
from t_car
</select>
高级映射
多对一
级联属性映射
多对一:多个主对象对应一个副对象
在设计的时候主对象应包含副对象的类
主对象对应的表是主表,副对象对应的是副表
多对一映射到JVM当中映射的是主对象
public class Student {//主对象
private Integer sId;
private String sName;
private Clazz clazz;//副对象
<resultMap id="studentResultMap" type="Student">
<id property="sId" column="sid"></id>
<result property="sName" column="sname"></result>
<result property="clazz.cId" column="cid"></result>
<result property="clazz.cName" column="cname"></result>
</resultMap>
<select id="selectById" resultMap="studentResultMap">
select
s.sid,s.sname,c.cid,c.cname
from t_stu as s
left join t_clazz as c
on s.cid=c.cid
where
s.sid=#{s.sid}
</select>
association方法
使用association标签进行映射
<resultMap id="studentResultMapSelectByIdAssociation" type="Student">
<id property="sId" column="sid"/>
<result property="sName" column="sname"/>
<!--
association:关联,一个student对象关联一个clazz对象
property:提供要映射的POJO类的属性名
javaType:用来指定要映射的java类型
-->
<association property="clazz" javaType="Clazz">
<id property="cId" column="cid"/>
<result property="cName" column="cname"/>
</association>
</resultMap>
分布查询
优点:可复用,可以进行延迟加载
<!--两条sql语句完成多对一的分布查询
这是第一步,根据学生id查询学生的所有信息,
property是指定映射的类型,
select是第二步查询的id,
column是将哪个参数传给select语句
-->
// Student映射文件对应的配置 主对象
<resultMap id="studentResultMapByStep" type="student">
<id property="sId" column="sid"/>
<result property="sName" column="sname"/>
<association property="clazz"
select="org.example.mapper.ClazzMapper.selectById"
column="cId"/>
</resultMap>
<select id="selectByIdStep1" resultMap="studentResultMapByStep">
select sid,sname,cid
from t_stu where sid=#{sid}
</select>
// Clazz映射文件对应的配置 副对象
<select id="selectById" resultType="Clazz">
select cid,cname from t_clazz where cid=#{cid}
</select>
延迟加载
延迟加载的核心原理:用的时候再执行查询语句,不用的时候不查询
作用:提高性能
在mybatis当中开启延迟加载,默认情况下是关闭的
这种在association设置fetchType只是局部的设置,只对当前关联的sql语句生效
如果要配置全局设置,要在核心配置文件当中设置
<association fetchType="lazy"/>
一对多
一对多:一个主对象对应多个副对象
主对象的类中有副对象类的集合
collection标签映射
<resultMap id="clazzResultMap" type="Clazz">
<id property="cId" column="cid"/>
<result property="cName" column="cname"/>
<!--
property:指定主对象中关联的副对象的属性名
ofType:用来指定集合中的元素类型
-->
<collection property="students" ofType="Student">
<id property="sId" column="sid"/>
<result property="sName" column="sname"/>
</collection>
</resultMap>
<select id="selectByCollection" resultMap="clazzResultMap">
select c.cid,c.cname,s.sid,s.sname
from t_clazz as c left join t_stu as s on c.cid=s.cid
where c.cid=#{cid}
</select>
分布查询
// collection中的property是clazz封装的List<Student>的属性名
// select是select的id
// column是要传入的值
// fetchType是否开启延迟加载
// Clazz的映射文件的配置 主对象
<resultMap id="ClazzResultMapStu" type="Clazz">
<id property="cId" column="cid"/>
<result property="cName" column="cName"/>
<collection property="students"
select="org.example.mapper.StudentMapper.selectById2"
column="cid"
fetchType="lazy"/>
</resultMap>
<select id="selectById1" resultMap="ClazzResultMapStu">
select cid,cname
from t_clazz
where cid=#{cid}
</select>
// Student的映射文件的配置 副对象
<select id="selectById2" resultType="Student">
select sid,sname,cid
from t_stu
where cid=#{cid}
</select>
Mybatis的缓存
内存:临时存储数据的空间,断电后消失
硬盘:持久化数据存储在硬盘当中,文件也是存储在硬盘上的,实际上各大关系型数据库的数据都是存储在文件当中
Mybatis的缓存机制
执行select语句的时候,将查询结果放到缓存当中,如果下一次还是执行完全相同的sql语句,直接从缓存中拿数据,不再查数据,不再去硬盘上拿数据
目的:提高执行效率
缓存机制:减少IO的方式来提高效率
IO:读写文件
缓存通常是我们程序开发中优化程序的重要手段
- 字符串常量池
- 整数型常量池
- 线程池
- 连接池
Mybatis的缓存
Myabtis的缓存包括
- 一级缓存:将查询到的数据存储到SqlSession中
- 二级缓存:将查询到的数据存储到SqlSessionFactory中
- 或者集成第三方的缓存,EhCache(Java语言开发)
一级缓存
一级缓存默认是开启的,不需要配置,将查询到的数据存储到SqlSession中
当SqlSession不是同一个的时候,不走缓存
一级缓存失效
当第一个DQL语句和第二个DQL语句之间做了两件事中的任意一件都会导致一级缓存失效
- 执行了sqlSession的clearCache()方法, 手动清空缓存
- 执行了INSERT或DELETE或UPDATE语句,不管是操作哪张表都会清空一级缓存
二级缓存
使用二级缓存需要配置条件,默认情况下二级缓存是开启的
- 在核心配置文件中配置<settingname="cacheEnabled" value="true">,默认是true,不用配置
- 在需要用到二级缓存的sql映射文件中添加配置<cache/>
- 使用二级缓存的实体类对象必须是可序列化的,必须实现Serializable接口,这样数据就可以以文件的形式存储了
- SqlSession对象关闭或提交之后,一级缓存中的数据才会被写入二级缓存当中,此时二级缓存才可用
二级缓存的失效
只要二级缓存之间存在INSERT或DELETE或UPDATE语句,不管操作哪个表,二级缓存都会失效
Mybatis的逆向工程
根据数据库逆向生成Java的pojo类,SqlMapper文件以及Mapper接口
QBC风格查询
QBC风格:Query By Criteria 一种查询方式,比较面向对象,看不到sql语句
mybatis的逆向工程的增强版中可以封装查询条件
通过XxxExample对象来封装对象
CarExample carExample = new CarExample();
//调用createCriteria方法来创建查询条件
carExample.createCriteria().andXxxXXX();
//两个查询条件是or的关系
carExample.or().and
Mybatis的PageHelper
页码:pageNum
每页显示的记录条数:pageSize
select *
from t_stu
limit startIndex,pageSize
mysql当中起始行的下标从0开始
在DQL语句之前使用pageHelper完成分页