关系型数据库和SQL是经受时间考验和验证的数据存储机制。和其他的ORM框架如Hibernate不同,MyBatis鼓励开发者可以直接使用数据库,而不是将其对开发者隐藏,因为这样可以充分发挥数据库服务器所提供的SQL语句的巨大威力。与此同时,MyBaits消除了书写大量冗余代码的痛苦,它让使用SQL更容易。在代码里直接嵌套SQL语句是很差的编码实践,并且维护起来困难。MyBaits使用了映射文件或注解来配置SQL语句。
一、 select 查询元素
select 主要要来做查询使用
<sql id="Base_Column_List">
id, user_name, real_name, sex, mobile, email, note,position_id
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer">
select
<include refid="Base_Column_List" />
from t_user
where id = #{id,jdbcType=INTEGER}
</select>
自动映射
前提:SQL列名和JavaBean的属性是一致的;
自动映射等级autoMappingBehavior设置为PARTIAL,需要谨慎使用FULL;
使用resultType;
如果列名和JavaBean不一致,但列名符合单词下划线分割,Java是驼峰命名法,
则mapUnderscoreToCamelCase可设置为true;
传递多个查询入参
使用map传递参数;可读性差,导致可维护性和可扩展性差,杜绝使用;
使用注解传递参数;直观明了,当参数较少一般小于5个的时候,建议使用;
使用Java Bean的方式传递参数;当参数大于5个的时候,建议使用;
如:
/**
* 是map作为入参
* 使用map传递参数;可读性差,导致可维护性和可扩展性差,不建议这样使用
* @param param
* @return
*/
List<TUser> selectByEmailAndSex1(Map<String, Object> param);
/**
*使用注解传递参数;直观明了,当参数较少一般小于5个的时候,建议使用
* @param email
* @param sex
* @return
*/
List<TUser> selectByEmailAndSex2(@Param("email") String email, @Param("sex") Byte sex);
/**
* 使用Java Bean的方式传递参数;当参数大于5个的时候,建议使用
* @param esb
* @return
*/
List<TUser> selectByEmailAndSex3(EmailSexBean esb);
mapper 中对应:
<select id="selectByEmailAndSex1" resultMap="BaseResultMap" parameterType="map">
select
id, user_name, real_name, sex, mobile, email, note,position_id
from t_user a
where a.email like CONCAT('%', #{email}, '%') and
a.sex = #{sex}
</select>
<select id="selectByEmailAndSex2" resultMap="BaseResultMap">
select
id, user_name, real_name, sex, mobile, email, note,position_id
from t_user a
where a.email like CONCAT('%', #{email}, '%') and
a.sex = #{sex}
</select>
<select id="selectByEmailAndSex3" resultMap="BaseResultMap"
parameterType="com.study.mybatis.entity.EmailSexBean">
select
id, user_name, real_name, sex, mobile, email, note,position_id
from t_user a
where a.email like CONCAT('%', #{email}, '%') and
a.sex = #{sex}
</select>
二 resultMap元素 属性
resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出
来,在对复杂语句进行联合映射的时候,它很可能可以代替数千行的同等功能的代码。
ResultMap 的设计思想是,简单的语句不需要明确的结果映射,而复杂一点的语句只需要描述它们的关系就行了。
<resultMap id="BaseResultMap" type="com.study.mybatis.entity.TUser">
<!-- <constructor>
<idArg column="id" javaType="int"/>
<arg column="user_name" javaType="String"/>
</constructor> -->
<id column="id" property="id" jdbcType="INTEGER" />
<result column="user_name" property="userName" jdbcType="VARCHAR" />
<result column="real_name" property="realName" jdbcType="VARCHAR" />
<result column="sex" property="sex" jdbcType="TINYINT" />
<result column="mobile" property="mobile" jdbcType="VARCHAR" />
<result column="email" property="email" jdbcType="VARCHAR" />
<result column="note" property="note" jdbcType="VARCHAR" />
<result column="position_id" property="positionId" jdbcType="INTEGER" />
</resultMap>
<!--可以继承-->
<resultMap id="userAndJobs2" extends="BaseResultMap" type="TUser">
<collection property="jobs" fetchType="lazy" column="id"
select="com.enjoylearning.mybatis.mapper.TJobHistoryMapper.selectByUserId" />
</resultMap>
2.1 resultMap子属性
2.2 id & result
id 和 result 都将一个列的值映射到一个简单数据类型(字符串,整型,双精度浮点数,日期等)的属性或字段。
两者之间的唯一不同是, id 表示的结果将是对象的标识属性,这会在比较对象实例时用到。 这样可以
提高整体的性能,尤其是缓存和嵌套结果映射(也就是联合映射)的时候。
2.3 constructor
一个pojo不存在没有参数的构造方法,就需要使用constructor;
为了通过名称来引用构造方法参数,你可以添加 @Param 注解,指定参数名称的前提下,以任意顺序编写
arg 元素
三 insert, update 和 delete
主要做数据增删改使用
3.1 selectKey元素
3.2 sql元素和参数
四、注解方式配置
@Results(id="jobInfo",value={
@Result(property="id",column="id",id = true),
@Result(property="userId",column="user_id"),
@Result(property="compName",column="comp_name"),
@Result(property="years",column="years"),
@Result(property="title",column="title")
})
@Select("select id, user_id, comp_name, years, title from t_job_history"
+ " where user_id = #{userId}")
List<TJobHistory> selectByUserId(int userId);
@ResultMap("jobInfo")
@Select("select id, user_id, comp_name, years, title from t_job_history")
List<TJobHistory> selectAll();
@Insert("insert into t_job_history (id, user_id, comp_name, years, title)"
+ " values (#{id,jdbcType=INTEGER}, #{userId,jdbcType=INTEGER},"
+ "#{compName,jdbcType=VARCHAR},"
+ "#{years,jdbcType=INTEGER}, #{title,jdbcType=VARCHAR})")
@Options(useGeneratedKeys=true,keyProperty="id")
int insert(TJobHistory record);
五 动态sql元素
5.1 if 标签
if 标签通常用于 WHERE 语句、UPDATE 语句、INSERT 语句中,通过判断参数值来决定是否使用某个查询条件、判断是否更新某一个字段、判断是否插入某个字段的值。
<select id="selectIfandWhereOper" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from t_user a
<where>
<if test="email != null and email != ''">
and a.email like CONCAT('%', #{email}, '%')
</if>
<if test="sex != null ">
and a.sex = #{sex}
</if>
</where>
</select>
5.2 where 标签
当 if 标签较多时,这样的组合可能会导致错误。 如下:
<select id="getStudentListWhere" parameterType="Object" resultMap="BaseResultMap">
SELECT * from STUDENT WHERE
<if test="name!=null and name!='' ">
NAME LIKE CONCAT(CONCAT('%', #{name}),'%')
</if>
<if test="hobby!= null and hobby!= '' ">
AND hobby = #{hobby}
</if>
</select>
当 name 值为 null 时,查询语句会出现 “WHERE AND” 的情况,解决该情况除了将"WHERE"改为“WHERE 1=1”之外,还可以利用 where
标签。这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以 AND 或 OR 开头的,则它会剔除掉。
<select id="getStudentListWhere" parameterType="Object" resultMap="BaseResultMap">
SELECT * from STUDENT
<where>
<if test="name!=null and name!='' ">
NAME LIKE CONCAT(CONCAT('%', #{name}),'%')
</if>
<if test="hobby!= null and hobby!= '' ">
AND hobby = #{hobby}
</if>
</where>
</select>
5.3 set 标签
没有使用 if 标签时,如果有一个参数为 null,都会导致错误。当在 update 语句中使用 if 标签时,如果最后的 if 没有执行,则或导致逗号多余错误。使用 set 标签可以将动态的配置 set
关键字,和剔除追加到条件末尾的任何不相关的逗号。
<update id="updateStudent" parameterType="Object">
UPDATE STUDENT SET
<if test="name!=null and name!='' ">
NAME = #{name},
</if>
<if test="hobby!=null and hobby!='' ">
MAJOR = #{major},
</if>
<if test="hobby!=null and hobby!='' ">
HOBBY = #{hobby}
</if>
WHERE ID = #{id};
</update>
使用 set+if 标签修改后,如果某项为 null 则不进行更新,而是保持数据库原值。
<update id="updateStudent" parameterType="Object">
UPDATE STUDENT
<set>
<if test="name!=null and name!='' ">
NAME = #{name},
</if>
<if test="hobby!=null and hobby!='' ">
MAJOR = #{major},
</if>
<if test="hobby!=null and hobby!='' ">
HOBBY = #{hobby}
</if>
</set>
WHERE ID = #{id};
</update>
5.4 foreach 标签
foreach 标签主要用于构建 in 条件,可在 sql 中对集合进行迭代。也常用到批量删除、添加等操作中。
<!-- in查询所有,不分页 -->
<select id="selectIn" resultMap="BaseResultMap">
select name,hobby from student where id in
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
</select>
属性介绍:
collection:collection 属性的值有三个分别是 list、array、map 三种,分别对应的参数类型为:List、数组、map 集合。
item :表示在迭代过程中每一个元素的别名
index :表示在迭代过程中每次迭代到的位置(下标)
open :前缀
close :后缀
separator :分隔符,表示迭代时每个元素之间以什么分隔
5.5 choose 标签
有时候我们并不想应用所有的条件,而只是想从多个选项中选择一个。MyBatis 提供了 choose 元素,按顺序判断 when 中的条件出否成立,如果有一个成立,则 choose 结束。当 choose 中所有 when
的条件都不满则时,则执行 otherwise 中的 sql。类似于 Java 的 switch 语句,choose 为 switch,when 为 case,otherwise 则为 default。
if 是与(and)的关系,而 choose 是或(or)的关系。
<select id="getStudentListChoose" parameterType="Student" resultMap="BaseResultMap">
SELECT * from STUDENT WHERE 1=1
<where>
<choose>
<when test="Name!=null and student!='' ">
AND name LIKE CONCAT(CONCAT('%', #{student}),'%')
</when>
<when test="hobby!= null and hobby!= '' ">
AND hobby = #{hobby}
</when>
<otherwise>
AND AGE = 15
</otherwise>
</choose>
</where>
</select>
5.6trim标签
trim元素的主要功能是可以在自己包含的内容前加上某些前缀,也可以在其后加上某些后缀,与之对应的属性是prefix和suffix;可以把包含内容的首部某些内容覆盖,即忽略,也可以把尾部的某些内容覆盖,对应的属性是prefixOverrides和suffixOverrides。正因为trim有这样的功能,所以我们也可以非常简单的利用trim来代替where/set标签的功能,示例代码如下:
trim代替where标签:
<!-- 5.1 if/trim代替where(判断参数) - 将实体类不为空的属性作为where条件 -->
<select id="getStudentList_if_trim" resultMap="resultMap_studentEntity">
SELECT ST.STUDENT_ID,
ST.STUDENT_NAME,
ST.STUDENT_SEX,
ST.STUDENT_BIRTHDAY,
ST.STUDENT_PHOTO,
ST.CLASS_ID,
ST.PLACE_ID
FROM STUDENT_TBL ST
<trim prefix="WHERE" prefixOverrides="AND|OR">
<if test="studentName !=null ">
ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName, jdbcType=VARCHAR}),'%')
</if>
<if test="studentSex != null and studentSex != '' ">
AND ST.STUDENT_SEX = #{studentSex, jdbcType=INTEGER}
</if>
<if test="studentBirthday != null ">
AND ST.STUDENT_BIRTHDAY = #{studentBirthday, jdbcType=DATE}
</if>
<if test="classId != null and classId!= '' ">
AND ST.CLASS_ID = #{classId, jdbcType=VARCHAR}
</if>
<if test="classEntity != null and classEntity.classId !=null and classEntity.classId !=' ' ">
AND ST.CLASS_ID = #{classEntity.classId, jdbcType=VARCHAR}
</if>
<if test="placeId != null and placeId != '' ">
AND ST.PLACE_ID = #{placeId, jdbcType=VARCHAR}
</if>
<if test="placeEntity != null and placeEntity.placeId != null and placeEntity.placeId != '' ">
AND ST.PLACE_ID = #{placeEntity.placeId, jdbcType=VARCHAR}
</if>
<if test="studentId != null and studentId != '' ">
AND ST.STUDENT_ID = #{studentId, jdbcType=VARCHAR}
</if>
</trim>
</select>
trim代替set标签
<!-- 5.2 if/trim代替set(判断参数) - 将实体类不为空的属性更新 -->
<update id="updateStudent_if_trim" parameterType="liming.student.manager.data.model.StudentEntity">
UPDATE STUDENT_TBL
<trim prefix="SET" suffixOverrides=",">
<if test="studentName != null and studentName != '' ">
STUDENT_TBL.STUDENT_NAME = #{studentName},
</if>
<if test="studentSex != null and studentSex != '' ">
STUDENT_TBL.STUDENT_SEX = #{studentSex},
</if>
<if test="studentBirthday != null ">
STUDENT_TBL.STUDENT_BIRTHDAY = #{studentBirthday},
</if>
<if test="studentPhoto != null ">
STUDENT_TBL.STUDENT_PHOTO = #{studentPhoto, javaType=byte[], jdbcType=BLOB, typeHandler=org.apache.ibatis.type.BlobTypeHandler},
</if>
<if test="classId != '' ">
STUDENT_TBL.CLASS_ID = #{classId},
</if>
<if test="placeId != '' ">
STUDENT_TBL.PLACE_ID = #{placeId}
</if>
</trim>
WHERE STUDENT_TBL.STUDENT_ID = #{studentId}
</update>