sql映射文件
mybatis最强大的低于就在于sql映射语句,mybatis专注于sql,对于开发人员来说,可以最大限度地调优,保证性能。
1.Mapper:映射文件的根节点,只有一个属性namespace(命名空间)
作用:(1)用于区分不同的mapper,全局唯一。
(2)绑定Dao接口,即面向接口编程,当绑定一个接口,就不需要编写该接口的实现类,会通过接口的完全限
定名找到对应的 mapper配置来执行sql语句,所以namspqce必须要先接口的完全限定名。
2.cache:配置给定命名空间的缓存。
3.cache-ref:从其他命名空间引用缓存配置。
4.resultMap:用来描述数据库结果集和对象的对应关系。
5.sql:可以重用的sql快,可以被其他语句使用。
6..insert:映射插入语句。
7.update:更新映射语句。
8.delete:删除映射语句。
9.select:映射查询语句。
使用select完成单条件查询
<!--传入实体类参数时最好不要写parameterType=“实体类路径”,更不要写mybatis不用的parameterMap,会报错的。不写的话只要mapper接口中传入此类,mybatis会自动处理传参,可以直接使用里面的属性值。-->
<select id = "getUser" resultType = "User" parameterType = "string">
select * from user where name like concat('%',#{name},'%') //按照姓名模糊查询。
</select>
id为GetUserByName的映射语句,参数类型为String,返回类型为User。
1.#{参数名}:告诉MyBatis生成的PreparedStatement参数,相对于JDBC,该参数被标识为‘?’。
2.id:命名空间的唯一标识符,可以被用来引用这条语句。
3.parameterType:查询语句传入的参数类型和完全限定名或者别名,支持基础数据类型和复杂数据类型,上述传入的
参数是个别名,代表Sting。
别名 | 映射类型 | 别名 | 映射类型 |
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 |
4.resultType:查询语句结果返回类型完全限定名或者别名。别名使用方式跟parameterType一样。
使用select完成多条件查询
使用复杂数据类型,把条件参数封装为对象、Map进行入参。不管什么类型的参数,或者多少个参数,都可以封装为
一个Map进行入参,通过map的key或者传入的参值。
<select id="getUser" resultType="User" parameterType="map">
select * from user where userName like CONCAT('%',#{name},'%') and age= #{age}
</select>
使用resultMap完成查询结果的展现
resultMap:做自定义映射,实体类属性名和数据库列名不一致的情况下,并且可以指定要显示的列,使用灵活,应用广
泛。
实体类 User.xml
package com.mybatis.usermanage.entity;
public class User {
private Integer id;
private String name;
private Integer age;
//一对一查询使用
private School school;
//一对多查询使用
private set<Furniture> furnitureSet = new HashSet<Furniture>();
public User() {
super();
}
public User(Integer id,String name, Integer age,School school) {
super();
this.id = id;
this.name = name;
this.age = age;
this.school=school;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age
+ ", school=" + school.toString() + "]";
}
}
映射配置
<!--resultMap标签的作用是,当实体类中的属性与数据库中的表字段不一致时可以通过该标签来进行映射 --><!--id自定义,在select的resultMap属性中使用,type表示map中的value类型 -->
<resultMap id="userMaps" type="com.mybatis.usermanage.entity.User">
<id column="id" property="id"/>
<!-- 使用result来映射需要映射的字段,column表示表字段,property表示实体类属性 -->
<result column="userName" property="Name"/>
</resultMap>
<id表示接口方法,resultMap上面resultMap标签的id>
<select id="userMap" resultMap="userMaps">
select * from user
</select>
属性和子节点:
id:唯一标识,此id值用于select元素resultMap属性的引用。
type:标识该resultMap的映射结果类型。
result子节点:标识一些简单属性,其中column属性代表数据库的字段名,property代表查询出来的字段名映射到
pojo类的某个属性。
id子节点:与result子节点作用一样,一般表示数据库的主键列。
resultType和resultMap的对比如下 :
1.resultType:直接表示返回类型, 包括基本数据类型和复杂数据类型。
2.resultMap:外部resultMap定义的引用,通过对应的外部resultMap的id,表示结果映射到哪个resultMap上,一
般用于字段名和属性名不一致的情况,或者需要做复杂的联合查询以便自由控制映射结果。
对于同级的resultMap可以通过继承extends的形式进行复用,具体见
https://blog.youkuaiyun.com/xiaoqiangyonghu/article/details/80055138
3.两者的关联
当进行查询时,查询出来的每个字段都会放在一个Map里,当查询元素返回属性是resultType的时候,会将键值
对取出赋所指定的属性。其实MyBatis的每个查询映射的返回类型都是resultMap,只是当我们使用resultType的
时候,会自动把对应的值赋给所指定的对象属性,当使用resultMap时候,因为map不是很好的表示领域,我们就
进一步的转化为对应的实体对象。resultMap主要作用于复杂的联合查询上。
注意:resultType和resultMap本质上是一样的,都是Map数据结构,但是二者不能同时存在。
4.resultMap的自动映射级别:默认级别为partial,也可以在settings更改值。
<settings>
<!-- 设置resultMap的自动映射级别为NONE(禁止自动匹配) -->
<setting name = "autoMappingBehavior" value = "NONE">
</settings>
使用MyBatis实现增删改操作
1.使用insert完成增加操作
<insert id="add" parameterType="User">
INSERT INTO user(name,age) VALUES(#{name},#{age})
</insert>
2.使用update完成修改操作
<update id="update" parameterType="User">
UPDATE user SET name= #{name},age= #{age} 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)
进行相应的指定。
使用resultMap实现高级结果映射
1.assocation:
映射到javaBean的某个复杂的“数据类型”属性,仅处理一对一的关联关系。(school中的信息与user中是一对一关
系)
实体类 School.java User.java见上
package com.mybatis.usermanage.entity;
public class School {
private Integer id;
private String schoolName;
private String profession;
private String className;
private Integer userId;
public School() {
super();
}
public School(Integer id, String schoolName, String profession,
String className,Integer userId) {
super();
this.id = id;
this.schoolName = schoolName;
this.profession = profession;
this.className = className;
this.userId = userId;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
public String getProfession() {
return profession;
}
public void setProfession(String profession) {
this.profession = profession;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
@Override
public String toString() {
return "School [id=" + id + ", schoolName=" + schoolName
+ ", profession=" + profession + ", className=" + className
+", userId=" + userId + "]";
}
}
<!--一对一联合查询-->
<resultMap id="schoolMaps" type="com.mybatis.usermanage.entity.User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<association标签用于映射查询副表数据,property对应主实体类中的的属性名,javaType对应该
副实体类全称类名>
<association property="school" javaType="com.mybatis.usermanage.entity.School">
<id property="id" column="id"/>
<result property="profession" column="profession"/>
<result property="schoolName" column="school_name"/>
<result property="className" column="class_name"/>
<result property="userId" column="user_id"/>
</association>
</resultMap>
<id表示接口方法,resultMap上面resultMap标签的id>
<select id="schoolMap" resultMap="schoolMaps">
select * from user u,school s where u.id=s.user_id and u.name=#{name}
</select>
association的属性节点:
property:映射数据库列的实体对象属性名。
javaType:完整的java类名和限定名。
property: 所映射的属性的类型。
子元素:id:一般为映射主键,可以提高性能。
result:
column:映射的数据库的字段名。
property:映射的数据列对应的实体对象属性。
2.collection:
映射到JavaBean的某个复杂的“数据类型”的属性,这个属性是一个集合列表,处理一对多的关联关系。
<resultMap id="furnitureMaps" type="com.mybatis.usermanage.entity.User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<collection property="furnitureSet" ofType="com.mybatis.usermanage.entity.Furniture">
<!-- 如果两表联查,主表和明细表的主键都是id的话,明细表的多条只能查询出来第一条,因此要将
furniture表的主键字段名Id另取名-->
<id property="id" column="furniture_id"/>
<result property="userId" column="user_id"/>
<result property="furnitureName" column="furniture_name"/>
</collection>
</resultMap>
<select id="furnitureMap" resultMap="furnitureMaps">
select * from user u,furniture f where u.id=f.user_id and u.name=#{name}
</select>
ofType:完整的java类名和限定名。
property:所映射的属性的类型。
其余和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="getUser" parameterType="Map" resultType="user">
select * from user
<where>
<if test="age!= null and age!= 0">
name = #{age}
</if>
<if test="name != null and name != ''">
and name like CONCAT('%',#{name},'%')
</if>
</where>
</select>
where元素可以智能的处理and 和 or 的多余问题, 不需担心多余关键字导致语法错误。
if元素的test用于判断表达式是否符合,符合则继续拼接SQL语句。
三、if+trim+foreach实现多条件查询
<select id="getUser" resultType="user">
select * from user
<trim prefix="where" prefixOverrides="and | or">
<if test="id!=null">
id in
<foreach collection="userIds" item="ids" open="(" close=")" separator=",">
#{ids}
</foreach>
</if>
<if test="age!= null and age!= 0">
and age= #{age}
</if>
</trim>
</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更新操作,类似于上述示例使用方法:
<update id="UpdateUser" parameterType="user">
update user
<trim prefix="set" suffixOverrides="," suffix="where id = #{id}">
<if test="name != null and name != ''">
name = #{name},
</if>
<if test="age!= null and age!= 0">
age= #{age}
</if>
</trim>
</update>
三、choose(when、otherwise)
<select id="getUser" resultType="user">
select * from user where 1 = 1
<choose>
<when test="name!= null and name!= ''">
and name like CONCAT('%',#{name},'%')
</when>
<when test="age!= null and proContact != 0">
and age=#{age}
</when>
<otherwise>
and id = 2016
</otherwise>
</choose>
</select>
when元素:当test属性中的条件满足时,就会输出when元素中的内容,并且当when中一旦有条件满足时,就会跳
出choose,所以只有一个条件会被输出。
otherwise元素:当when中的所有条件都不满足时,则会输出此元素的内容。
四、MyBatis实现分页功能
1.使用聚合函数获得总记录数-
2.实现分页通过limit(起始位置,页面显示量)
补充:起始位置的下标 = (当前页码 - 1 ) * 页面显示量
<!-- 多条件筛选分页 -->
<select id="UserPage" parameterType="map" resultType="user">
select * from user
<trim prefix="where" prefixOverrides="and | or">
<if test="name != null and name!= ''">
name like concat('%',#{name},'%')
</if>
<if test="age!= null and age!= 0">
and age= #{age}
</if>
</trim>
limit #{startRow},#{pageSize}
</select>