MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
在SpringBoot框架的基础之上导入相关启动器依赖
1 2 3 4 5 6 7 8 9 10 11
| <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter-test</artifactId> <version>3.0.2</version> <scope>test</scope> </dependency>
|
在 application.yml中简单配置数据库地址池与Mybatis
1 2 3 4 5 6 7 8 9 10 11 12
| spring: datasource: url: jdbc:mysql://localhost:3306/mysql?useUnicode=true&characterEncoding=utf-8 username: root password: root
# MyBatis mybatis: # 实体类包路径 typeAliasesPackage: com.example.**.entity # mapper.xml 文件地址 mapperLocations: classpath*:mapper/**/*Mapper.xml
|
创建实体类
1 2 3 4 5 6 7
| public class Student { private Integer id; private String name; private String age; private String address; }
|
mapper接口创建
1 2 3 4 5 6
| public interface StudentMapper { public int insertName(); public int deleteinfo(); public int updateName(); public Student selectName(); }
|
在resources下创建Mapper.StudentMapper.xml文件
导入Mybatis头文件
1 2 3 4
| <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
书写标签,namespace用于绑定Mapper的接口
1 2 3 4 5 6 7 8
| <mapper namespace="com.example.demo.Mapper.StudentMapper"> <resultMap type="Student" id="resultMapId"> <result property="id" column="id" /> <result property="name" column="name" /> <result property="age" column="age" /> <result property="address" column="address" /> </resultMap> </mapper>
|
结果映射将结果映射给Java对象
resultMap标签用于定义结果映射规则,将查询结果映射到Java对象。其常用属性如下:
id
:标识符,用于在配置文件中引用该结果映射规则。映射数据表的主键ID,
type
:指定映射结果的Java类型。
result
:标识符,用于在配置文件中引用该结果映射规则。注入到字段或 JavaBean 属性的结果
property
:column 指定的列进行映射的 JavaBean 变量名称。(Java实体类字段名)
column
:用来指定我们需要将那一列进行和 JavaBean 属性映射。(数据库字段名)
添加基本的sql操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <mapper namespace="com.example.demo.Mapper.StudentMapper"> <resultMap type="Student" id="resultMapId"> <id property="id" column="student_id"/> <result property="name" column="student_name"/> <result property="age" column="student_age"/> <result property="address" column="student_address"/> </resultMap> <insert id="insertName"> INSERT INTO student (student_name,student_age,student_address) VALUES (#{name}, #{age}, #{address}) </insert> <update id="updateName"> UPDATE student SET student_name = #{name}, student_age = #{age} WHERE student_id = #{id} </update> <delete id="deleteinfo"> DELETE FROM student WHERE student_id = #{id} </delete> <select id="selectName" resultType="com.example.demo.entity.Student"> SELECT * FROM student WHERE student_id = #{id} </select> </mapper>
|
<select>
:插入操作的标签
<update>
:更新操作的标签
<delete>
:删除操作的标签
<select>
:查询操作的标签
id
:与Mapper方法名对应,使用此id调用SQL语句
resultType
:指定 SQL 语句执行后返回的结果类型,Java对象或者基本数据类型
parameterType
:删除操作的标签
#{}
:占位符, 可以防止 SQL 注入攻击,并且会自动进行参数类型转换和字符转义,相对安全。#{}
在执行前会被预编译成一个占位符,MyBatis 会将 SQL 语句中的 #{}
部分替换为问号(?
),然后将参数值通过 PreparedStatement ( Java 中用于执行预编译 SQL 语句的接口,它可以确保参数值被安全地传递给数据库,并且不会受到恶意输入的影响)的方式绑定到这些问号上。它可以确保参数值被安全地传递给数据库,因此可以防止 SQL 注入。
${}
:字符串替换,在 SQL 语句中使用 ${}
会直接将参数的值拼接到 SQL 语句中,存在 SQL 注入的风险。
一对一映射
一实体对应一实体相关联。
改动下原来的实体类,并添加子映射实体类
1 2 3 4 5 6 7 8
| public class Student { private Integer id; private String name; private String age; private String address; private IdCard idCard; }
|
1 2 3 4 5
| public class IdCard { private Integer idCardId; private String idCardNumber; }
|
1 2 3 4 5 6 7
| public interface StudentMapper { public int insertName(); public int deleteinfo(); public int updateName(); public Student selectName(); public Student StudentWithIdCard(); }
|
创建新的Mapper接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <mapper namespace="com.example.demo.Mapper.StudentMapper"> <resultMap type="Student" id="resultMapIdOne"> <id property="id" column="student_id"/> <result property="name" column="student_name"/> <result property="age" column="student_age"/> <result property="address" column="student_address"/> <association property="idCard" javaType="IdCard"> <id property="idCardId" column="id_card_id"/> <result property="idCardNumber" column="id_card_number"/> </association> </resultMap> <insert id="insertName"> INSERT INTO student (student_name,student_age,student_address) VALUES (#{name}, #{age}, #{address}) </insert> <update id="updateName"> UPDATE student SET student_name = #{name}, student_age = #{age} WHERE student_id = #{id} </update> <delete id="deleteinfo"> DELETE FROM student WHERE student_id = #{id} </delete> <select id="selectName" resultType="com.example.demo.entity.Student"> SELECT * FROM student WHERE student_id = #{id} </select> <select id="StudentWithIdCard" resultMap="resultMapIdOne"> SELECT s.student_id, s.student_name, s.student_age, s.student_address, i.id_card_id, i.id_card_number FROM student s LEFT JOIN id_card i ON s.id_card_id = i.id_card_id WHERE s.student_id = #{id} </select> </mapper>
|
使用LEFT JOIN将student与id_card表进行关联,使用字段id将其关联,将select标签内查询出来的数据通过resultMap处理映射,使用resultMap进行指定。
查询到的数据会映射到相应的实体类,此时,Student中除原本属性外idCard中的数据将Set到IdCard对象中,”一对象“对应另一个对象中的”其中一组数据
一对多映射
一实体对应一实体多条数据,甚至多个实体多条记录
改动原实体类
Student中添加了LIst<>属性,它代表学生与学生证、学生与教师与之间的一对多关系。
1 2 3 4 5 6 7 8 9
| public class Student { private Integer id; private String name; private String age; private String address; private List<IdCard> idCardList; private List<Teacher> teacherList; }
|
1 2 3 4 5
| public class IdCard { private Integer idCardId; private String idCardNumber; }
|
添加新的实体类Teacher
1 2 3 4 5
| public class Teacher { private Integer teacherId; private String teacherName; }
|
1 2 3 4 5 6 7 8 9
| public interface StudentMapper { public int insertName(); public int deleteinfo(); public int updateName(); public Student selectName(); public Student StudentWithIdCard(); List<Student> StudentsWithDetailsAll(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| <mapper namespace="com.example.demo.Mapper.StudentMapper"> <resultMap type="Student" id="resultMapIdTwo"> <id property="id" column="student_id"/> <result property="name" column="student_name"/> <result property="age" column="student_age"/> <result property="address" column="student_address"/> <collection property="idCardList" ofType="IdCard"> <id property="idCardId" column="id_card_id"/> <result property="idCardNumber" column="id_card_number"/> </collection>
<collection property="teacherList" ofType="Teacher"> <id property="teacherId" column="teacher_id"/> <result property="teacherName" column="teacher_name"/> </collection> </resultMap> <select id="StudentsWithDetailsAll" resultMap="resultMapIdTwo"> SELECT s.student_id, s.student_name, s.student_age s.student_address, i.id_card_id, i.id_card_number, t.teacher_id, t.teacher_name FROM student s LEFT JOIN id_card i ON s.student_id = i.student_id LEFT JOIN teacher t ON s.student_id = t.student_id; </select> </mapper>
|
使用student_id将三张表进行关联,student表映射到Student类,idCard映射到idCardList中,teacher映射到teacherList中,实现一实体对应多个实体的关系
注意我分别使用了association与collection它们在两个不同的内对应id分别为resultMapIdOne与resultMapIdTwo
两个元素都用于处理关联关系
动态拼接与格式化标签
在resultMapIdOne映射基础上对基本语句进行调整,添加Mybatis标签使用
改动mapper接口,改变insertName接收
1 2 3 4 5 6 7 8 9
| public interface StudentMapper { public int insertName(@Param("students") List<Student> students); public int deleteinfo(); public int updateName(); public Student selectName(); public Student StudentWithIdCard(); List<Student> StudentsWithDetailsAll(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| <mapper namespace="com.example.demo.Mapper.StudentMapper"> <insert id="insertName"> INSERT INTO student (student_name,student_age,student_address) VALUES <foreach collection="students" item="student" separator=","> (#{student.name}, #{student.age}, #{student.address}) </foreach> </insert> <update id="updateName"> UPDATE student <set> <if test="name != null">student_name = #{name},</if> <if test="age != null">student_age = #{age},</if> </set> WHERE student_id = #{id} </update> <delete id="deleteinfo"> DELETE FROM student WHERE <choose> <when test="id != null"> student_id = #{id} </when> <when test="name != null"> student_name = #{name} </when> <otherwise> 1=1 </otherwise> </choose> </delete> <select id="selectName" resultType="com.example.demo.entity.Student"> SELECT student_id,student_name,student_age,student_address FROM student <where> <trim prefix="AND" suffixOverrides="AND"> <if test="age != null"> student_age = #{age} AND </if> <if test="address != null"> student_address = #{address} AND </if> </trim> </where> </select> </mapper>
|
if
:判断是否要添加相应的语句。
choose
:类似if判断,搭配when与otherwisse使用,当所有when条件都不成立/不符合时,使用otherwise,所有when条件只会执行一次
foreach
:动态生成 SQL 语句,用于遍历集合生成Sql片段,
内部标签结构:
collection
: 遍历的集合或数组的名称。对应Mapper传递参数名
item
: 集合中的每个元素在循环中的别名。
index
(可选): 当遍历的是 Map 时,表示 Map 的键。
open
: 遍历开始时的字符串。
close
: 遍历结束时的字符串。
separator
: 每个元素之间的分隔符,注意:控制的是在每两个元素之间插入的分隔符。对于最后一个元素,不会在其后添加分隔符。
where
:用于在 SQL 查询中动态生成 WHERE
子句。
set
:用于 UPDATE
语句中,用于动态生成 SET
子句
trim
:定制 SQL 语句的前缀、后缀,以及连接条件。它可以用于处理动态 SQL 语句的前缀和后缀。
内部标签结构:
prefix
:字符串开头添加的前缀。
prefixOverrides
:字符串开头删除的前缀。
suffix
:字符串结尾添加的后缀。
suffixOverrides
:字符串结尾删除的后缀。
标签补充
sql
:定义SQL的常量。
include
:用于引用sql标签定义的常量
以此查询条件为例进行改动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <select id="selectName" resultType="com.example.demo.entity.Student"> SELECT student_id,student_name,student_age,student_address FROM student <where> <trim prefix="AND" suffixOverrides="AND"> <if test="age != null"> student_age = #{age} AND </if> <if test="address != null"> student_address = #{address} AND </if> </trim> </where> </select>
<sql id="sqlIdOne"> SELECT student_id,student_name,student_age,student_address FROM student </sql>
<select id="selectName" resultType="com.example.demo.entity.Student"> <include refid="sqlIdOne"/> <where> <trim prefix="AND" suffixOverrides="AND"> <if test="age != null"> student_age = #{age} AND </if> <if test="address != null"> student_address = #{address} AND </if> </trim> </where> </select>
|
结语
希望和朋友们一起学习、一起进步