目录
4. choose..when..otherwise 组合标签
一、特殊SQL语句
1. 模糊查询
模糊查询的特殊之处 -- 使用" #{} "占位符赋值使用时要注意,因为在解析sql时会在引号内再次动态拼接一次引号(因为#{}有自动拼接引号的作用);而使用 " ${} " 就不会。
<!--UserEntity getLike(@Param("address") String address);-->
<select id="getLike" resultType="userEntity">
<!--1. 直接使用的方式-->
select * from test_user where address like '%${address}%'
<!--2. 拼接:select * from test_user where address like concat('%',#{address},'%')-->
<!--3. select * from test_user where address like '%#{address}%' 这样会出错 -->
</select>
第三方式的报错信息:
2. 批量删除
批量删除使用 where 字段名 in(1,2,3...)时是不可以使用" #{} "动态赋值的 -- 因为这样会添加上引号
delete from test_user where id in (${ids})
如果想删除除了这几个参数以外的数据的话用 not in
delete from test_user where id not in (${ids})
3.动态设置表名
动态设置表明也不可以使用" #{} ",因为正确的查询语句 表名是不能用引号的
例如: select * from test_user
<!--List<User> getAllUser(@Param("tableName") String tableName);-->
<select id="getAllUser" resultType="userEntity">
select * from ${tableName}
</select>
4. 添加功能获取自增的主键
useGeneratedKeys :开启主键自增keyProperty :实体类中唯一的属性因为增删改有统一的返回值是受影响的行数,因此只能将获取的自增的主键放在传输的参数user 对象的某个属性中
<!--int insertUser(UserEntity user);-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into test_user values(null,#{username},#{password},#{address})
</insert>
二、自定义映射关系(resultMap)
- 可以通过为字段起别名的方式,保证和实体类中的属性名保持一致
- 可以在MyBatis的核心配置文件中设置一个全局配置信息mapUnderscoreToCamelCase,可以在查询表中数据时,自动将_类型的字段名转换为驼峰
若实体类中属性名和字段名不一致,可以通过resultMap来进行自定义映射
<!--resultMap:设置自定义映射 属性:
id:表示自定义映射的唯一标识
type:查询的数据要映射的实体类的类型
子标签:
id:设置主键的映射关系
result:设置普通字段的映射关系
association:设置多对一的映射关系
collection:设置一对多的映射关系
属性: property:设置映射关系中实体类中的属性名
column:设置映射关系中表中的字段名 -->
<resultMap id="userMap" type="UserEntity">
<id property="id" column="id"></id>
<result property="name" column="user_name"></result>
<result property="password" column="password"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
</resultMap>
<!--List<User> testLike(@Param("str") String str);-->
<select id="testLike" resultMap="userMap">
<!--select id,user_name,password,age,sex from t_user where username like '%${str}%'-->
select id,user_name,password,age,sex from t_user where user_name like concat('%',#{str},'%')
</select>
1. 多对一映射处理
指的是多个emp对像都对应某一条dept对象的数据
添加在Emp实体类中: private Dept dept;
a> 级联方式处理映射关系
<resultMap id="empDeptMap" type="Emp">
<id column="eid" property="eid"></id>
<result column="ename" property="ename"></result>
<result column="age" property="age"></result>
<result column="sex" property="sex"></result>
<!--这里property="dept.did" 第二个实体类直接用类名.属性名-->
<result column="did" property="dept.did"></result>
<result column="dname" property="dept.dname"></result>
</resultMap>
<!--Emp getEmpAndDeptByEid(@Param("eid") int eid);-->
<select id="getEmpAndDeptByEid" resultMap="empDeptMap">
select emp.*, dept.* from t_emp emp left join t_dept dept on emp.did = dept.did where emp.eid = #{eid}
</select>
b> 使用association处理关系映射
<!--使用association处理多对一映射关系-->
<resultMap id="empDeptMap" type="Emp">
<id column="eid" property="eid"></id>
<result column="ename" property="ename"></result>
<result column="age" property="age"></result>
<result column="sex" property="sex"></result>
<!--property="dept" - 对应Emp类中的属性名 javaType="Dept" - 对应的而实体类名-->
<association property="dept" javaType="Dept">
<id column="did" property="did"></id>
<result column="dname" property="dname"></result>
</association>
</resultMap>
<!--Emp getEmpAndDeptByEid(@Param("eid") int eid);-->
<select id="getEmpAndDeptByEid" resultMap="empDeptMap">
select emp.*,dept.* from t_emp emp left join t_dept dept on emp.did = dept.did where emp.eid = #{eid}
</select>
c> 分布查询
将多表联查拆分成单表查询,一层一层的进行查询,通过多次查询筛选到自己想要的数据。
3. 一对多映射处理
指一条Dept对象数据对应多条Emp对象数据
在Dept实体类中: private List<Emp> emp;
a> collection映射处理
<!--collection处理多对一映射-->
<resultMap id="deptEmpMap" type="Dept">
<id property="did" column="did"></id>
<result property="dname" column="dname"></result>
<!--ofType:设置collection标签所处理的集合属性中存储数据的类型 -->
<collection property="emps" ofType="Emp">
<id property="eid" column="eid"></id>
<result property="ename" column="ename"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
</collection>
</resultMap>
<!--Dept getDeptEmpByDid(@Param("did") int did);-->
<select id="getDeptEmpByDid" resultMap="deptEmpMap">
select dept.*,emp.* from t_dept dept left join t_emp emp on dept.did = emp.did where dept.did = #{did}
</select>
b> 分布查询
将多表联查拆分成单表查询,一层一层的进行查询,通过多次查询筛选到自己想要的数据。
分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息:lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载,此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType="lazy(延迟加载)|eager(立即加载)"
三、动态SQL语句
1. if 标签
根据标签的test属性对应的表达式决定标签中的内容是否需要拼接到SQL中
<!--List<UserEntity> getIf(UserEntity user);-->
<select id="getIf" resultType="UserEntity">
select * from test_user where 1=1
<if test="id !='' and id !=null">and id =#{id}</if>
<if test="name !='' and name !=null">and name =#{name}</if>
<if test="password !='' and password !=null">and password =#{password}</if>
<if test="address !='' and address !=null">and address =#{address}</if>
</select>
2. where 标签
当where标签中有内容时,会自动生成where关键字,并且将内容前多余的and或者or去掉
当where标签中没有内容时,此标签不会生效 (注)and或or标签只能添加在内容之前
<!--List<UserEntity> getWhere(UserEntity user);-->
<select id="getWhere" resultType="UserEntity">
select * from test_user
<where>
<if test="id !='' and id !=null">id =#{id}</if>
<if test="name !='' and name !=null">and name =#{name}</if>
<if test="password !='' and password !=null">and password =#{password}</if>
<if test="address !='' and address !=null">and address =#{address}</if>
</where>
</select>
3. trim 标签
若标签有内容时:
prefix\suffix:将trim标签中内容前面\后面添加指定内容
suffixOverrides\prefixOverrides: 将trim标签中内容前面\后面移除指定内容
若标签没有内容时,trim标签也不回生效
<!--List<UserEntity> getTrim(UserEntity user);-->
<select id="getTrim" resultType="UserEntity">
select * from test_user
<trim prefix="where" suffixOverrides="and|or">
<if test="id !='' and id !=null">id =#{id} or</if>
<if test="name !='' and name !=null"> name =#{name} and</if>
<if test="password !='' and password !=null"> password =#{password} or</if>
<if test="address !='' and address !=null"> address=#{address}</if>
</trim>
</select>
4. choose..when..otherwise 组合标签
相当于java中的if..else if..else,when标签至少有一个.otherwise标签最多有一个
!--List<UserEntity> getChoose(UserEntity user);-->
<select id="getChoose" resultType="UserEntity">
select * from test_user
<where>
<choose>
<when test="name !='' and name !=null">name =#{name}</when>
<when test="address !='' and address !=null">address =#{address}</when>
<otherwise>password =#{password}</otherwise>
</choose>
</where>
</select>
5. foreach 标签
如果传递过来的参数是一个数据,一个集合是就像需要循环来进行操作
collection="ids" 要循环的数组\集合名称
item="id" 标识数据的名称
separator="," 以什么为间隔符号
open="(" 从什么符号开始
close=")" 从什么符号结束
<!--List<UserEntity> getForeach(Integer[] ids);-->
<select id="getForeach" resultType="UserEntity">
select * from test_user where id
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
<!--Integer insertForeach(@Param("user") List<UserEntity> list);-->
<insert id="insertForeach" >
insert into test_user values
<foreach collection="users" item="user" separator=",">
(null,#{user.name},#{user.password},#{user.address})
</foreach>
</insert>
6. sql 标签
可以记录一段公共sql片段,在使用的地方通过include标签进行引入
<sql id="ser">
id,name,password,address
</sql>
<select id="xxx" resultType="UserEntity">
select
<include refid="ser"></include>
from test_user
</select>
四、Mybatis的缓存
mybatis的缓存机制分为一级缓存和二级缓存两种机制,除了自带的,还可以整合第三方缓存,第三方缓存也是二级缓存。
1. 一级缓存
一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问。
- 不同的SqlSession对应不同的一级缓存
- 同一个SqlSession但是查询条件不同
- 同一个SqlSession两次查询期间执行了任何一次增删改操作
- 同一个SqlSession两次查询期间手动清空了缓存
2. 二级缓存
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取。
使二级缓存失效的情况:两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效。
二级缓存开启的条件:
- a>在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
- b>在映射文件中设置标签<cache />
- c>二级缓存必须在SqlSession关闭或提交之后有效
- d>查询的数据所转换的实体类类型必须实现序列化的接口
<!--开启二级缓存 在mybatis-config.xml核心配置文件中配置 -->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<!-- 在mapper配置文件中配置 -->
<cache type="org.apache.ibatis.cache.impl.PerpetualCache">
<property name="eviction" value="LRU" />
<property name="flushInterval" value="6000000" />
<property name="size" value="1024" />
<property name="readOnly" value="false" />
</cache>
PerpetualCache这个类是mybatis默认实现缓存功能的类。我们不写type就使用mybatis默认的缓存,也可以去实现 Cache 接口来自定义缓存。
* 二级缓存在mapper配置文件中添加cache标签可以设置的属性: * a> eviction属性: 缓存回收策略 * LRU-最近最少使用的:移除最长时间不被使用的对象 (默认选项) * FIFO-先进先出:按照对象进入缓存的顺序来移除他们 * SOFT-软引用:移除基于垃圾回收器状态和软引用规则的对象 * WEAK-弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象 * b> flushInterval属性: 刷新间隔:缓存多长时间刷新一次,单位毫秒 * 默认情况是不设置的,缓存仅仅调用sql语句时刷新(调用增删改的语句才会刷新缓存) * c> size属性: 引用数目,正整数 * 代表缓存最多可以储存多少个对象,太大容易导致内存溢出 * d> readOnly属性: 只读 true\false (默认false) * true:只读缓存,会给所有调用者返回缓存对象的相同实例;因此这些对象不能被修改,这提供了很重要的性能优势 * false:读写缓存,会返回缓存对象的拷贝(通过序列化),但是性能上慢一些,但是安全
3. 缓存查询得顺序
- a> 先查二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用
- b> 如果二级缓存没有命中,在查询一级缓存
- c> 如果一级缓存也没有命中,会查询数据库
- d> sqlSession关闭后,一级缓存中的数据会写入二级缓存中
四、拓展
Mybatis中除了上述功能,整合第三方缓存机制、分页插件、逆向工程都可以通过导入依赖来配置使用,建议使用Mybatis-Plus,指在mybatis基础上只做增强不做改变。