第06章 SpringBoot集成MyBatis(2)

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值