MyBatis
MyBatis 入门概述
MyBatis 概念
MyBatis 是一款优秀的 持久层框架,用于对传统的 JDBC 操作进行优化封装,简化数据库操作的复杂过程。
-
它的前身是 Apache 的开源项目 iBatis,2010 年迁移到 Google Code 并更名为 MyBatis,2013 年 11 月又迁移到了 GitHub。
持久层 是Java 开发中专门负责 将程序中的数据存储到数据库,或者从数据库中读取数据 的代码部分。
JavaEE 三层架构:
- 表现层:负责用户交互,通常是前端或接口。
- 业务层:处理核心业务逻辑。
- 持久层:与数据库交互,负责数据的存储和查询。
框架 是一种 半成品软件,为开发者提供了一套可以重复使用的代码模型。开发者在框架的基础上编写代码,可以更高效、更规范地完成软件开发。
JDBC 缺点
通过下面代码分析 JDBC 都存在什么缺点:
传统的 JDBC 开发方式存在以下问题:
- 连接信息硬编码问题:
- 如上图框1所示,在 JDBC 中,数据库驱动、连接地址、用户名和密码等信息是写死在代码中的。如果要切换数据库(比如从 MySQL 换到 PostgreSQL),需要修改多处源代码。
- SQL 与代码耦合紧密:
- 如上图框2所示,JDBC 的 SQL 写在代码中,如果表结构变化,SQL 需要修改,同时代码也需要重新编译和发布。
- 操作繁琐:
- 手动设置参数:如上图框3所示,开发者需要手动将 Java 对象的属性绑定到 SQL 的参数中。
- 手动封装结果集:如上图框4所示,查询结果需要逐行读取并手动映射到 Java 对象,既繁琐又容易出错。
MyBatis 的优化
- 配置文件管理:
- 数据库连接信息、SQL 语句都集中在 XML 文件中,易于修改和维护。
- 简化操作:
- MyBatis 自动完成参数绑定和结果映射的工作,开发者只需专注于业务逻辑。
- 灵活性:
- 支持动态 SQL,可以根据条件生成不同的 SQL 语句,避免手动拼接字符串带来的安全和效率问题。
如下图所示
Mybatis快速入门
1. 需求描述
- 我们需要查询
user表中的所有数据。
2. 准备工作
2.1 创建 user 表及插入数据
通过以下 SQL 脚本创建数据库和表,并插入一些测试数据:
CREATE DATABASE mybatis;
USE mybatis;
DROP TABLE IF EXISTS tb_user;
CREATE TABLE tb_user (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(20),
password VARCHAR(20),
gender CHAR(1),
addr VARCHAR(30)
);
INSERT INTO tb_user VALUES (1, 'zhangsan', '123', '男', '北京');
INSERT INTO tb_user VALUES (2, '李四', '234', '女', '天津');
INSERT INTO tb_user VALUES (3, '王五', '11', '男', '西安');
2.2 创建项目并添加依赖
在项目的 pom.xml 文件中添加以下依赖:
<dependencies>
<!-- MyBatis 依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!-- JUnit 测试框架,专用于单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope> <!-- 表示此依赖只在测试阶段使用 -->
</dependency>
<!-- SLF4J 日志框架 API,用于统一日志接口 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.20</version>
</dependency>
<!-- Logback 日志实现依赖,用于实际的日志记录 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- Logback 核心依赖,与 logback-classic 搭配使用 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
注意:需要在项目的
resources目录下添加logback的日志配置文件(如logback.xml)。
3. 编写配置文件
3.1 MyBatis 核心配置文件
在 模块下的resources 目录下创建Mybatis的配置文件 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">
<configuration>
<!-- 定义别名,用于简化类名的引用 -->
<typeAliases>
<package name="com.itheima.pojo"/> <!-- 扫描指定包中的类并生成别名 -->
</typeAliases>
<!-- 配置数据库连接环境 -->
<environments default="development"> <!-- 设置默认使用的环境 -->
<environment id="development"> <!-- 环境标识,表示开发环境 -->
<transactionManager type="JDBC"/> <!-- 使用 JDBC 事务管理 -->
<dataSource type="POOLED"> <!-- 使用连接池数据源 -->
<!-- 数据库连接属性 -->
<property name="driver" value="com.mysql.jdbc.Driver"/> <!-- MySQL 驱动类 -->
<property name="url" value="jdbc:mysql:///mybatis?useSSL=false"/> <!-- 数据库 URL -->
<property name="username" value="root"/> <!-- 数据库用户名 -->
<property name="password" value="1234"/> <!-- 数据库密码 -->
</dataSource>
</environment>
</environments>
<!-- 配置 SQL 映射文件 -->
<mappers>
<mapper resource="UserMapper.xml"/> <!-- 引用 UserMapper.xml 文件,加载映射规则 -->
</mappers>
</configuration>
3.2 编写 SQL 映射文件
在模块的 resources 目录下创建映射配置文件 UserMapper.xml,用于编写 SQL(统一管理sql语句,解决硬编码问题):
<?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="test"> <!-- namespace 用于标识当前 Mapper,与 Java 接口方法名绑定 -->
<!-- 定义一个 SQL 查询语句 -->
<select id="selectAll" resultType="com.itheima.pojo.User">
<!--
id="selectAll":唯一标识此 SQL 查询,Java 代码中通过 "namespace.id" 调用此查询
resultType="com.itheima.pojo.User":将查询结果自动映射到 User 类对象
-->
SELECT * FROM tb_user; <!-- SQL 语句:查询 tb_user 表中所有数据 -->
</select>
</mapper>
4. 编写代码
4.1 创建实体类 User
在 com.itheima.pojo 包下创建 User 类:
package com.itheima.pojo;
public class User {
private int id;
private String username;
private String password;
private String gender;
private String addr;
//省略 setter 和 getter
4.2 编写测试类 MyBatisDemo
在 com.itheima 包下创建 MyBatisDemo 测试类:
package com.itheima;
import com.itheima.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MyBatisDemo {
public static void main(String[] args) throws IOException {
// 1. 加载 MyBatis 核心配置文件,获取 SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取 SqlSession 对象,用它来执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. 执行 SQL
List<User> users = sqlSession.selectList("test.selectAll");
System.out.println(users);
// 4. 释放资源
sqlSession.close();
}
}
5. 问题与解决
警告:SQL 映射文件中的表名报红,如下:
- 原因:IDEA 没有与数据库建立连接,导致无法识别表结构。(但实际上它并不影响程序的执行)
- 解决方法:在 IDEA 中配置 MySQL 数据库连接:
- 点击右侧的
Database面板,在展开的界面 选择+→Data Source→MySQL。 - 在弹出的界面填写连接信息(如 URL、用户名、密码)。
- 点击测试连接并完成配置,如下界面。
- 点击右侧的
6. 至此,就可以直接在该界面进行数据库的操作,也可以编写SQL语句
Mapper代理开发
Mapper代理开发概述
-
传统方式的问题:
在之前的开发中,需要通过
namespace.id写成固定的字符串的方式手动调用 SQL,这种方式存在 硬编码问题,不利于后期维护。
比如以下代码,"test.selectAll"是硬编码://通过 MyBatis 框架执行 SQL 查询,并将查询结果封装为 `List<User>` 类型的数据集合 List<User> users = sqlSession.selectList("test.selectAll");这里调用 selectList() 方法传递的参数是映射配置文件中的
namespace.id值。这样写也不便于后期的维护。 -
Mapper 代理方式的优点:
如果使用Mapper 代理方式(如下)则不存在硬编码问题:
// 获取 UserMapper 的代理对象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 调用 Mapper 中定义的 selectAll 方法,查询所有用户 List<User> users = userMapper.selectAll();- 简化 SQL 调用:通过定义接口,直接调用接口方法执行 SQL,无需关心
namespace.id。 - 无硬编码问题:接口方法名与 SQL 映射文件中的
id一一对应,自动完成调用。
- 简化 SQL 调用:通过定义接口,直接调用接口方法执行 SQL,无需关心
MyBatis 官网推荐使用 Mapper 代理方式,它是当前最主流的开发方式。
使用 Mapper 代理的要求
-
定义Mapper 接口名称要与 SQL 映射文件名称一致,并且将Mapper接口和SQL映射文件放置于同一目录下。 如下图:
-
设置SQL映射文件的
namespace属性为Mapper接口全限定名(包含包路径): -
在 Mapper 接口中定义方法,方法名要与 SQL 映射文件中sql语句的
id一致,并保持参数类型和返回值类型也一致:
Mapper 代理方式的案例实现
1. 定义 Mapper 接口
在 com.itheima.mapper 包下创建 UserMapper 接口:
package com.itheima.mapper;
import com.itheima.pojo.User;
import java.util.List;
public interface UserMapper {
List<User> selectAll(); // 查询所有用户
User selectById(int id); // 根据 ID 查询用户
}
2. 编写 SQL 映射文件
在 resources 下创建 com/itheima/mapper 目录,并在该目录下创建 UserMapper.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">
<mapper namespace="com.itheima.mapper.UserMapper"> <!-- 设置 namespace 必须为对应 Mapper 接口的全限定名 -->
<!-- 查询所有用户 -->
<select id="selectAll" resultType="com.itheima.pojo.User">
SELECT * FROM tb_user;
</select>
<!-- 根据 ID 查询用户 -->
<select id="selectById" parameterType="int" resultType="com.itheima.pojo.User">
SELECT * FROM tb_user WHERE id = #{id};
</select>
</mapper>
3. 编写测试类
在 com.itheima 包下创建 MyBatisDemo2 测试类:
package com.itheima;
import com.itheima.mapper.UserMapper;
import com.itheima.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
import java.util.List;
public class MyBatisDemo2 {
public static void main(String[] args) throws Exception {
// 1. 加载 MyBatis 核心配置文件,获取 SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取 SqlSession 对象,用它来执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. 获取 Mapper 接口的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 4. 调用接口方法执行 SQL
List<User> users = userMapper.selectAll(); // 查询所有用户
System.out.println(users);
User user = userMapper.selectById(1); // 根据 ID 查询用户
System.out.println(user);
// 5. 释放资源
sqlSession.close();
}
}
注意:
如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以启用包扫描的方式简化SQL映射文件的加载。也就是将核心配置文件 mybatis-config.xml 的加载映射配置文件的配置修改为
<mappers>
<!--加载sql映射文件-->
<!-- <mapper resource="com/itheima/mapper/UserMapper.xml"/>-->
<!-- 使用包扫描方式加载 Mapper 接口 -->
<package name="com.itheima.mapper"/>
</mappers>
MyBatis 核心配置文件
MyBatis 的核心配置文件(mybatis-config.xml)是 MyBatis 框架运行的基础,它定义了数据库连接、事务管理、类型映射等重要内容。以下是核心配置文件的主要功能和具体讲解。
我们可以通过查询官网看可以配置的内容
接下来我们先对里面的一些配置进行讲解。
核心配置文件的结构
典型的核心配置文件内容如下:
<configuration>
<!-- 配置多环境 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--数据库连接信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--数据库连接信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
<!-- 配置类型别名 -->
<typeAliases>
<package name="com.itheima.pojo"/>
</typeAliases>
<!-- 配置映射文件或 Mapper 包扫描 -->
<mappers>
<!-- 加载映射文件 -->
<!-- <mapper resource="com/itheima/mapper/UserMapper.xml"/> -->
<!-- 使用包扫描方式 -->
<package name="com.itheima.mapper"/>
</mappers>
</configuration>
多环境配置
在 <environments> 标签中可以定义多个数据库环境 environment,使用 id 给每段环境起名以进行区分,并在environments 中使用 default='环境id' 来指定使用哪儿段配置。我们一般就配置一个 environment 即可。
-
多环境的作用:
- 当项目需要连接不同的数据库(如开发环境和测试环境)时,可以通过不同的
environment配置切换。
- 当项目需要连接不同的数据库(如开发环境和测试环境)时,可以通过不同的
-
配置示例: 见上 “典型的核心配置文件内容”的 2-24行
-
配置中几个关键元素:
<transactionManager>:事务管理器,一般使用类型JDBC。<dataSource>:数据源配置,常用类型POOLED(连接池方式)。default:指定默认环境(如development)。
类型别名配置
在映射配置文件中的 resultType 属性需要配置数据封装的类型(类的全限定名)。Mybatis提供了 类型别名 (typeAliases) 可以简化这部分的书写。
-
问题:如果不配置类型别名,需要使用类的全限定名:
<select id="selectAll" resultType="com.itheima.pojo.User"> SELECT * FROM tb_user; </select> -
解决方案:
在核心配置文件中通过<typeAliases>标签配置类型别名:<typeAliases> <!-- 指定实体类所在包名 --> <package name="com.itheima.pojo"/> </typeAliases>配置类型别名后,可以简化为类名(不区分大小写):
<select id="selectAll" resultType="user"> SELECT * FROM tb_user; </select> -
工作原理:
- MyBatis 自动为包下的每个类生成别名,别名默认为类名(不区分大小写)。
- 如:
com.itheima.pojo.User的别名为user。
注解实现CRUD
使用注解开发会比配置文件开发更加方便。如下就是使用注解进行开发
@Select(value = "select * from tb_user where id = #{id}")
public User select(int id);
注意:注解是用来替换映射配置文件方式配置的,所以使用了注解,就不需要再映射配置文件中书写对应的
statement
Mybatis 针对 CURD 操作都提供了对应的注解,已经做到见名知意。如下:
- 查询 :@Select
- 添加 :@Insert
- 修改 :@Update
- 删除 :@Delete
使用 Mybatis 的注解开发的案例
代码实现:
-
将之前案例中
UserMapper.xml中的 根据id查询数据 的statement注释掉 -
在
UserMapper接口的selectById方法上添加注解 -
运行测试程序也能正常查询到数据
我们课程上只演示这一个查询的注解开发,其他的同学们下来可以自己实现,都是比较简单。
注意:在官方文档中 入门 中有这样的一段话:
所以,注解完成简单功能,配置文件完成复杂功能。
而我们之前写的动态 SQL 就是复杂的功能,如果用注解使用的话,就需要使用 Mybatis 提供的SQL构建器来完成,而对应的代码如下:
上述代码将java代码和SQL语句融到了一块,使得代码的可读性大幅度降低。