MyBatis的学习重点在于Mapper XML映射文件。
1. select 查询语句标签
2. insert 插入语句标签
3. update 更新语句标签
4. delete 删除语句标签
5. sql 被其他语句引用标签
6. cache 给定命名空间做缓存配置标签
7. cache-ref 其他命名空间缓存配置的引用标签
8. resultMap 如何从数据库结果集中加载对象标签
接下来,我们先学习一个<select>如何使用
这个 <select>标签用来映射查询语句,下面是一个简单的查询示例:
<select id="selectStudentInfo" parameterType="int" resultType="com.demo.data.StudentData">
SELECT * FROM STUDENT_INFO WHERE stu_id = #{id}
</select>
上面的SQL映射的id是 “selectStudentInfo”,它接受一个int类型的参数,并返回一个StudentData对象。注意参数符号 “#{id}” ,这是告诉MyBatis创建一个预处理语句参数,相当于JDBC中的占位符“?”。但是,这里存在一个问题,就是表字段到类变量的对应关系。在MyBatis中,只有字段名和类变量名保持一致,才能够正确匹配,才能将结果集中的数据正确的赋值到 StudentData 对象上面。我们在之前演示案例的时候,就使用Map作为返回类型了。但是,我们在使用Map输出数据的时候,就必须使用数据表中的原始字段名称。但是,我们的表字段名和StudentInfo 类变量名是不一样的,例如表字段 “user_name” 对应的类变量名为 “userName”。在Spring JDBC中可以正确识别,但是在MyBatis中不行。当然,我们可以手动进行配置,如下所示
<resultMap id="StudentDataResultMap" type="com.demo.data.StudentData">
<id property="stuId" column="stu_id" />
<result property="classId" column="class_id" />
<result property="stuName" column="stu_name" />
<result property="stuAge" column="stu_age" />
<result property="stuSex" column="stu_sex" />
<result property="addTime" column="add_time" />
</resultMap>
<select id="queryStudentList" resultMap="StudentDataResultMap">
SELECT * FROM `student_info` ORDER BY `stu_id` ASC
</select>
我们使用<resultMap>来完成属性字段映射配置,id代表本次映射的唯一标识,可以被其他标签引用。type则是我们之前创建的 StudentData 数据类对象。然后property是数据类中的属性变量,column则是表字段名称,普通字段使用<result>配置即可,主键请使用<id>来配置。有的同学可能会疑问,怎么没有配置表名的位置?我们的映射只是用来配置返回结果集里面的字段,并不是针对某张数据表来做配置的。虽然我们在创建 StudentData 类的时候,确实是根据 "student_info" 表结构来创建的,但是我们不会根据 "student_info" 表来配置它的映射,这一点大家一定要注意了。手动映射完毕后,在<select>中可以使用“resultMap”来引用定义好的映射规则,其值就是我们<resultMap>中id唯一标识。接下来,我们看看<select>的完整属性,如下
<select
id="queryStudentInfo" //唯一标识符
parameterType="int" //输入参数类型,没有输入参数就不用设置
resultType="java.util.Map" //返回结果类型,不能与下面的resultMap同时使用
resultMap="StudentDataResultMap" //外部resultMap引用,不能与上面的resultType同时使用
flushCache="false" //是否刷新缓存,默认为false
useCache="true" //是否使用缓存,默认为true
timeout="10" //等待数据库返回请求结果的秒数,默认unset
fetchSize="100" //尝试影响每次查询结果行数和这个设置值相等
statementType="PREPARED" //是否预编译,默认就是PREPARED(使用预编译语句)
resultSetType="FORWARD_ONLY"> //结果集的类型,默认值为unset
接下来,我们做一个复杂的查询,使用一个java类来提供一个查询参数。
我们使用上一个章节的工程 “SpringBootMyBatisDemo” 来演示。
上一个章节地址为: 第05章 SpringBoot集成MyBatis
关于“student”数据库的内容请参考: https://blog.youkuaiyun.com/richieandndsc/article/details/142763743
package com.demo.data;
public class StudentRequest {
private String name;
private Integer age;
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;
}
}
我们提供按照name=姓名,age=年龄进行查询
StudentData queryStudentByCondition(StudentRequest request);
在 “StudentMapper.java” 接口中增加抽象方法 “queryStudentByCondition”
<select id="queryStudentByCondition" parameterType="com.demo.data.StudentRequest" resultMap="StudentDataResultMap">
SELECT * FROM `student_info` WHERE 1 = 1
<if test="name != ''">and stu_name = #{name}</if>
<if test="age > 0">and stu_age = #{age}</if>
ORDER BY stu_id ASC LIMIT 0,1
</select>
在 “StudentMapper.xml” 中增加 SQL 语句,其中<if test="xxx">用于属性变量判空的操作。上面两个条件参数 #{name} 和 #{age} 是通过Java数据对象传入的,当然也可以通过Map传入。在实际项目开发中,经常需要根据不同条件拼接SQL语句,拼接时候还要确保不能忘了必要的空格,有时候还要注意最后的逗号等等。MyBatis的动态SQL可以解决这个问题。常用的动态SQL标签包括:if, choose, when, set, foreach, bind。
接下来,我们在 “StudentController” 中补全调用
@RequestMapping("/search")
public String search(StudentRequest request, Map<String, Object> map){
StudentData info = studentMapper.queryStudentByCondition(request);
map.put("info", info);
return "student";
}
接下来继续补全 “index.html” 和 "student.html" 中内容
<a href="/student">student</a>
<br />
<a href="/studentinfo?id=1">studentinfo?id=1</a>
<br />
<a href="/studentmap?id=1">studentmap?id=1</a>
<br />
<a href="/search?name=小明">search?name=小明</a>
由于我们传递给 "student.html" 就是 “StudentData” 对象,因此不需要修改 "student.html" 了。
我们重新运行,测试一下
接下来是<insert>标签的使用
<insert
id="insertStudentData" // 唯一标识符
parameterType="xxxxxx" // 输入参数类型
keyProperty="" // 主键属性名(类变量名),下面的二选一就行
keyColumn="" // 主键字段名,上面的二选一就行
useGeneratedKeys="true" // 使用数据库生成主键(主键自增的情况)
flushCache="true" // 是否刷新缓存,默认为false
statementType="PREPARED" // 是否预编译,默认就是PREPARED(使用预编译语句)
timeout="10"> // 等待数据库返回请求结果的秒数,默认unset
在插入语句执行时候需要返回插入成功的数据生成的主键值。所以<insert>元素里面有一些额外的属性和子元素用来处理主键的生成,而且根据数据库的主键生成策略不同,配置也有多种方式。如果数据库支持自动生成主键的字段,那么就可以设置 useGeneratedKeys=”true”,然后在再把 keyProperty 设置到目标属性上就可以了。添加该属性之后并非改变insert方法的返回值,也就是说,该方法还是返回新增的结果。而如果需要获取新增行的主键ID,直接使用传入的实体对象的主键对应属性的值就行了。接下来,我们演示一下<insert>的使用
int insertStudentData(StudentData data);
在 “StudentMapper.java” 接口中增加抽象方法 “insertStudentData”
<insert id="insertStudentData" parameterType="com.demo.data.StudentData" useGeneratedKeys="true" keyProperty="stuId">
INSERT INTO STUDENT_INFO(stu_name, stu_age, add_time) VALUES (#{stuName}, #{stuAge}, #{addTime})
</insert>
在 “StudentMapper.xml” 中增加 SQL 语句。上面的id就不解释了,parameterType是传入参数类型,我们直接传入StudentData对象即可,在SQL语句中,我们可以使用 “#{stuName}” 方式直接使用里面的属性变量即可。接下来的useGeneratedKeys="true" 说明我们由数据库来生成主键,且主键对应的属性名为keyProperty="stuId"。也就是说,我们执行完插入语句后,可以直接获取StudentData对象的stuId属性变量就会得到刚刚新添加的新记录的主键ID了。
接下来,我们在 “StudentController” 中补全调用
@RequestMapping("/add")
public String add(Map<String, Object> map){
StudentData data = new StudentData();
data.setStuName("阿华");
data.setStuAge(20);
data.setAddTime("2011-03-01 09:00:00");
int res = studentMapper.insertStudentData(data);
System.out.println("res=" + res);
map.put("info", data);
return "student";
}
接下来继续补全 “index.html” 和 "student.html" 中内容
<a href="/student">student</a>
<br />
<a href="/studentinfo?id=1">studentinfo?id=1</a>
<br />
<a href="/studentmap?id=1">studentmap?id=1</a>
<br />
<a href="/search?name=小明">search?name=小明</a>
<br />
<a href="/add">add</a>
由于我们传递给 "student.html" 就是 “StudentData” 对象,因此不需要修改 "student.html" 了。
我们重新运行,测试一下
我们去数据库中核实一下主键ID
我们去控制台查看输出日志
接下来我们介绍<update>标签的使用
<update
id="updateStudentData" // 唯一标识符
parameterType="xxxxxx" // 输入参数类型
flushCache="true" // 是否刷新缓存,默认为false
statementType="PREPARED" // 是否预编译,默认就是PREPARED(使用预编译语句)
timeout="10"> // 等待数据库返回请求结果的秒数,默认unset
我们直接添加代码测试吧
int updateStudentData(StudentData data);
在 “StudentMapper.java” 接口中增加抽象方法 “updateStudentData”
<update id="updateStudentData" parameterType="com.demo.data.StudentData">
UPDATE STUDENT_INFO SET stu_name = #{stuName}, stu_age = #{stuAge} WHERE stu_id = #{stuId}
</update>
在 “StudentMapper.xml” 中增加 SQL 语句。
接下来,我们在 “StudentController” 中补全调用
@RequestMapping("/edit")
public String edit(Map<String, Object> map){
StudentData data = new StudentData();
data.setStuId(9);
data.setStuName("张三");
data.setStuAge(25);
data.setAddTime("2022-02-01 09:00:00");
int res = studentMapper.updateStudentData(data);
System.out.println("res=" + res);
map.put("info", data);
return "student";
}
接下来继续补全 “index.html” 和 "student.html" 中内容
<a href="/student">student</a>
<br />
<a href="/studentinfo?id=1">studentinfo?id=1</a>
<br />
<a href="/studentmap?id=1">studentmap?id=1</a>
<br />
<a href="/search?name=小明">search?name=小明</a>
<br />
<a href="/add">add</a>
<br />
<a href="/edit">edit</a>
由于我们传递给 "student.html" 就是 “StudentData” 对象,因此不需要修改 "student.html" 了。
我们重新运行,测试一下
我们去数据库里面核实一下
接下来介绍<delete>的使用方式
<delete
id="delStudentData" // 唯一标识符
parameterType="xxxxxx" // 输入参数类型
flushCache="true" // 是否刷新缓存,默认为false
statementType="PREPARED" // 是否预编译,默认就是PREPARED(使用预编译语句)
timeout="10"> // 等待数据库返回请求结果的秒数,默认unset
我们直接使用代码测试
int delStudentData(int id);
在 “StudentMapper.java” 接口中增加抽象方法 “delStudentData”
<delete id="delStudentData" parameterType="int">
DELETE FROM STUDENT_INFO WHERE stu_id = #{id}
</delete>
在 “StudentMapper.xml” 中增加 SQL 语句。
接下来,我们在 “StudentController” 中补全调用。
@RequestMapping("/del")
public String del(Map<String, Object> map){
int res = studentMapper.delStudentData(9);
System.out.println("res=" + res);
map.put("info", null);
return "student";
}
因为是删除,所以我们向视图传递了null对象。
接下来继续补全 “index.html” 和 "student.html" 中内容
<a href="/student">student</a>
<br />
<a href="/studentinfo?id=1">studentinfo?id=1</a>
<br />
<a href="/studentmap?id=1">studentmap?id=1</a>
<br />
<a href="/search?name=小明">search?name=小明</a>
<br />
<a href="/add">add</a>
<br />
<a href="/edit">edit</a>
<br />
<a href="/del">del</a>
由于我们传递给 "student.html" 就是 “StudentData” null 对象,因此不需要修改 "student.html" 了。
我们重新运行,测试一下
因为是null对象,所以没有显示任何数据,我们再去数据库核实一下
刚刚写入进去的“id=9”的记录被成功删除掉了。
未完待续。
完整 “SpringBootMyBatisDemo” 工程文件下载: https://download.youkuaiyun.com/download/richieandndsc/89888983