1. Mapper接口的传参
在mapper文件中,每个sql语句的id都是唯一的,所以在mapper接口中定义重载方法没有意义。
1.1 接口方法传一个基本类型的参数
当接口方法有一个基本类型参数时,mapper文件中的sql语句中可以使用 #{任意名称} 引用这个参数;
List<StudentInfo> list1(Integer stuId);
<select id="list1" resultType="StudentInfo">
select * from studentInfo
where studentId = #{xxx}
</select>
1.2 接口方法传多个基本类型参数
当接口方法中有多个参数时, mapper不能直接使用参数名引用参数,可以使用 #{arg0},
#{arg1}这种特定的参数名来依次传参,或者用 #{param1},#{param2};
List<StudentInfo> list2(Integer stuId,String name);
<select id="list2" resultType="StudentInfo">
select * from studentInfo
where studentId = #{arg0} and name = #{arg1}
</select>
1.3 为方法参数设置别名
对于多个参数使用上中方式不够直观,可以通过 @Param注解 为接口方法的参数设置别名,mybatis会自动将多个参数数据封装到Map对象中;
List<StudentInfo> studentList1(@Param("studentId") Integer studentId,
@Param("classId") Integer classId);
<select id="studentList1" resultMap="studentMap">
select studentId,name,sex,birthday,province,s.classId,
c.classId,c.className
from studentInfo s join classInfo c
on s.classId = c.classId
<where>
<if test="studentId!=null and studentId!=''">
and studentId > #{studentId}
</if>
<if test="classId!=null and classId!= ''">
and s.classId = #{classId}
</if>
</where>
</select>
1.4 传入对象类型的参数
方法参数用对象封装,在mapper文件中可以直接引用对象属性;
List<StudentInfo> listByStu(StudentInfo studentInfo);
<select id="listByStudent" resultType="StudentMap" parameterType="StudentInfo">
select * from studentInfo
where sex = #{sex} and name like concat("%",#{name},"%")
</select>
1.5 #{} 和 ${} 区别
#{ }:是一个参数占位符,mybatis默认使用PreparedStatement 来执行sql语句,#{} 等价于 占位符 ?;
${ }:用字符串拼接的方式,拼接sql语句,当方法参数只有一个值的时候,同时没有设置 @Param 注解时可以使用 ${value} 来引用参数,同时不安全,sql注入。
2. resultType和resultMap的使用
对于查询而言,除了使用resultType指定返回记录类型,也可以使用resultMap进行查询结果的映射。
resultType:查询结果是单表数据(单一实体),或者插叙的列名和实体属性能一一对应,一般 用于简单结果集的映射配置;
resultMap:查询是多表数据(有多个实体),或者查询的列名和实体属性不能对应,一般用于 复杂结果集的映射配置。
2.1 一对一查询的配置
一个学生对应一个班级;
@Data
public class StudentInfo {
private Integer studentId;
private String name;
private String sex;
private Date birthday;
private String province;
private Integer classId;
private ClassInfo classInfo;
}
sql:
<resultMap id="studentMap" type="StudentInfo" autoMapping="true">
<association property="classInfo" javaType="ClassInfo" autoMapping="true"/>
</resultMap>
<select id="studentList" resultMap="studentMap">
select studentId,name,sex,birthday,province,s.classId,
c.classId,c.className
from studentInfo s join classInfo c
on s.classId = c.classId
</select>
属性名称 | 作用 |
property | 对象属性名称 |
javaType | 对象属性的类型 |
column | 所对应的外键字段名称 |
select | 使用另一个查询封装结果 |
2.2 一对多的配置
一个班级对应多个学生;
@Data
public class ClassInfo {
private Integer classId;
private String className;
private List<StudentInfo> studentList;
}
sql:
<resultMap id="classMap" type="classInfo" autoMapping="true">
<!--必须配置主键列-->
<id property="classId" column="classId"/>
<collection property="studentList" ofType="studentInfo" autoMapping="true">
</collection>
</resultMap>
<select id="classList" resultMap="classMap">
select studentId,name,sex,birthday,province,s.classId,
c.classId,c.className
from studentInfo s join classInfo c
on s.classId = c.classId
</select>
属性名称 | 作用 |
property | 对象属性名称 |
ofType | 对象属性类型 |
column | 所对应的外键字段名称 |
select | 使用另一个查询封装结果 |
3. MyBatis 的动态SQL
使用动态sql标签
3.1 if
条件判断,动态拼接sql;
一般用于非空验证,不满足条件,if标签里面的代码就不会执行。
3.2 where
一般和if结合使用,根据参数动态拼接sql,特点:
①当需要拼接条件时,根据参数值动态拼接sql;
②自动去除第一个条件前面的and关键字。
<select id="studentList1" resultMap="studentMap">
select studentId,name,sex,birthday,province,s.classId,
c.classId,c.className
from studentInfo s join classInfo c
on s.classId = c.classId
<where>
<if test="studentId!=null and studentId!=''">
and studentId > #{studentId}
</if>
<if test="classId!=null and classId!= ''">
and s.classId = #{classId}
</if>
</where>
</select>
此外,在xml文件中尽量避免直接写 >,<,& 等;
特殊符号 | 转义序列 |
< | < |
<= | <= |
> | > |
>= | >= |
& | & |
' | ' |
" | " |
备用方式:
<![CDATA[
含有特殊符号的代码
>
3.3 trim,set
trim 标签一般用于去除sql语句中多余的and关键字,逗号,或者给sql语句前拼接"where","set"以及"values("等前缀,或者添加")"等后缀,可用于选择性插入,更新,删除或者条件查询等操作。
属性 | 描述 |
prefix | 给sql语句拼接后缀 |
suffix | 给sql语句拼接前缀 |
prefixOverides |
去除sql语句前面的关键字或者字符,该关键字或者字符由prefixOverrides属性指定,假设该属性指定为"AND",当sql语句的开头为"AND",trim标签将会去除该"AND"
|
suffixOverides |
去除sql语句后面的关键字或者字符,该关键字或者字符由suffixOverrides属性指定
|
<update id="updateStu" parameterType="StudentInfo">
update studentInfo
<set>
<if test="name != null and name !=''">
name = #{name},
</if>
<if test="sex!=null and sex !=''">
sex = #{sex},
</if>
</set>
where studentId = #{studentId}
</update>
3.4 foreach
使用循环生成sql语句;
foreach 标签可迭代任何对象(如数组、集合(list,set,map)等)和任何的字典或者数组对象传递给 foreach 作为集合参数,当使用可迭代对象或者数组时,index 是当前迭代的次数,item 的值是本次迭代获取的元素;当使用字典(或者 Map.Entry 对象的集合)时, index 是键, item 是值;collection 标签可以填( 'list','array','map')
<!--传入整数数组-->
<select id="listByArray" resultType="StudentInfo">
select * from studentInfo
where studentId in
<foreach collection="array" item="data" open="(" close=")" separator=",">
#{data}
</foreach>
</select>
<!--批量插入数据-->
<insert id="insertGoods" parameterType="java.util.ArrayList">
insert into tb_goods(goods_name,price,produce_date,address,category_id)
values
<foreach collection="list" item="goods" index="index" separator=",">
(#{goods.goodsName}, #{goods.price}, #{goods.produceDate}, #{goods.address}, #{goods.categoryId})
</foreach>
</insert>
3.5 choose(when,otherwise)
与switch分支语句类似,可以根据条件执行某个分支,只会执行其中的一个分支;
<select id="listByCon" resultType="StudentInfo">
select * from studentInfo
<where>
<choose>
<when test="name != null and name != ''">
name = #{name}
</when>
<when test="sex !=null and sex != ''">
sex = #{sex}
</when>
<otherwise>
studentId = 1
</otherwise>
</choose>
</where>
</select>
3.6 返回自动增长的主键
用于有外键关系的两个表,主表插入数据之后,需要把主表数据的自增值获取到,然后再插入从表的数据时,插入到从表的外键列中;
useGeneratedKeys="true" 启用自增值返回的功能keyProperty="实体属性": 自增值填充到传入对象的那个属性中
<insert id="insertStu" parameterType="StudentInfo" useGeneratedKeys="true" keyProperty="studentId">
insert into studentInfo
(name,sex,birthday,province)
values
(#{name},#{sex},#{birthday},#{province})
</insert>
3.7 sql标签定义通用sql片段
<sql id="stuSql">
select studentId,name,sex,birthday,province,s.classId,
c.classId,c.className
from studentInfo s join classInfo c
on s.classId = c.classId
</sql>
<select id="studentList" resultMap="studentMap">
<include refid="stuSql"></include>
</select>
4. 延迟加载(懒加载)
使用嵌套查询实现多表关联,使用嵌套查询的时候会出现1+N的问题;
嵌套查询:
<!--goods-->
<resultMap id="goodsMap2" type="Goods" autoMapping="true">
<id property="goodsId" column="goods_id"/>
<association property="category"
javaType="Category"
column="category_id"
select="com.mapper.CategoryMapper.category">
</association>
</resultMap>
<sql id="colSql2">
goods_id,goods_name,price,produce_date,address,category_id
</sql>
<select id="goodsList2" resultMap="goodsMap2">
select
<include refid="colSql2"></include>
from goods
</select>
<!--category-->
<select id="category" resultType="category">
select category_id,category_name
from category
where category_id = #{categroy_id}
</select>
1+N问题(查询一次商品要查询多次种类):
可以使用延迟加载技术解决这个问题;
延迟加载,就是再进行关联查询的时候,按照设置的延迟规则推迟对关联对象的查询;延迟加载可以有效的减少数据库的压力,延迟加载只是对有延迟设置的关联对象的推迟查询,对于主查询是直接执行sql。
MyBatis关联查询加载时机:
①直接加载:执行完主对象的查询后,马上执行对关联对象的查询语句;
②侵入式延迟:执行完对主对象的查询后,不会执行对关联对象的查询,但当访问主对象的属性时,就会执行关联对象的查询;
③深度延迟:只有当真正访问关联对象的详情时,才会执行查询语句。
4.1 MyBatis延迟加载实现方式
4.1.1 全局延迟
①直接加载(默认)
<setting name="lazyLoadingEnabled" value="false"/>
<setting name="aggressiveLazyLoading" value="false"/>
②侵入式延迟:
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="true"/>
效果:
(访问对象属性时执行关联对象查询)
③深度延迟:
(访问关联对象时执行关联查询)
4.1.2 部分延迟
在关联查询collection,association标签上添加fetchType属性;
lazy:(深度)延迟加载
eager:立即加载
指定属性后,在映射配置中的全局配置 lazyLoadingEnabled 会被忽略。
<resultMap id="goodsMap2" type="Goods" autoMapping="true">
<id property="goodsId" column="goods_id"/>
<association property="category"
javaType="Category"
column="category_id"
select="com.mapper.CategoryMapper.category"
fetchType="eager">
</association>
</resultMap>