在mapper文件中,每个sql语句的id都是唯一的,所以在mapper接口中定义重载方法没有意义。
当接口方法有一个基本类型参数时,mapper文件中的sql语句中可以使用 #{任意名称} 引用这个参数;
List list1(Integer stuId);
- <select id="list1" resultType="StudentInfo">
- select * from studentInfo
- where studentId = #{xxx}
- </select>
当接口方法中有多个参数时, mapper不能直接使用参数名引用参数,可以使用 #{arg0},
#{arg1}这种特定的参数名来依次传参,或者用 #{param1},#{param2};
List list2(Integer stuId,String name);
- <select id="list2" resultType="StudentInfo">
- select * from studentInfo
- where studentId = #{arg0} and name = #{arg1}
- </select>
对于多个参数使用上中方式不够直观,可以通过 @Param注解 为接口方法的参数设置别名,mybatis会自动将多个参数数据封装到Map对象中;
- List
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>
方法参数用对象封装,在mapper文件中可以直接引用对象属性;
List listByStu(StudentInfo studentInfo);
- <select id="listByStudent" resultType="StudentMap" parameterType="StudentInfo">
- select * from studentInfo
- where sex = #{sex} and name like concat("%",#{name},"%")
- </select>
#{ }:是一个参数占位符,mybatis默认使用PreparedStatement 来执行sql语句,#{} 等价于 占位符 ?;
${ }:用字符串拼接的方式,拼接sql语句,当方法参数只有一个值的时候,同时没有设置 @Param 注解时可以使用 ${value} 来引用参数,同时不安全,sql注入。
对于查询而言,除了使用resultType指定返回记录类型,也可以使用resultMap进行查询结果的映射。
resultType:查询结果是单表数据(单一实体),或者插叙的列名和实体属性能一一对应,一般 用于简单结果集的映射配置;
resultMap:查询是多表数据(有多个实体),或者查询的列名和实体属性不能对应,一般用于 复杂结果集的映射配置。
一个学生对应一个班级;
- @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 | 使用另一个查询封装结果 |
一个班级对应多个学生;
- @Data
- public class ClassInfo {
- private Integer classId;
- private String className;
-
- private List
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 | 使用另一个查询封装结果 |
使用动态sql标签
条件判断,动态拼接sql;
一般用于非空验证,不满足条件,if标签里面的代码就不会执行。
一般和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文件中尽量避免直接写 >,<,& 等;
| 特殊符号 | 转义序列 |
| < | < |
| <= | <= |
| > | > |
| >= | >= |
| & | & |
| ' | ' |
| " | " |
备用方式:
含有特殊符号的代码
>
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>
使用循环生成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>
与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>
用于有外键关系的两个表,主表插入数据之后,需要把主表数据的自增值获取到,然后再插入从表的数据时,插入到从表的外键列中;
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>
- <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>
使用嵌套查询实现多表关联,使用嵌套查询的时候会出现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关联查询加载时机:
①直接加载:执行完主对象的查询后,马上执行对关联对象的查询语句;
②侵入式延迟:执行完对主对象的查询后,不会执行对关联对象的查询,但当访问主对象的属性时,就会执行关联对象的查询;
③深度延迟:只有当真正访问关联对象的详情时,才会执行查询语句。
①直接加载(默认)
- <setting name="lazyLoadingEnabled" value="false"/>
- <setting name="aggressiveLazyLoading" value="false"/>
②侵入式延迟:
- <setting name="lazyLoadingEnabled" value="true"/>
- <setting name="aggressiveLazyLoading" value="true"/>
效果:
(访问对象属性时执行关联对象查询)

③深度延迟:
(访问关联对象时执行关联查询)

在关联查询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>