![47af408f22f93c9ffa89954961870a05.png](https://i-blog.csdnimg.cn/blog_migrate/aa1d1bc39ae376c8aa42517e913072e1.jpeg)
PS:你的状态取决于你的心态,要想不再焦虑,先把生活节奏规律起来。MyBatis 是一款优秀的持久层框架,MyBatis 使用 XML 或者注解来进行配置和映射,可以方便的将 POJO 映射成数据库中的记录。
MyBatis工作流程
依赖及配置
@Mapper和@MapperScan
实体类
Mapper配置文件
Mapper接口
Mapper映射文件
collection标签的使用
多数据源配置
测试结果
MyBatis使用注解配置
MyBatis工作流程
MyBatis 工作流程如下图所示:![a3368e6bd76cafd8e2d2412065b3b69f.png](https://i-blog.csdnimg.cn/blog_migrate/b5db6919ed4cd5cc297914137b897236.png)
读取 mybatis-config.xml 配置文件;
加载 Mapper 映射文件或对应注解内容,里面定义了相应的 SQL 语句;
根据配置信息创建会话工厂
SqlSessionFactory
;根据会话工厂创建
SqlSession
,里面包含了执行 SQL 需要的所有方法;创建
Executor
执行器,用来执行 SQL 语句,在创建会话工厂SqlSessionFactory
的时候就会创建一个Executor
,其默认执行器类型是ExecutorType.SIMPLE
;MappedStatement
对象,该对象是Executor
执行器方法中的参数,主要是对 Mapper XML 文件中映射信息的封装;输入参数映射;
输出参数映射。
依赖及配置
创建 Spring Boot 项目,在其 build.gradle 文件中添加 MyBatis 和 MySQL 驱动的依赖如下:dependencies {
// ...
// myBaits
// http://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/index.html
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.1'
// mysql驱动
runtime("mysql:mysql-connector-java")
// ...
}
然后在项目的 application.properties 文件中配置数据库连接参数以及 MyBatis 相关配置,如下:
# 数据库用户名
spring.datasource.username=root# 数据库密码
spring.datasource.password=admin# JDBC Driver
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver# JDBC URLspring.datasource.url=jdbc:mysql://localhost:3306/db_student?serverTimezone=Asia/Shanghai#spring.datasource.url=jdbc:mysql://localhost:3306/db_student?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true# 是否执行MyBatis xml配置文件的状态检查, 只是检查状态,默认false
mybatis.check-config-location=true# mybatis-config.xml文件的位置mybatis.config-location=classpath:mybatis/mybatis-config.xml# Mapper对应的xml路径mybatis.mapper-locations=classpath:mybatis/mapper/*.xml# 设置别名的路径,可避免写全限定类名
mybatis.type-aliases-package=com.manu.mybatisxml.model
MyBatis 主要配置的是配置文件 mybatis-config.xml 的路径、Mapper 对应的 XML 文件的路径。
@Mapper和@MapperScan
@Mapper
注解用来标记 Mapper 接口,其被标注的接口都会生成对应的动态代理类,如果有多个 Mapper 接口,则都需要用
@Mapper
注解来标注,使用方式如下:
@Mapperpublic interface ClassMapper{///
}
@MapperScan
在项目的入口类上进行标注,可以配置要扫描的接口所在的一个或多个包,也可以使用通配符
*
来进行配置,使用方式如下:
@SpringBootApplication// 扫描指定包中的接口@MapperScan("com.manu.mybatisxml.mapper")// @MapperScan("com.manu.mybatisxml.*.mapper")// @MapperScan({"pack1","pack2"})public class SpringBootMybatisXmlApplication {public static void main(String[] args) {
SpringApplication.run(SpringBootMybatisXmlApplication.class, args);
}
}
实体类
案例是班级和学生的关系,也就是一对多的关系,定义班级类Class
如下:
/**
* 班级类
*/public class Class {private String classId;private String name;private List students;public Class() {
}public Class(String classId, String name) {this.classId = classId;this.name = name;
}// ...// setter、getter、toString
}
定义学生类
Student
类如下:
/**
* 学生类
*/public class Student {private String classId;private String sno;private String name;private String grade;public Student() {
}public Student(String classId, String sno, String name, String grade) {this.classId = classId;this.sno = sno;this.name = name;this.grade = grade;
}// ...// setter、getter、toString
}
MyBatis配置文件
MyBatis 的配置文件是 mybatis-config.xml 文件,当在 Spring Boot 中使用 MyBatis 时,该配置文件中的大多数配置都可以在 application.properties 文件中配置,所以在 Spring Boot 项目中可以借助该配置文件简化全限定类名,如下:<?xml version="1.0" encoding="UTF-8" ?>configuration PUBLIC
"-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><typeAliases><typeAlias alias="Integer" type="java.lang.Integer" /><typeAlias alias="Long" type="java.lang.Long" /><typeAlias alias="HashMap" type="java.util.HashMap" /><typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" /><typeAlias alias="ArrayList" type="java.util.ArrayList" /><typeAlias alias="LinkedList" type="java.util.LinkedList" /><typeAlias alias="Student" type="com.manu.mybatisxml.model.Student" /><typeAlias alias="Class" type="com.manu.mybatisxml.model.Class" />typeAliases>configuration>
Mapper接口
Mapper 接口中中方法名对应 Mapper 映射文件中对应的 SQL 语句对应的方法,且方法名必须与对应的 SQL 语句中的id
属性子相同,
ClassMapper
如下:
/**
* ClassMapper.xml对应的Mapper接口
*/public interface ClassMapper {/**
* 插入一条数据
* @param student student
*/void insertStudent(Student student);void insertClass(Class course);/**
* 根据sno删除一条记录
* @param sno sno
*/void deleteStudent(String sno);/**
* 更新数据
* @param student student
*/void updateStudent(Student student);/**
* 更具名称查询数据
* @param name name
* @return
*/Student findStudentByName(String name);/**
* 查询全部数据
* @return
*/List findAllStudent();/**
* 集合数据查询
* @param name name
* @return
*/Class findClassStudents(String name);/**
* 集合数据嵌套查询
* @param classId classId
* @return
*/Class findClassStudents1(String classId);
}
Mapper映射文件
Mapper 映射文件以 XML 为基础,使用与 SQL 语句对应的 SQL 标签来灵活的构建 SQL 语句,一些标签及其属性都是见名知意,常用标签如下:mapper
:配置 Mapper 映射文件对应的 Mapper 接口类;resultMap
:查询语句结果集;result
:用于定义resultMap
标签中的字段;id
:用于定义resultMap
标签中的主键字段;collection
:集合数据,如List
这种数据;sql
:定义 SQL 语句块供其他 SQL 语句使用;insert
:插入语句;delete
:删除语句;update
:更新语句;select
:查询语句。
ClassMapper
对应的 Mapper 映射文件如下:
<?xml version="1.0" encoding="UTF-8"?>mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" ><mapper namespace="com.manu.mybatisxml.mapper.ClassMapper"><resultMap id="StudentResultMap" type="com.manu.mybatisxml.model.Student"><id column="classId" property="classId" jdbcType="VARCHAR" /><result column="userName" property="name" jdbcType="VARCHAR" /><result column="sno" property="sno" jdbcType="VARCHAR" /><result column="grade" property="grade" jdbcType="VARCHAR" />resultMap><resultMap id="ClassWithCollectionResultMap" type="com.manu.mybatisxml.model.Class"><id column="classId" property="classId" jdbcType="VARCHAR" /><result column="name" property="name" jdbcType="VARCHAR" /><collection property="students" ofType="Student"><id column="sno" property="sno" jdbcType="VARCHAR" /><result column="userName" property="name" jdbcType="VARCHAR" /><result column="classId" property="classId" jdbcType="VARCHAR" /><result column="grade" property="grade" jdbcType="VARCHAR" />collection>resultMap><resultMap id="ClassWithCollectionResultMap1" type="com.manu.mybatisxml.model.Class"><id column="classId" property="classId" jdbcType="VARCHAR" /><result column="name" property="name" jdbcType="VARCHAR" /><collection column="{classId = classId}" property="students" ofType="Student"select="getStudent" />resultMap><select id="getStudent" parameterType="String" resultMap="StudentResultMap">
SELECT *
FROM mybatis_student
WHERE classId = #{classId}select><sql id="BaseStudentColumn">
sno,userName,classId,gradesql><insert id="insertClass" parameterType="Class">
INSERT INTO mybatis_class(classId, name)
VALUES (#{classId}, #{name})insert><insert id="insertStudent" parameterType="Student">
INSERT INTO mybatis_student(classId, userName, sno, grade)
VALUES (#{classId}, #{name}, #{sno}, #{grade})insert><delete id="deleteStudent" parameterType="String">
DELETE
FROM mybatis_student
WHERE sno = #{sno}delete><update id="updateStudent" parameterType="Student">
UPDATE mybatis_student
SET userName = #{name},
classId = #{classId},
grade = #{grade},
sno = #{sno}
WHERE sno = #{sno}update><select id="findClassStudents" parameterType="String" resultMap="ClassWithCollectionResultMap">
SELECT mybatis_class.classId,
mybatis_class.name,
mybatis_student.sno,
mybatis_student.userName,
mybatis_student.grade
FROM mybatis_student,
mybatis_class
WHERE mybatis_class.classId = mybatis_student.classId
and mybatis_class.name = #{name}select><select id="findClassStudents1" parameterType="String"resultMap="ClassWithCollectionResultMap1">
SELECT mybatis_class.classId,
mybatis_class.name,
mybatis_student.sno,
mybatis_student.userName,
mybatis_student.grade
FROM mybatis_student,
mybatis_class
WHERE mybatis_class.classId = mybatis_student.classId
and mybatis_class.classId = #{classId}select><select id="findStudentByName" resultMap="StudentResultMap" parameterType="String">
SELECT *
FROM mybatis_student
WHERE userName = #{name}select><select id="findAllStudent" resultMap="StudentResultMap">
SELECT<include refid="BaseStudentColumn" />
FROM mybatis_studentselect>mapper>
collection标签的使用
上文介绍了Mapper 文件中中的一些常用标签,其他标签的使用没什么可单独说的,这里单独说明一下
标签的使用,该标签主要用来标识结果集,如班级类
Class
中的学生集合
List
,通过该标签就可以查询到指定班级的学生集合,第一种方式:
<resultMap id="ClassWithCollectionResultMap" type="Class"><id column="classId" property="classId" jdbcType="VARCHAR" /><result column="name" property="name" jdbcType="VARCHAR" /><collection property="students" ofType="Student"><id column="sno" property="sno" jdbcType="VARCHAR" /><result column="userName" property="name" jdbcType="VARCHAR" /><result column="classId" property="classId" jdbcType="VARCHAR" /><result column="grade" property="grade" jdbcType="VARCHAR" />collection>resultMap>
对应的查询 SQL 映射如下:
<select id="findClassStudents" parameterType="String" resultMap="ClassWithCollectionResultMap">
SELECT mybatis_class.classId,
mybatis_class.name,
mybatis_student.sno,
mybatis_student.userName,
mybatis_student.grade
FROM mybatis_student,
mybatis_class
WHERE mybatis_class.classId = mybatis_student.classId
and mybatis_class.name = #{name}select>
第二种方式如下:
<resultMap id="ClassWithCollectionResultMap1" type="com.manu.mybatisxml.model.Class"><id column="classId" property="classId" jdbcType="VARCHAR" /><result column="name" property="name" jdbcType="VARCHAR" /><collection column="{classId = classId}" property="students" ofType="Student"select="getStudent" />resultMap><select id="getStudent" parameterType="String" resultMap="StudentResultMap">
SELECT *
FROM mybatis_student
WHERE classId = #{classId}select>
对应的查询 SQL 映射如下:
<select id="findClassStudents1" parameterType="String"resultMap="ClassWithCollectionResultMap1">
SELECT mybatis_class.classId,
mybatis_class.name,
mybatis_student.sno,
mybatis_student.userName,
mybatis_student.grade
FROM mybatis_student,
mybatis_class
WHERE mybatis_class.classId = mybatis_student.classId
and mybatis_class.classId = #{classId}select>
通过在 Mapper 接口中定义的
findClassStudents
即可查询到
Student
的对应集合。
多数据源配置
分别创建多数据源配置文件,生成多个不同的数据源以及不同的SqlSessionFactory
等,主要数据源配置如下:
/**
* @Primary表示主数据源
* basePackages:指定扫描的Mapper接口
* sqlSessionTemplateRef:指定在Mapper路径下指定的SqlSessionTemplate
*/@Configuration@MapperScan(basePackages = "com.manu.multimybatisxml.mapper.primary",
sqlSessionTemplateRef = "primarySqlSessionTemplate")public class PrimaryDataSourceConfig {@Primary@Bean@ConfigurationProperties(prefix = "spring.datasource.primary")public DataSource primaryDataSource() {return DataSourceBuilder.create().build();
}@Primary@Beanpublic SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/primary/*.xml"));return sessionFactoryBean.getObject();
}@Primary@Beanpublic DataSourceTransactionManager primaryDataSourceTransactionManager(@Qualifier("primaryDataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);
}@Primary@Beanpublic SqlSessionTemplate primarySqlSessionTemplate(@Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {return new SqlSessionTemplate(sqlSessionFactory);
}
}
第二个数据源的配置同上,只是不在标注
@Primary
,修改第二个数据源的名称以及对应的 Mapper 映射文件等,这里不再赘述。然后按照上述配置中指定的前缀,在 application.properties 文件中配置多数据库连接如下:
# dataSourceOne
spring.datasource.primary.username=root
spring.datasource.primary.password=admin
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver#spring.datasource.jdbc-url 多数据源中用来重写自定义连接池
spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/data_source_one?serverTimezone=Asia/Shanghai# dataSourceTwo
spring.datasource.secondary.username=root
spring.datasource.secondary.password=admin
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/data_source_two?serverTimezone=Asia/Shanghai# 是否执行MyBatis xml配置文件的状态检查, 只是检查状态,默认false
mybatis.check-config-location=true# mybatis-config.xml文件的位置
mybatis.config-location=classpath:mybatis/mybatis-config.xml# 设置别名的路径,可避免写全限定类名
mybatis.type-aliases-package=com.manu.multimybatisxml.model
具体内容可回复关键字【Spring Boot】获取源码链接。
测试结果
案例仅仅是为了说明使用方式,读者无需关心其合理性,编写测试类如下:/**
* MyBatisTest
*/@RunWith(SpringRunner.class)@SpringBootTestpublic class MyBatisTest {@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")@Autowiredprivate ClassMapper mClassMapper;@Testpublic void insert() {
Class class1 = new Class("class1", "一班");
Class class2 = new Class("class2", "二班");
mClassMapper.insertClass(class1);
mClassMapper.insertClass(class2);
List students = new ArrayList<>();for (int i = 0; i 10; i++) {
Student student;if (i % 2 == 0) {
student = new Student("class1", "sno" + i, "Student"+i, "A");
} else {
student = new Student("class2", "sno" + i, "Student"+i, "B");
}
mClassMapper.insertStudent(student);
}
}@Testpublic void deleteStudentBySno() {
mClassMapper.deleteStudent("sno0");
}@Testpublic void updateStudent() {
Student student = new Student("class1","sno1","student1","C");
mClassMapper.updateStudent(student);
}@Testpublic void findStudentByName() {
Student student = mClassMapper.findStudentByName("student5");
System.out.println(student);
}@Testpublic void findAllStudent() {
List students = mClassMapper.findAllStudent();for (Student student : students) {
System.out.println(student.toString());
}
}@Testpublic void findClassStudents(){
Class clazz = mClassMapper.findClassStudents("一班");
System.out.println("classId:"+clazz.getClassId()+",name:"+clazz.getName());
List students = clazz.getStudents();for (Student student : students) {
System.out.println(student.toString());
}
}@Testpublic void findClassStudents1(){
Class clazz = mClassMapper.findClassStudents1("class1");
System.out.println("classId:"+clazz.getClassId()+",name:"+clazz.getName());
List students = clazz.getStudents();for (Student student : students) {
System.out.println(student.toString());
}
}
}
这里以
findClassStudents
方法为例查看执行结果如下:
classId:class1,name:一班
Student{classId='class1', sno='sno1', name='student1', grade='C'}
Student{classId='class1', sno='sno2', name='Student2', grade='A'}
Student{classId='class1', sno='sno4', name='Student4', grade='A'}
Student{classId='class1', sno='sno6', name='Student6', grade='A'}
Student{classId='class1', sno='sno8', name='Student8', grade='A'}
注解配置
MyBatis 除了使用 XML 进行配置外还可以通过注解进行配置,如下:@Mapperpublic interface StudentMapper {/**
* 注解中的SQL语句中会自动获取对象student的相关属性
*/@Insert("INSERT INTO mybatis_student(userName,sno,grade) VALUES(#{name},#{sno},#{grade})")void insert(Student student);/**
* StudentFactory中会自动获取对象student的相关属性在SQL语句中
* StudentFactory中insert2方法通过#{属性名}的方式获取变量值
*/@InsertProvider(type = StudentFactory.class, method = "insert1")void insert1(Student student);/**
* 直接传递参数
* StudentFactory中insert2方法通过#{变量名}的方式获取变量值
* 此外也可以通过StringBuffer拼接SQL,如在insert2方法中拼接SQL字符串返回
*/@InsertProvider(type = StudentFactory.class, method = "insert2")void insert2(String sno, String name, String grade);
}
实现上述方法即可,如下:
public class StudentFactory {public String insert1(Student student) {
String sql = new SQL() {{
INSERT_INTO("mybatis_student");
VALUES("sno", "#{sno}");
VALUES("userName", "#{name}");
VALUES("grade", "#{grade}");
}}.toString();
System.out.println("SQL:" + sql);return sql;
}public String insert2(String sno,String name,String grade) {
String sql = new SQL() {{
INSERT_INTO("mybatis_student");
VALUES("sno", "#{sno}");
VALUES("userName", "#{name}");
VALUES("grade", "#{grade}");
}}.toString();
System.out.println("SQL:" + sql);return sql;
}
}
最后,进行测试,如下:
@RunWith(SpringRunner.class)@SpringBootTestpublic class MyBatisAnnotationTests {@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")@Autowired
StudentMapper mStudentMapper;@Testpublic void insert() {
Student student = new Student("sno0", "jzman0", "A");
mStudentMapper.insert(student);
}@Testpublic void insert1() {
Student student = new Student("sno1", "jzman1", "A");
mStudentMapper.insert1(student);
}@Testpublic void insert2() {
Student student = new Student("sno2", "jzman2", "A");
mStudentMapper.insert2(student.getSno(), student.getName(), student.getGrade());
}
}
MyBatis 使用注解方式代码更少,但是在 SQL 的灵活性性上还是有一定的局限性,这里没实践不做过多阐述。
---END---
![4bb6b3dcca3cb3ab63d982eae9d21b41.png](https://i-blog.csdnimg.cn/blog_migrate/23a6dc292cf6d4d93e7bf77692040683.jpeg)
让我知道你在看
![8b42ae1007ccefaffec08cbbb642e1d7.gif](https://i-blog.csdnimg.cn/blog_migrate/79e15eefad03007ffc9d8adb3fe7d516.gif)