Mybatis- 简单整合
Mybatis- 简单整合
原生方式整合
参考官方档中章节:mybatis - MyBatis 3 | Getting started
基础模块
直接在 IDEA 中新建模块

会创建一个标准的 Maven 构建的 JavaSE 项目的模块结构
假设根包名为 xyz.xiashuo
,我们在根包名下创建 domain
包,并创建 User
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
private String gender;
private String email;
// 省略属性的getter、setter方法,有参构造和无参构造、toString()方法
....
}
同时在 MySql 数据库创建中创建模式 MyBatis
,并在其中创建表 t_user
,建表语句如下
create table t_user
(
id int auto_increment,
username varchar(20) null,
password varchar(20) null,
age int null,
gender char null,
email varchar(20) null,
constraint t_user_pk
primary key (id)
)
comment '用户表';
开始整合
在 POM 文件中添加依赖
<dependencies>
<!-- Mybatis核心 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<!-- junit测试 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
</dependencies>
其中核心的 jar 包就一个,就是 mybatis
,此外注意,MySQL 驱动版本要跟 MySQL 数据库匹配,比如我当前的 MySQL 数据库的版本是 8,那么 mysql-connector-java
的版本最好也是 8
然后开始创建核心配置文件,核心配置文件主要用于配置连接数据库的环境以及 MyBatis 的全局配置信息。
框架的本质,就是 jar 包加上配置文件
MyBatis 的配置文件分为两种
核心配置文件
SQL 映射文件
在 src/main/resources
下创建 mybatis-config.xml
,
没有默认名字,习惯上命名为
mybatis-config.xml
,这个文件名仅仅只是建议,并非强制要求。将来整合 Spring 之后,这个配置文件可以省略,所以大家操作时可以直接复制、粘贴
<?xml version="1.0" encoding="UTF-8" ?>
<!-- !DOCTYPE 后面的单词,必定是xml文件的根标签-->
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--设置连接数据库的环境-->
<environments default="development">
<!-- 可配置多种环境下的数据库配置 -->
<environment id="development">
<!-- 事务管理器-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!-- Mysql新版驱动类-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!-- 我自己的个人服务器上的Mysql数据库-->
<property name="url" value="jdbc:mysql://xiashuo.xyz:3306/MyBatis"/>
<property name="username" value="mysqlXS"/>
<property name="password" value="mySql@327541"/>
</dataSource>
</environment>
</environments>
<!--引入SQL映射文件-->
<mappers>
<!-- resource 路径的起点是类路径 -->
<mapper resource="mappers/UserMapper.xml"/>
</mappers>
</configuration>
接下来创建 Mapper 接口,MyBatis 中的 mapper 接口相当于以前的 dao。但是区别在于,mapper 仅仅是接口,我们不需要提供实现类。
创建 xyz.xiashuo.mapper
,然后创建 UserMapper
接口,对应 domain
包下的 User
,对应 Mysql 中的 t_user
表
// 对应domain 包下的 User
// 对应 Mysql 中的 t_user 表
public interface UserMapper {
/**
* * 添加用户信息
*/
int insertUser();
}
接下来开始创建 MyBatis 的映射文件,MyBatis 映射文件用于编写 SQL,访问以及操作表中的数据,MyBatis 映射文件存放的位置是 src/main/resources/mappers
目录下,当然你可以放在别的路径下,注意映射文件的路径要在核心配置文件中的 <mappers>
下的 <mapper>
标签中进行配置,否则映射文件无法生效。
首先我们看看 ORM 框架的含义
ORM(Object Relationship Mapping)对象关系映射。其中:
对象:Java 的实体类对象
关系:关系型数据库
映射:二者之间的对应关系
Java 概念 数据库概念 类 表 属性 字段/列 对象 记录/行
映射文件有两点需要注意:
-
映射文件的命名规则:
表所对应的实体类的类名+Mapper.xml
。例如:表 t_user,映射的实体类为 User,所对应的映射文件为UserMapper.xml
因此一个映射文件对应一个实体类,对应一张表的操作。
-
MyBatis 中可以面向接口操作数据,要保证两个一致:
-
mapper 接口的全类名和 xml 映射文件的命名空间(
<mapper>
跟标签的namespace
属性)保持一致 -
mapper 接口中方法的方法名和 xml 映射文件中编写 SQL 的标签的 id 属性保持一致
-
<?xml version="1.0" encoding="UTF-8" ?>
<!-- !DOCTYPE 后面的单词,必定是xml文件的根标签-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 属性保存的是此映射文件对应的mapper接口 -->
<mapper namespace="xyz.xiashuo.mapper.UserMapper">
<!-- id属性为此映射文件对应的mapper接口中的方法名 -->
<insert id="insertUser">
insert into t_user
values (null, '张三', '123', 23, '女', '[email protected]')
</insert>
</mapper>
注意,IDEA 安装 MyBatisX
插件之后,可以很方便地在 mapper 接口和映射文件之间进行跳转
在映射文件中

