使用MyBatis实现条件查询
1.SQL映射文件:
MyBatis真正的强大之处就在于SQL映射语句,MyBatis专注于SQL,对于开发人员来说也是极大限度的进行SQL调优,以保证性能。下面是SQL映射文件的几个顶级元素的配置:
1.mapper:映射文件的根节点,只有一个属性namespace(命名空间),作用如下:
(1)用于区分不同的mapper,全局唯一。
(2)绑定DAO接口,即面向接口编程,当绑定一个接口,就不用写此接口的实现类,会通过接口的完全限定名找到对应的mapper配置来执行SQL语句,所以,namespace的命名必须要写接口的完全限定名。
2.cache:配置给定命名空间的缓存。
3.cache-ref:从其他命名空间引用缓存配置。
4.resultMap:用来描述数据库结果集和对象的对应关系。
5.sql:可以重用的SQL块,也可以被其他语句引用。
6.insert:映射插入语句。
7.update:更新映射语句。
8.delete:删除映射语句。
9.select:映射查询语句。
2.使用select完成单条件查询
<select id = "GetUserByName" resultType = "User" parameterType = "string">
select * from user where name like concat('%',#{name},'%') //按照姓名模糊查询。
</select>
这是一个id为GetUserByName的映射语句,参数类型为string,返回类型为User。
#{参数名}:告诉MyBatis生成的PreparedStatement参数,相对于JDBC,改参数被标识为‘?’。
id:命名空间的唯一标识符,可以被用来引用这条语句。
parameterType:表示查询语句传入参数的类型和完全限定名或别名。支持基础数据类型和复杂数据类型。上述实例中传入的参数是一个别名,代表String。
别名与Java类型映射
别名 | 映射的类型 | 别名 | 映射的类型 |
string | String | double | Double |
byte | Byte | float | Float |
long | Long | boolean | Boolean |
short | Short | date | Date |
int | Integer | map | Map |
integer | Integer | hashmap | HashMap |
arraylist | ArrayList | list | List |
resultType:查询语句返回结果类型的完全限定名或别名。别名使用方式和parameterType是一样的。
2.使用select完成多条件查询
使用复杂数据类型,把条件参数封装为对象、Map进行入参。
不管什么类型的参数,或者多少个参数,都可以封装为一个Map进行入参,通过Map的key进行获取传入的值。
1 <select id="GetUserByNameAndRoleId" resultType="User" 2 parameterType="map"> 3 select * from smbms_user where userName like 4 CONCAT('%',#{userName},'%') 5 and userRole = #{userRole} 6 </select>
3.使用resultMap完成查询结果的展现
resultMap:做自定义映射,实体类属性名和数据库列名不一致的情况下,并且可以指定要显示的列,使用灵活 应用广泛。
1 <resultMap type="User" id="userMap"> 2 <id column="id" property="id"/> 3 <result column="userName" property="Name"/> //字段名和属性名不一致的情况下。 4 </resultMap>
属性和子节点:
id:唯一标识,此id值用于select元素resultMap属性的引用。
type:标识该resultMap的映射结果类型。
result子节点:标识一些简单属性,其中column属性代表数据库的字段名,property代表查询出来的字段名映射到pojo类的某个属性。
id子节点:与result子节点作用一样,一般表示数据库的主键列。
-------------------------------------------------------------------------------------------------------
resultType和resultMap的对比如下 :
1.resultType:直接表示返回类型, 包括基本数据类型和复杂数据类型。
2.resultMap:外部resultMap定义的引用,通过对应的外部resultMap的id,表示结果映射到哪个resultMap上,一般用于字段名和属性名不一致的情况,或者需要做复杂的联合查询以便自由控制映射结果。
3.两者的关联
当进行查询时,查询出来的每个字段都会放在一个Map里,当查询元素返回属性是resultType的时候,会将键值对取出赋所指定的属性。其实MyBatis的每个查询映射的返回类型都是resultMap,只是当我们使用resultType的时候,会自动把对应的值赋给所指定的对象属性,当使用resultMap时候,因为map不是很好的表示领域,我们就进一步的转化为对应的实体对象。resultMap主要作用于复杂的联合查询上。
注意:resultType和resultMap本质是一样的,都是Map数据结构,但是二者不能同时存在。
4.resultMap的自动映射级别:默认级别为PARTIAL,也可以在settings更改值。
1 <settings> 2 <!-- 设置resultMap的自动映射级别为NONE(禁止自动匹配) --> 3 <setting name = "autoMappingBehavior" value = "NONE"> 4 </settings>
4.使用MyBatis实现增删改操作
1.使用insert完成增加操作
<insert id="add" parameterType="User"> INSERT INTO user(userName,userCode) VALUES(#{userName},#{userCode}) </insert>
2.使用update完成修改操作
<update id="update" parameterType="User"> UPDATE user SET userName= #{userName},userCode= #{userCode} WHERE id = #{id} </update>
3.使用delete完成删除操作
<delete id="User" parameterType="integer"> delete from user where id = #{id}</delete>
元素中的属性:
id:与select元素id一样,命名空间的唯一标识符。
parameterType:传入参数的类型的完全限定名或者别名。
对于增删改操作的注意事项:
(1)该类型的操作本身默认返回执行SQL影响的行数,所以DAO层的接口方法返回值一般为int类型,最好不要boolean类型。
(2)insert、update、delete元素中均没有resultType属性,只有查询操作需要对返回结果类型(resultType/resultMap)进行相应的指定。
使用注解用来传入多个参数,相当于给该参数重命名,在SQL映射文件中需要使用#{注解名称}来传入参数。
public user GetUserByIdAndName(@Param("id") Integer id,@Param("Name") String Name);
当参数为基础类型时,无论是多参数还是单参数,!
使用resultMap实现高级结果映射
1.association:
映射到JavaBean的某个复杂的”数据类型”属性,仅处理一对一的关联关系。
<resultMap type="SMS_USER" id="userMap"> <id column="id" property="id" /> <result column="userName" property="userName" /> <result column="phone" property="phone" /> <association property="role" javaType="SMS_Role"> <id column="id" property="id" /> <result column="roleName" property="roleName" /> </association> </resultMap>
association的属性节点:
property:映射数据库列的实体对象属性名。
javaType:完整的java类名和限定名。propert所映射的属性的类型。
子元素:id:一般为映射主键,可以提高性能。
result:
column:映射的数据库的字段名。
property:映射的数据列对应的实体对象属性。
2.collection:
映射到JavaBean的某个复杂的”数据类型”属性,这个属性是一个集合列表,处理一对多的关联关系。
<resultMap type="SMS_USER" id="userMapAddress"> <id column="id" property="id"/> <result column="userName" property="userName"/> <collection property="lists" ofType="SMS_Address"> <id column = "id" property = "id"> <result column="addressDesc" property="addressDesc"/> </collection> </resultMap>
ofType:完整的java类名和限定名。propert所映射的属性的类型。
其余和association基本一致。
MyBatis缓存
1.一级缓存:基于PerpetualCache(MyBatis自带)的HashMap本地缓存。作用域在Session域内,当session flush或者close之后,该缓存被清空。
2.二级缓存:global Cache,超出session范围之外,可以被所有SqlSession共享。开启它只需在MyBatis的核心配置文件 settings 设置即可。
补充:一级缓存缓存的是SQL语句,二级缓存缓存的是结果对象。
3.二级缓存配置:
(1)开启二级缓存;
<settings> <setting name="cacheEnabled" value = "true"/> <settings>
(2)mapper文件中设置缓存,默认是没有开启缓存的。作用域是针对namespace而言的,只在namespace内的查询才能共享这个cache。
(3)对个别查询进行缓存,单独设置cache:
<select id = "getUser" resultType = "User" useCache = "true"> ........... </select>
补充:对MyBatis的缓存了解就可以了,对结果集做缓存并不是MyBatis所擅长的,而且性能也不是很好,它专心做的应该是SQL映射。
------------------------------------------------------------------------------------------------------------------------------------
动态SQL
一、使用动态SQL完成多条件查询。
动态SQL基于OGNL的表达式,我们可以方便的在SQL语句中实现某些逻辑,用于实现动态SQL元素如下:
if:利用if实现简单的条件选择。
choose(when,otherwise):相当于java中的switch语句,通常与when和otherwise搭配。
set:解决动态更新语句。
trim:灵活的去除多余的关键字。
foreach:迭代一个集合,通常用于in条件。
二、if+where实现多条件查询
<select id="ShowUser" parameterType="Map" resultType="SMS_USER"> select * from smbms_user <where> <if test="userRole != null and userRole != 0"> userRole = #{userRole} </if> <if test="userName != null and userName != ''"> and userName like CONCAT('%',#{userName},'%') </if> </where> </select>
where元素可以智能的处理and 和 or 的多余问题, 不需担心多余关键字导致语法错误。
if元素的test用于判断表达式是否符合,符合则继续拼接SQL语句。
三、if+trim+foreach实现多条件查询
1 <select id="listsByInAndGender" resultType="SMS_USER"> 2 select * from smbms_user 3 <trim prefix="where" prefixOverrides="and | or"> 4 <if test="userIds!=null"> 5 id in 6 <foreach collection="userIds" item="ids" open="(" close=")" separator=","> 7 #{ids} 8 </foreach> 9 </if> 10 <if test="gender != null and gender != 0"> 11 and gender = #{gender} 12 </if> 13 </trim> 14 </select>
(1)trim的属性:
prefix:前缀: 作用是通过自动识别是否有返回值后,在trim包含的内容上加上前缀,如上述示例的where。
suffix:后缀: 作用是在trim包含的内容上加上后缀。
prefixOverrides: 对于trim包含内容的首部进行指定内容,(如上述示例的 and | or) 的忽略(去余);
suffixOverrides: 对于trim包含内容的首位部进行指定内容的忽略。
(2)foreach的属性:
item:表示集合中每一个元素进行迭代时的别名。
index: 指定一个名称,表示在迭代的过程中,每次迭代到的位置。
open:表示该语句以什么开始(既然是in条件语句,必然是 ' ( ' 开始)
separator: 表示每次进行迭代的时候以什么符号作为分隔符(既然是in条件语句,必然是 ' , ' 分隔)
close: 表示该语句以什么结束(既然是in条件语句,必然是 ' ) ' 结束)
collection:最关键,并且最容易出错的属性。需注意,该属性必须指定,不同情况下,该属性值是不同的,主要有三种情况:
若传入的参数是单参数且类型为一个List的时候,属性值为list;
若传入的参数是单参数且类型为一个数组的时候,属性值为array;
若传入的参数为多参数时,就需要封装为一个map集合进行处理。属性值为Map的key;
使用set更新操作,类似于上述示例使用方法:
1 <update id="UpdateUser" parameterType="SMS_USER"> 2 update smbms_user 3 <trim prefix="set" suffixOverrides="," suffix="where id = #{id}"> 4 <if test="userName != null and userName != ''"> 5 userName = #{userName}, 6 </if> 7 <if test="gender != null and gender != 0"> 8 gender = #{gender}, 9 </if> 10 <if test="address != null and address != ''"> 11 address = #{address}, 12 </if> 13 </trim> 14 </update>
三、choose(when、otherwise)
1 <select id="QueryAllByChoose" resultType="SMS_provider"> 2 select * from smbms_provider where 1 = 1 3 <choose> 4 <when test="proCode != null and proCode != ''"> 5 and proCode like CONCAT('%',#{proCode},'%') 6 </when> 7 <when test="proName != null and proName != ''"> 8 and proName like CONCAT('%',#{proName},'%') 9 </when> 10 <when test="proContact != null and proContact != ''"> 11 and proContact like CONCAT('%',#{proContact},'%') 12 </when> 13 <otherwise> 14 and YEAR(creationDate) = 2016 15 </otherwise> 16 </choose> 17 </select>
when元素:当test属性中的条件满足时,就会输出when元素中的内容,并且当when中一旦有条件满足时,就会跳出choose,所以只有一个条件会被输出。
otherwise元素:当when中的所有条件都不满足时,则会输出此元素的内容。
四、MyBatis实现分页功能
1.使用聚合函数获得总记录数-
2.实现分页通过limit(起始位置,页面显示量)
补充:起始位置的下标 = (当前页码 - 1 ) * 页面显示量
1 <!-- 多条件筛选分页 --> 2 <select id="UserPage" parameterType="map" resultType="SMS_USER"> 3 select * from smbms_user 4 <trim prefix="where" prefixOverrides="and | or"> 5 <if test="userName != null and userName != ''"> 6 userName like concat('%',#{userName},'%') 7 </if> 8 <if test="userRole != null and userRole != 0"> 9 and userRole = #{userRole} 10 </if> 11 </trim> 12 limit #{startRow},#{pageSize} 13 </select>