MyBatis
ORM 框架
- ORM(Object Relational Mapping)对象关系映射,将程序中的
一个对象与表中的一行数据一一对应
。 - ORM 框架提供了持久化类与表的映射关系,在运行时参照映射文件的信息,
把对象持久化存储到数据库中
。
使用 JDBC 完成 ORM 操作的缺点
-
存在大量的冗余代码。
-
手动创建 Connection、Statement 等。
-
手动将结果集封装成实体对象。
-
查询效率低,没有对数据访问进行过优化(Not Cache)。
MyBatis 框架概述
概述
- MyBatis 本是 apache 的一个开源项目 iBatis,2010年这个项目由 apache software foundation 迁移到了google code,并且改名为 MyBatis 。2013年11月迁移到 Github。
- iBATIS 一词来源于 “internet” 和 “abatis” 的组合,是一个基于 Java 的持久层框架。iBATIS 提供的持久层框架包括 SQL Maps 和 Data Access Objects(DAOs)
- MyBatis 是一个优秀的基于 Java 的持久层框架,支持自定义SQL,存储过程和高级映射。
- MyBatis 对原有 JDBC 操作进行了封装,几乎消除了所有 JDBC 代码,使开发者只需关注 SQL 本身。
- MyBatis 可以使用简单的 XML 或 Annotation 来配置执行 SQL,并自动完成 ORM 操作,将执行结果作为一个实体类进行返回,完成数据库中的记录与接口、POJO 的映射。
- 当前,最新版本是 MyBatis 3.5.9,其发布时间是 2021 年 12 月 25 日。
访问与下载
-
官方网站:https://mybatis.org/mybatis-3/
-
下载地址:https://github.com/mybatis/mybatis-3/releases
-
官方中文文档:https://mybatis.org/mybatis-3/zh/index.html
MyBatis 框架原理图解【重点】
-
MyBatis 配置
MyBatis.xml,此文件作为 MyBatis 的全局配置文件,配置了 MyBatis 的运行环境等信息。
mapper.xml 文件即 sql 映射文件,文件中配置了操作数据库的 sql 语句。此文件需要在 MyBatis.xml 中加载。
-
通过 MyBatis 环境等配置信息构造 SqlSessionFactory 即会话工厂
-
由会话工厂创建 sqlSession 即会话,操作数据库需要通过 sqlSession 进行
-
MyBatis 底层自定义了 Executor 执行器接口操作数据库,Executor 接口有两个实现,一个是基本执行器、一个是缓存执行器
-
Mapped Statement 也是 MyBatis 一个底层封装对象,它包装了 MyBatis 配置信息及sql映射信息等。mapper.xml 文件中一个sql对应一个 Mapped Statement 对象,sql 的 id 即是Mapped statement 的 id
-
Mapped Statement 对 sql 执行输入参数进行定义,包括 HashMap、基本类型、实体类对象,Executor 通过 Mapped Statement 在执行 sql 前将输入的 java 对象映射至 sql 中,输入参数映射就是 jdbc 编程中对 preparedStatement 设置参数
MappedStatement 对 sql 执行输出结果进行定义,包括 HashMap、基本类型、实体类对象,Executor 通过 Mapped Statement 在执行 sql 后将输出结果映射至 java 对象中,输出结果映射过程相当于 jdbc 编程中对结果的解析处理过程。
MyBatis 初识【重点】
使用流程【固定格式】
- pom.xml 中引入核心依赖
- 声明 Mybatis 的配置文件
- 声明 dao 层接口
- 声明接口对应的 mapper 映射文件
- 将 mapper 映射文件注册到 MyBatis 配置文件中
- 根据流程操作获取结果
案例代码
1、pom.xml 中引入 MyBatis 核心依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.fc</groupId>
<artifactId>02_MyBatis</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!--数据库连接-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
</dependencies>
</project>
2、创建 mybatis-config.xml 配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--MyBatis配置-->
<configuration>
<!--JDBC环境配置、选中默认环境-->
<environments default="development">
<!--MySql数据库环境配置-->
<environment id="development">
<!--事务管理-->
<transactionManager type="JDBC"/>
<!--连接池相关配置-->
<dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/FC2021?useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>
【注意】配置文件要放在 resources 文件目录下
3、建立数据表
create table student(
id int primary key auto_increment,
name varchar(20) not null,
age tinyint,
gender char(1) default '女',
birthday datetime,
info text);
4、声明数据表对应的实体类
public class Student {
private Integer id;
private String name;
private Byte age;
private String gender;
private Date birthday;
private String info;
// Constructor、Setters、Getters
}
【注意】必须符合 JavaBean 规范
5、定义 dao 接口
public interface StudentDao {
Student selectStudentById(Integer id);
}
6、编写 Mapper 文件
mapper 规范
- dao 接口的全限定名要和 mapper 映射文件的 namespace 值一致。
- dao 接口的方法名要和 mapper 映射文件的 statement 的 id 一致。
- dao 接口的方法参数类型要和 mapper 映射文件的 statement 的 parameterType 的值一致,并且参数只能是一个。
- dao 接口的方法返回值类型要和 mapper 映射文件的 statement 的 resultType 的值一致。
StudentMapper.xml 配置文件
<?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 namespace="com.fc.dao.StudentDao">
<!--id对应所需重写的接口抽象方法,resultType对应查询后所需返回的对象类型-->
<select id="selectStudentById" resultType="com.fc.bean.Student">
<!--SQL语句,参数使用固定格式: #{} -->
SELECT * FROM student WHERE id = #{arg0}
</select>
</mapper>
【注意】mapper 配置文件建议声明在 resources 文件目录下
7、将 Mapper.xml 注册到 mybatis-config.xml 中
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--MyBatis配置-->
<configuration>
<!--Mapper注册-->
<mappers>
<!--注册Mapper文件的所在位置-->
<mapper resource="StudentMapper.xml"/>
</mappers>
</configuration>
8、编写测试类
流程【固定格式】
- 读取配置文件
- 获取 SqlSession 工厂
- 获取 SqlSession 对象
- 通过 SqlSession 获取接口的代理对象
- 通过代理对象调用方法操作数据库
- 关闭资源【重点】
案例代码
public class StudentTest {
// 使用@Test注解进行单元测试
@Test
public void testSelectStudentById() {
try {
// 读取配置文件
InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
// 获取SqlSession工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resource);
// 获取SqlSession对象
SqlSession sqlSession = factory.openSession();
// 通过SqlSession获取接口的代理对象
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
// 通过代理对象调用查询方法操作数据库并获取实体类对象
Student student = mapper.selectStudentById(1);
// 关闭资源
sqlSession.close();
// 展示
System.out.println(student);
} catch (IOException e) {
e.printStackTrace();
}
}
}
【补充】iBatis 传统操作方式
public class StudentTest {
@Test
public void testTraditionalWay() {
try {
// 读取配置文件
InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
// 获取SqlSession工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resource);
// 获取SqlSession对象
SqlSession sqlSession = factory.openSession();
// 使用SqlSession对象查询单条数据,需要的参数为接口中的方法的完整路径名以及参数,获取对应的实体类对象
Object o = sqlSession.selectOne("com.fc.dao.StudentDao.selectStudentById", 2);
// 关闭资源
sqlSession.close();
// 展示
System.out.println(o);
} catch (IOException e) {
e.printStackTrace();
}
}
}
细节补充
特殊符号处理
在XML中,有一些符号作为作为XML 的标记符号,不能直接使用,可以通过其他方式对特定字符进行转换
<![CDATA[]>
在 xml 文件中,被<![CDATA[]]>包括起来的内容会被原样输出
案例代码
select * from student where id <![CDATA[<=]]> 4
实体引用(字符实体)
实体 | 实体引用 | 描述 |
---|---|---|
lt | < | < |
gt | > | > |
amp | & | & |
apos | ' | ’ |
quot | " | " |
案例代码
select * from student where id <= 4
#{}与${}区别【重点】
- #{}在预编译时,相当于一个参数占位符"?",用来补全预编译语句,能够防止注入式攻击。
- ${}表示内容的原样输出,相当于单纯的内容替换,拼接完成后才会对SQL进行编译、执行。
使用 properties 配置文件
对于mybatis-config.xml的核心配置中,如果存在需要频繁改动的数据内容,可以提取到properties中
声明 jdbc.properties
# jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/FC2021?useSSL=false&useUnicode=true&characterEncoding=UTF8
jdbc.username=root
jdbc.password=root
修改mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--MyBatis配置-->
<configuration>
<!--添加properties配置文件路径(外部配置、动态替换)-->
<properties resource="jdbc.properties" />
<!--JDBC环境配置、选中默认环境-->
<environments default="MySqlDB">
<!--MySql数据库环境配置-->
<environment id="MySqlDB">
<!--事务管理-->
<transactionManager type="JDBC"/>
<!--连接池相关配置-->
<dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
<!--使用$ + 占位符-->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--Mapper注册-->
<mappers>
<!--注册Mapper文件的所在位置-->
<mapper resource="StudentMapper.xml"/>
</mappers>
</configuration>
类型别名
为实体类定义别名,提高书写效率。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--MyBatis配置-->
<configuration>
...
<!--定义别名-->
<typeAliases>
<!--给指定类起一个别名-->
<typeAlias type="com.fc.bean.Student" alias="Student" />
</typeAliases>
...
</configuration>
【注意】声明别名的 typeAliases 标签必须跟在 properties 标签后,environments 标签之前
使用 log4j2 输出执行日志
1、pom.xml 配置文件中添加 log4j2 依赖
<!-- log4j2日志依赖 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
</dependency>
2、mybatis-config.xml 中添加日志设置
<settings>
<!--配置日志框架为log4j2-->
<setting name="logImpl" value="LOG4J2"/>
</settings>
3、创建并配置 log4j2.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="OFF">
<!-- 配置日志信息输出目的地 -->
<Appenders>
<!-- 输出到控制台 -->
<Console name="Console" target="SYSTEM_OUT">
<!--配置日志信息的格式 -->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %style{[%t]}{bright,magenta} %highlight{%-5level}{ERROR=Bright RED, WARN=Bright Yellow, INFO=Bright Green, DEBUG=Bright Cyan, TRACE=Bright White} %logger{36} - %msg%n"/>
</Console>
</Appenders>
<!-- 定义logger,只有定义了logger并引入了appender,appender才会有效 -->
<Loggers>
<!-- 将dao接口所在的包填写进去,并用在控制台和文件中输出 -->
<logger name="com.fc.dao" level="TRACE" additivity="false">
<AppenderRef ref="Console"/>
</logger>
<Root level="INFO">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
参数绑定【重点】
序号参数绑定【不要用】
1、dao 层接口
public interface StudentDao {
/**
* 根据id和name查询对应的学生
* 使用原生序号参数绑定
*
* @param id 学生的id
* @param name 学生的name
* @return 返回对应的学生对象
*/
Student selectStudentByIdAndName(Integer id, String name);
}
2、mapper 配置文件
<?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">
<mapper namespace="com.fc.dao.StudentDao">
<select id="selectStudentByIdAndName" resultType="Student" >
select * from student where id = #{param1} and name = #{param2}
</select>
</mapper>
【注意】参数绑定除了能用 param (从1开始依次后续)还可以使用 arg (从0开始依次后续)
<select id="selectStudentByIdAndName" resultType="Student" > select * from student where id = #{arg0} and name = #{arg1} </select>
3、测试类
public class StudentTest {
@Test
public void testSelectStudentByIdAndName() {
try {
// 读取配置文件
InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
// 获取SqlSession工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resource);
// 获取SqlSession对象
SqlSession sqlSession = factory.openSession();
// 通过SqlSession获取接口的代理对象
StudentDao mapper = sqlSession.getMapper(StudentSelectDao.class);
// 调用接口中的方法
Student student = mapper.selectStudentByIdAndName(1, "张三");
// 关闭资源
sqlSession.close();
System.out.println(student);
} catch (IOException e) {
e.printStackTrace();
}
}
}
注解参数绑定【推荐】
1、dao 层接口
public interface StudentDao {
/**
* 根据id和age查询对应的学生
* 使用@Param注解进行参数绑定
*
* @param id 学生的id
* @param age 学生的age
* @return 返回对应的学生对象
*/
Student findByTwoParam(@Param("id") Integer id, @Param("age") Integer age);
}
2、mapper 配置文件
<?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">
<mapper namespace="com.fc.dao.StudentDao">
<select id="findByTwoParam" resultType="Student">
<!--获取声明的注解中对应的值-->
select * from student where id = #{id} and age = #{age}
</select>
</mapper>
3、测试类
public class StudentTest {
@Test
public void testSelectStudentByIdAndGender() {
try {
// 读取配置文件
InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
// 获取SqlSession工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resource);
// 获取SqlSession对象
SqlSession sqlSession = factory.openSession();
// 通过SqlSession获取接口的代理对象
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
// 调用接口中的方法
Student student = mapper.findByTwoParam(1, "男");
// 关闭资源
sqlSession.close();
System.out.println(student);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Map 参数绑定【不要用】
1、dao 层接口
public interface StudentDao {
/**
* 根据id和info查询对应的学生
*
* @param map 传入包含学生信息的map
* @return 返回对应的学生对象
*/
Student selectStudentByIdAndGender(Map<String, Object> map);
}
2、mapper 配置文件
<?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">
<mapper namespace="com.fc.dao.StudentDao">