在 mapper 接口中

甚至 mapper 接口和映射文件的图标也是特殊图标

简单测试
public class UserMapperTest {
SqlSession sqlSession = null;
/**
* 方便多个测试方法,直接将获取 SqlSession 的内容提取出来
*/
@BeforeEach
public void getSqlSession() throws IOException {
//1. 读取MyBatis的核心配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//2. 创建SqlSessionFactoryBuilder对象,通过核心配置文件所对应的字节输入流创建工厂类SqlSessionFactory,生产SqlSession对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
//3. 创建SqlSession对象,
// openSession方法参数为空时,通过SqlSession对象所操作的sql都必须手动提交或回滚事务
// SqlSession sqlSession = sqlSessionFactory.openSession();
// openSession方法参数为true时,通过SqlSession对象所操作的sql都会自动提交
sqlSession = sqlSessionFactory.openSession(true);
}
@Test
public void testInsertUser() throws IOException {
if (sqlSession == null) {
return;
}
//通过代理模式创建UserMapper接口的代理实现类对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用UserMapper接口中的方法,就可以根据UserMapper的全类名匹配元素文件,通过调用的方法名匹配映射文件中的SQL标签,并执行标签中的SQL语句
int result = userMapper.insertUser();
//sqlSession.commit()
System.out.println("结果:" + result);
}
}
执行日志:
结果:1
简单分析一下 Mybatis 原生的使用过程:
-
读取 MyBatis 的核心配置文件
-
创建 SqlSessionFactoryBuilder 对象,通过核心配置文件所对应的字节输入流创建工厂类 SqlSessionFactory,生产 SqlSession 对象
-
创建 SqlSession 对象
-
openSession 方法参数为空时,通过 SqlSession 对象所操作的 sql 都必须手动提交或回滚事务
-
openSession 方法参数为 true 时,通过 SqlSession 对象所操作的 sql 都会自动提交
openSession 方法应该使用了 Mybatis 配置文件中的数据库配置,这个以后有时间再去研究,TODO
-
-
调用
getMapper
方法,通过代理模式创建XXXMapper
接口的代理实现类对象getMapper 方法应该有 xml 配置文件的查找过程,这个以后有时间再去研究,TODO
-
调用
XXXMapper
接口中的方法
这个测试类中,记录的,实际上是Mybatis 原生的使用方法,其中最终要的操作对象是SqlSession,代表 Java 程序和数据库之间的(连接)会话。(HttpSession
是 Java 程序和浏览器之间的会话),在获取 SqlSession
对象的时候,我们可以指定四个方面的信息
-
是否自动提交
-
是否通过指定的
Connection
连接创建 -
事务的隔离级别
-
执行器类型
SqlSessionFactory
的源码:
public interface SqlSessionFactory {
// 默认
SqlSession openSession();
// 设置是否自动提交
SqlSession openSession(boolean autoCommit);
// 直接通过 Connection 连接创建会话
SqlSession openSession(Connection connection);
// 指定事务的隔离级别,重要
SqlSession openSession(TransactionIsolationLevel level);
// 指定执行器的类型,再配合上面三个条件
// 执行器有三种:SimpleExecutor、ReuseExecutor、BatchExecutor
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();
}
这里,我们最常见的,其实是事务是否自动提交的问题,默认情况下,通过 openSession()
获取的 SqlSession
在获取 mapper 接口的实例之后,执行完 mapper 接口中的方法,是需要手动提交的,但是通过 openSession(true)
获取的 SqlSession
在获取 mapper 接口的实例之后,执行完 mapper 接口中的方法,会自动提交。
一般情况下,简单的增删改查的 SQL,手动提交太麻烦,我们都会设置自动提交,而一些业务复杂,设置到回滚的事务操作,我们最好手动提交和回滚
其实通过查看
SqlSession
接口的方法,发现SqlSession
不仅可以通过getMapper
方法获取 mapper 接口实例,还可以直接执行 sql 语句,非常的方便和牛逼。这个以后有时间再去研究,TODO
添加日志 - log4j2
参考官方文档:mybatis - MyBatis 3 | Logging
在 pom 中添加依赖
<!-- 日志相关-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.2</version>
</dependency>
在 src/main/resources
中添加配置文件,log4j2.xml
,此配置会将日志同时 sql 的执行日志同时输出到工作目录和控制台之中
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" monitorInterval="30">
<properties>
<property name="LOG_HOME">${sys:user.dir}\logs</property>
</properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<File name="SqlFile" fileName="${LOG_HOME}/sqlFile.log" append="true">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</File>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
<!-- name 为 mapper类所在的包-->
<Logger name="xyz.xiashuo.mapper" level="debug" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="SqlFile"/>
</Logger>
</Loggers>
</Configuration>
输出日志:
2022-10-28 12:10:56.102 [main] DEBUG xyz.xiashuo.mapper.UserMapper.insertUser - ==> Preparing: insert into t_user values (null, '张三', '123', 23, '女', '[email protected]')
2022-10-28 12:10:56.120 [main] DEBUG xyz.xiashuo.mapper.UserMapper.insertUser - ==> Parameters:
2022-10-28 12:10:56.191 [main] DEBUG xyz.xiashuo.mapper.UserMapper.insertUser - <== Updates: 1
工作目录:
如果是在 IDEA 中,工作目录就是当前模块所在项目的根路径
如果是打成 jar 包,那么工作目录就是执行
java -jar
的目录具体请看《Java 中的常见路径和资源获取.md》
重点:
-
Mybatis 的框架代码的日志级别是
DEBUG
-
Mybatis 生成的 Mapper 接口的实现类的执行 SQL 的日志的日志级别也是
DEBUG
我们关注的 SQL 的执行日志,主要在 Mapper 接口的实现类中的日志,日志的内容是执行了哪条 Sql,参数是什么,返回值是什么。
因此,我们需要创建一个
name
属性为 mapper 接口所在包名同时level
为DEBUG
的<Logger>
,专门用于处理这些日志。<Logger name="xyz.xiashuo.mapper" level="debug" additivity="false">
log4j 相关知识请查看《log4j2_Document.docx》
添加更新和删除的方法
UserMapper
接口中添加
int updateUser();
int deleteUser();
UserMapper.xml
映射文件中添加
<update id="updateUser">
update t_user set username = 'xiashuo' where id = 3
</update>
<delete id="deleteUser">
delete from t_user where id = 4
</delete>
测试类中添加
@Test
public void testUpdateUser() throws IOException {
if (sqlSession == null) {
return;
}
//4. 通过代理模式创建UserMapper接口的代理实现类对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用UserMapper接口中的方法,就可以根据UserMapper的全类名匹配元素文件,通过调用的方法名匹配映射文件中的SQL标签,并执行标签中的SQL语句
int result = userMapper.updateUser();
//sqlSession.commit()
System.out.println("结果:" + result);
}
@Test
public void testDeleteUser() throws IOException {
if (sqlSession == null) {
return;
}
//4. 通过代理模式创建UserMapper接口的代理实现类对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用UserMapper接口中的方法,就可以根据UserMapper的全类名匹配元素文件,通过调用的方法名匹配映射文件中的SQL标签,并执行标签中的SQL语句
int result = userMapper.deleteUser();
//sqlSession.commit()
System.out.println("结果:" + result);
}
查询功能
跟更新和删除的区别就是,查询时必定有返回值的
映射文件中的 SQL 语句的标签中的 resultType
或者 resultMap
属性的功能时指导 Mybatis 处理 SQL 语句的结果集,<select>
标签必须设置其中一个标签
-
resultType
,将从 SQL 语句返回的结果的预期的类型的完全限定类名或别名。注意,在返回多条数据(集合)的情况下,resultType
指定的应该是集合包含的元素类型,而不是集合本身的类型。使用resultType
或resultMap
,而不是两者都使用。一般在结果列和对象属性可以一一对应时使用。
-
resultMap
,对外部ResultMap
的引用。ResultMap
(结果映射)是 MyBatis 最强大的特性,可以将 SQL 查询的结果集映射到复杂的类中,比如字段为其他 JavaBean 类型,比如字段为集合或者 Map 类型,这些情况都可以通过ResultMap
进行映射,通过对它们的良好理解,可以解决许多复杂的映射场景。使用resultType
或resultMap
,而不是两者都使用。以后有机会再研究ResultMap
类,官方文档(mybatis - MyBatis 3 | Mapper XML Files):中写的例子非常值得实践一把。这个我们在后面的篇章里都会学习到
结果列跟对象属性无法一一对应的时候使用,比如一对多,多对一的时候
简单使用一下 resultType
:
UserMapper
接口中添加
User getUser();
List<User> getUsers();
UserMapper.xml
映射文件中添加
<select id="getUser" resultType="xyz.xiashuo.domain.User">
select *
from t_user
where id = 5
</select>
<select id="getUsers" resultType="xyz.xiashuo.domain.User">
select *
from t_user
</select>
测试类中添加
@Test
public void testSelectUser() throws IOException {
if (sqlSession == null) {
return;
}
//4. 通过代理模式创建UserMapper接口的代理实现类对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用UserMapper接口中的方法,就可以根据UserMapper的全类名匹配元素文件,通过调用的方法名匹配映射文件中的SQL标签,并执行标签中的SQL语句
User result = userMapper.getUser();
System.out.println("结果:" + result);
}
@Test
public void testSelectUsers() throws IOException {
if (sqlSession == null) {
return;
}
//4. 通过代理模式创建UserMapper接口的代理实现类对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用UserMapper接口中的方法,就可以根据UserMapper的全类名匹配元素文件,通过调用的方法名匹配映射文件中的SQL标签,并执行标签中的SQL语句
List<User> result = userMapper.getUsers();
System.out.println("结果:");
result.forEachprintln;
}
在 SpringBoot 中的整合
以后有时间再增加,TODO。