MyBatis 是一款优秀的持久层框架,它对JDBC进行了封装,解决了原生JDBC的冗余代码、参数硬编码、结果集手动封装等问题。
- 核心特点:SQL与Java代码分离、轻量级、SQL可控、半自动ORM(对象关系映射)
- 适用场景:企业级项目、复杂SQL查询、需要性能优化的业务系统
入门示例
1.1 开发环境
JDK 8+
Maven 3.6+
MySQL 5.7/8.0
1.2 数据库准备
创建测试表user,执行SQL脚本:
sql
CREATE DATABASE mybatis_demo;
USE mybatis_demo;
CREATE TABLE `user` (
`id` INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID',
`username` VARCHAR(20) NOT NULL COMMENT '用户名',
`password` VARCHAR(32) NOT NULL COMMENT '密码',
`age` INT COMMENT '年龄',
`email` VARCHAR(50) COMMENT '邮箱'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `user` VALUES (1,'张三','123456',20,'zhangsan@qq.com');
1.3 Maven依赖
创建Maven项目,在pom.xml引入核心依赖:
xml
<?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.example</groupId>
<artifactId>mybatis-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 依赖管理 -->
<dependencies>
<!-- MyBatis核心依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
</dependencies>
<!-- 编译配置 -->
<build>
<resources>
<!-- 让Maven打包时包含XML文件 -->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
</project>
1.4 项目结构(基于Maven)
src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ ├── pojo // 实体类
│ │ │ └── User.java
│ │ ├── mapper // 映射器接口
│ │ │ └── UserMapper.java
│ │ └── util // 工具类
│ │ └── MyBatisUtil.java
│ └── resources
│ ├── mybatis-config.xml // MyBatis核心配置文件
│ └── com
│ └── example
│ └── mapper
│ └── UserMapper.xml // SQL映射文件
└── test
└── java
└── com
└── example
└── MyBatisTest.java // 测试类
1.5 核心代码编写
1. 实体类 User.java
对应数据库表的实体对象,实现ORM映射
java
package com.example.pojo;
/**
* 用户实体类
*/
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
private String email;
// 无参构造(必须)
public User() {}
// getter/setter
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
// toString
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
", email='" + email + '\'' +
'}';
}
}
2. MyBatis核心配置文件 mybatis-config.xml
配置数据库连接、环境、映射器等核心参数
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>
<!-- 环境配置:开发环境 -->
<environments default="development">
<environment id="development">
<!-- 事务管理器:JDBC事务 -->
<transactionManager type="JDBC"/>
<!-- 数据源:连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/database_name?useSSL=false&serverTimezone=UTC&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="你的数据库密码"/>
</dataSource>
</environment>
</environments>
<!-- 注册映射器 -->
<mappers>
<mapper resource="com/example/mapper/UserMapper.xml"/>
</mappers>
</configuration>
3. 映射器接口 UserMapper.java
MyBatis通过接口代理实现SQL调用,无需编写实现类
java
package com.example.mapper;
import com.example.pojo.User;
import org.apache.ibatis.annotations.Select;
/**
* 用户映射器接口
*/
public interface UserMapper {
/**
* 根据ID查询用户
* @param id 用户ID
* @return 用户对象
*/
User selectUserById(Integer id);
}
4. SQL映射文件 UserMapper.xml
编写SQL语句,与接口方法绑定
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接口(必须) -->
<mapper namespace="com.example.mapper.UserMapper">
<!--
select:查询标签
id:对应接口方法名
resultType:返回值类型
parameterType:参数类型(可省略)
-->
<select id="selectUserById" resultType="com.example.pojo.User">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
使用IDEA编译器,建议下载MybatisX插件快速跳转到mapper文件
5. MyBatis工具类 MyBatisUtil.java
封装SqlSessionFactory创建逻辑,全局单例
java
package com.example.util;
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;
/**
* MyBatis工具类:获取SqlSession
*/
public class MyBatisUtil {
// 静态单例SqlSessionFactory
private static SqlSessionFactory sqlSessionFactory;
// 静态代码块:项目启动时加载配置文件
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取SqlSession会话
* true:自动提交事务
* false:手动提交事务(默认)
*/
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession(true);
}
}
6. 测试类 MyBatisTest.java
验证环境是否搭建成功
java
package com.example;
import com.example.mapper.UserMapper;
import com.example.pojo.User;
import com.example.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class MyBatisTest {
@Test
public void testSelectUserById() {
// 1. 获取SqlSession
try (SqlSession session = MyBatisUtil.getSqlSession()) {
// 2. 获取Mapper接口代理对象
UserMapper mapper = session.getMapper(UserMapper.class);
// 3. 调用方法执行SQL
User user = mapper.selectUserById(1);
// 4. 输出结果
System.out.println(user);
}
}
}
1.6 运行结果
User{id=1, username='张三', password='123456', age=20, email='zhangsan@qq.com'}
MyBatis核心组件详解
MyBatis的核心工作流程:
配置文件 -> SqlSessionFactoryBuilder -> SqlSessionFactory -> SqlSession -> Mapper代理对象 -> 执行SQL
2.1 核心组件
| 组件 | 作用 | 生命周期 |
|---|---|---|
| SqlSessionFactoryBuilder | 解析配置文件,构建SqlSessionFactory | 方法级别(用完即毁) |
| SqlSessionFactory | 创建SqlSession,全局单例 | 应用级别 |
| SqlSession | 执行SQL、管理事务 | 请求/方法级别 |
| Mapper接口 | 定义SQL方法,无实现类 | 方法级别 |
| Mapper XML | 编写SQL语句,绑定接口 | 应用级别 |
2.2 核心API示例
java
// 1. 构建工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(输入流);
// 2. 创建会话
SqlSession session = factory.openSession(); // 手动提交
SqlSession session = factory.openSession(true); // 自动提交
// 3. 获取Mapper
UserMapper mapper = session.getMapper(UserMapper.class);
// 4. 执行SQL
User user = mapper.selectUserById(1);
// 5. 手动提交事务(增删改必须)
session.commit();
// 6. 关闭会话
session.close();
基础CRUD操作(XML映射)
企业开发中增删改查是核心操作,本节配套完整示例。
3.1 映射器接口新增方法
java
package com.example.mapper;
import com.example.pojo.User;
import java.util.List;
public interface UserMapper {
// 1. 根据ID查询
User selectUserById(Integer id);
// 2. 查询所有用户
List<User> selectAllUser();
// 3. 新增用户
int insertUser(User user);
// 4. 更新用户
int updateUser(User user);
// 5. 删除用户
int deleteUser(Integer id);
}
3.2 映射文件编写SQL
xml
<mapper namespace="com.example.mapper.UserMapper">
<!-- 1. 根据ID查询 -->
<select id="selectUserById" resultType="com.example.pojo.User">
SELECT * FROM user WHERE id = #{id}
</select>
<!-- 2. 查询所有 -->
<select id="selectAllUser" resultType="com.example.pojo.User">
SELECT * FROM user
</select>
<!-- 3. 新增用户 -->
<insert id="insertUser" parameterType="com.example.pojo.User">
INSERT INTO user(username,password,age,email)
VALUES (#{username},#{password},#{age},#{email})
</insert>
<!-- 4. 更新用户 -->
<update id="updateUser" parameterType="com.example.pojo.User">
UPDATE user
SET username=#{username},password=#{password},age=#{age},email=#{email}
WHERE id=#{id}
</update>
<!-- 5. 删除用户 -->
<delete id="deleteUser">
DELETE FROM user WHERE id=#{id}
</delete>
</mapper>
3.3 测试CRUD
java
@Test
public void testCRUD() {
try (SqlSession session = MyBatisUtil.getSqlSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
// 1. 新增
User user = new User();
user.setUsername("李四");
user.setPassword("666666");
user.setAge(22);
user.setEmail("lisi@qq.com");
int insert = mapper.insertUser(user);
System.out.println("新增行数:" + insert);
// 2. 查询所有
List<User> userList = mapper.selectAllUser();
System.out.println("所有用户:" + userList);
// 3. 更新
user.setAge(23);
int update = mapper.updateUser(user);
System.out.println("更新行数:" + update);
// 4. 删除
int delete = mapper.deleteUser(user.getId());
System.out.println("删除行数:" + delete);
}
}
3.4 参数传递规则
-
单个参数 :
#{任意名称}即可获取 -
实体参数 :
#{属性名}自动匹配 -
多个参数 :使用
@Param注解绑定javaUser selectUserByUsernameAndPwd(@Param("username") String username, @Param("password") String pwd);xml<select id="selectUserByUsernameAndPwd" resultType="User"> SELECT * FROM user WHERE username=#{username} AND password=#{password} </select> -
Map参数 :
#{key}获取值
核心配置文件详解
mybatis-config.xml 是MyBatis的核心配置,企业开发中常用配置如下:
4.1 外部属性文件(db.properties)
分离数据库配置,便于环境切换
- resources下创建
db.properties
properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_demo?useSSL=false&serverTimezone=UTC
jdbc.username=root
jdbc.password=123456
- 核心配置文件引入
xml
<configuration>
<!-- 引入外部属性文件 -->
<properties resource="db.properties"/>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<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>
</configuration>
4.2 类型别名(简化类名)
xml
<typeAliases>
<!-- 单个类别名 -->
<typeAlias type="com.example.pojo.User" alias="User"/>
<!-- 包扫描:默认别名=类名首字母小写 -->
<package name="com.example.pojo"/>
</typeAliases>
映射文件中可直接使用别名:
xml
<select id="selectUserById" resultType="User">
4.3 全局设置(必备)
xml
<settings>
<!-- 开启驼峰命名自动映射:user_name -> userName -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 开启日志 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>
4.4 包扫描映射器
xml
<mappers>
<!-- 包扫描:自动注册所有Mapper接口 -->
<package name="com.example.mapper"/>
</mappers>
动态SQL(企业高频核心)
动态SQL是MyBatis的核心优势,根据条件自动拼接SQL,解决复杂业务查询问题。
5.1 常用标签
1. <if>:条件判断
场景:多条件模糊查询用户
xml
<!-- 多条件查询用户 -->
<select id="selectUserByCondition" resultType="User">
SELECT * FROM user
WHERE 1=1
<if test="username != null and username != ''">
AND username LIKE CONCAT('%',#{username},'%')
</if>
<if test="age != null">
AND age = #{age}
</if>
</select>
2. <where>:智能处理WHERE
自动去除多余的AND/OR,无需写1=1
xml
<select id="selectUserByCondition" resultType="User">
SELECT * FROM user
<where>
<if test="username != null and username != ''">
AND username LIKE CONCAT('%',#{username},'%')
</if>
<if test="age != null">
AND age = #{age}
</if>
</where>
</select>
3. <set>:智能更新
自动去除多余的逗号,用于更新操作
xml
<update id="updateUserDynamic">
UPDATE user
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="age != null">age=#{age},</if>
<if test="email != null">email=#{email}</if>
</set>
WHERE id=#{id}
</update>
4. <foreach>:循环遍历
场景1:批量删除(IN查询)
xml
<delete id="deleteBatch">
DELETE FROM user WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
接口方法:
java
int deleteBatch(@Param("ids") List<Integer> ids);
场景2:批量新增
xml
<insert id="insertBatch">
INSERT INTO user(username,password,age,email)
VALUES
<foreach collection="list" item="user" separator=",">
(#{user.username},#{user.password},#{user.age},#{user.email})
</foreach>
</insert>
5. <sql>+<include>:抽取重复SQL
xml
<!-- 抽取公共字段 -->
<sql id="userColumns">id,username,password,age,email</sql>
<!-- 使用公共字段 -->
<select id="selectAllUser" resultType="User">
SELECT <include refid="userColumns"/> FROM user
</select>
结果映射(ResultMap)
当数据库字段名与实体属性名不一致 ,或需要关联查询 时,使用ResultMap手动映射。
6.1 基础映射(字段名不一致)
数据库字段:user_name、user_age
实体属性:username、age
xml
<!-- 定义结果映射 -->
<resultMap id="UserResultMap" type="User">
<!-- 主键映射 -->
<id column="id" property="id"/>
<!-- 普通字段映射:column=数据库字段,property=实体属性 -->
<result column="user_name" property="username"/>
<result column="user_age" property="age"/>
</resultMap>
<!-- 使用ResultMap -->
<select id="selectUserById" resultMap="UserResultMap">
SELECT id,user_name,user_age FROM user WHERE id=#{id}
</select>
6.2 一对一映射(association)
场景:一个用户对应一个账户
xml
<resultMap id="UserAccountMap" type="User">
<id column="u_id" property="id"/>
<result column="username" property="username"/>
<!-- 一对一关联 -->
<association property="account" javaType="Account">
<id column="a_id" property="id"/>
<result column="money" property="money"/>
</association>
</resultMap>
<select id="selectUserAndAccount" resultMap="UserAccountMap">
SELECT u.id u_id, u.username, a.id a_id, a.money
FROM user u
LEFT JOIN account a ON u.id = a.user_id
WHERE u.id=#{id}
</select>
6.3 一对多映射(collection)
场景:一个用户对应多个订单
xml
<resultMap id="UserOrderMap" type="User">
<id column="u_id" property="id"/>
<result column="username" property="username"/>
<!-- 一对多关联 -->
<collection property="orderList" ofType="Order">
<id column="o_id" property="id"/>
<result column="order_no" property="orderNo"/>
</collection>
</resultMap>
MyBatis缓存机制
MyBatis自带两级缓存,提升查询性能,企业开发中必用。
7.1 一级缓存(默认开启)
- 级别:
SqlSession级别(会话缓存) - 生命周期:会话开启->关闭
- 特点:自动开启,无需配置
示例:
java
@Test
public void testFirstCache() {
try (SqlSession session = MyBatisUtil.getSqlSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
// 第一次查询:查询数据库
User user1 = mapper.selectUserById(1);
// 第二次查询:走一级缓存
User user2 = mapper.selectUserById(1);
// 结果:同一个对象
System.out.println(user1 == user2); // true
}
}
缓存失效场景:
- 不同SqlSession
- 执行增删改操作
- 手动清空缓存:
session.clearCache()
7.2 二级缓存(手动开启)
- 级别:
Mapper级别(全局缓存) - 生命周期:应用运行期间
- 开启步骤:
- 核心配置文件开启缓存
xml
<setting name="cacheEnabled" value="true"/>
- 映射文件开启缓存
xml
<mapper namespace="com.example.mapper.UserMapper">
<!-- 开启二级缓存 -->
<cache/>
</mapper>
- 实体类实现序列化
java
public class User implements Serializable {}
注解开发
MyBatis支持注解+XML混合开发,简单SQL用注解,复杂SQL用XML。
8.1 基础注解
java
public interface UserMapper {
// 查询
@Select("SELECT * FROM user WHERE id=#{id}")
User selectUserById(Integer id);
// 新增
@Insert("INSERT INTO user(username,password) VALUES (#{username},#{password})")
int insertUser(User user);
// 更新
@Update("UPDATE user SET username=#{username} WHERE id=#{id}")
int updateUser(User user);
// 删除
@Delete("DELETE FROM user WHERE id=#{id}")
int deleteUser(Integer id);
}
8.2 注解+动态SQL
java
@Select("<script>" +
"SELECT * FROM user " +
"<where>" +
"<if test='username != null'>AND username=#{username}</if>" +
"</where>" +
"</script>")
List<User> selectUserByCondition(@Param("username") String username);
SpringBoot整合MyBatis(企业主流)
企业开发中SpringBoot + MyBatis是标准架构,本节提供完整整合示例。
9.1 Maven依赖
xml
<!-- SpringBoot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis SpringBoot Starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
9.2 application.yml配置
yaml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_demo?serverTimezone=UTC
username: root
password: 123456
# MyBatis配置
mybatis:
# 映射文件路径
mapper-locations: classpath:com/example/mapper/*.xml
# 别名包
type-aliases-package: com.example.pojo
# 驼峰命名
configuration:
map-underscore-to-camel-case: true
9.3 核心代码
- Mapper接口添加
@Mapper注解
java
@Mapper // SpringBoot自动扫描
public interface UserMapper {
User selectUserById(Integer id);
}
- Service层
java
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User getUserById(Integer id) {
return userMapper.selectUserById(id);
}
}
- Controller层
java
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User getUser(@PathVariable Integer id) {
return userService.getUserById(id);
}
}
9.4 启动测试
访问:http://localhost:8080/user/1
返回用户JSON数据,整合成功!
实战技巧
10.1 分页插件(PageHelper)
企业必备分页工具,无需手写limit
- 依赖
xml
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.2</version>
</dependency>
- 使用
java
@Test
public void testPage() {
// 分页:页码,每页条数
PageHelper.startPage(1, 2);
List<User> userList = userMapper.selectAllUser();
// 封装分页结果
PageInfo<User> pageInfo = new PageInfo<>(userList);
System.out.println("总条数:" + pageInfo.getTotal());
System.out.println("当前页数据:" + pageInfo.getList());
}
10.2 事务管理
SpringBoot中使用@Transactional注解
java
@Service
public class UserService {
@Transactional // 开启事务
public void addUser(User user) {
userMapper.insertUser(user);
// 异常:事务回滚
int i = 1/0;
}
}
10.3 SQL优化
- 避免
SELECT *,查询指定字段 - 动态SQL避免全表扫描
- 关联查询代替子查询
- 合理使用索引
常见问题
-
Mapper绑定异常
原因:namespace与接口路径不一致、方法名不匹配
解决:核对XML的namespace和接口全类名
-
参数绑定错误
原因:多个参数未加
@Param解决:使用
@Param注解绑定参数名 -
结果映射失败
原因:字段名与属性名不一致
解决:开启驼峰命名或使用ResultMap
-
增删改无效果
原因:未提交事务
解决:手动
session.commit()或开启自动提交
总结
- 掌握环境搭建、核心组件、基础CRUD
- 精通动态SQL、ResultMap、缓存等核心特性
- 熟练SpringBoot整合MyBatis
- 了解企业实战技巧与问题排查
MyBatis的核心是SQL与代码分离,灵活可控,是Java企业级持久层开发的首选框架。