MyBatis全面保姆指南:原生接口与自定义接口开发详解
在现代Java企业级开发中,MyBatis作为半自动化ORM框架的标杆,以其灵活的SQL控制能力和优雅的架构设计,持续赋能开发者构建高性能数据访问层。本文将深入剖析MyBatis的两种核心开发模式:
原生接口 - 快速直连SQL的轻量级方案
Mapper代理 - 企业级应用的架构首选通过对比两种模式的实现机制、适用场景与生产实践差异,您将获得:
- 精准把握
SqlSession原生API与动态代理的底层运作原理- 彻底解决「XML路径映射」「事务提交」「参数传递」三大高频痛点
- 掌握接口与SQL解耦的可维护性设计黄金法则
1、在IDEA创建一个Maven工程,pom.xml中添加以下相关依赖,添加完后记得更新Maven
<?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.ping</groupId>
<artifactId>MyBaitis1-pra</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!--在此处开始添加依赖,需要使用dependencies包裹-->
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
</dependencies>
<!--依赖添加结束-->
</project>
2、去数据库可视工具创建数据表user
use test11;
create table user(
id int primary key auto_increment,
username varchar(11),
password varchar(11),
age int
);
添加一组数据User{id=1, username=‘张三’, password=‘123456’, age=22}
-- 推荐写法(不指定id),上面指定了id自增
INSERT INTO user (username, password, age)
VALUES ('张三', '123456', 22);
3、回到IDEA创建实体类com.test.entity.User
并添加上述字段属性,Getter and Setter以及tostring
IDE 快捷生成
- IntelliJ/Eclipse:
Alt+Insert→ 选择生成方法为什么需要Getter/Setter?
- 框架依赖:MyBatis通过反射调用方法操作数据
- 数据安全:封装字段访问
- 业务扩展:可在Setter中添加验证逻辑
在实体类中添加 Getter、Setter 和 toString() 方法是 Java 开发的核心实践,三者共同作用实现数据安全、框架兼容和高效调试。
方法 核心目的 典型应用场景 Getter 安全读取数据 获取对象状态,避免直接暴露字段 Setter 安全写入数据 + 验证逻辑 数据修改时进行校验(如范围检测) toString() 对象可读性输出 日志打印、调试、监控数据展示 三者组合实现了 「数据安全」+「业务扩展」+「开发效率」 的铁三角,是现代 Java 实体类的基础设施。删除它们将导致代码健壮性、可维护性大幅下降。
User:
package com.test.entity;
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
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;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
'}';
}
}
4、在resources路径下创建MyBaits配置文件config.xml(文件名可自定义)
直接右键resources,然后New File,命名为config.xml,配置数据源信息,数据库以及用户密码改成你自己的。
config.xml文件体,键入environments,开始配置。
<?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>
<!--此处开始配置-->
</configuration>
完整的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>
<!--此处开始配置-->
<!--MyBaits运行环境配置-->
<environments default="development">
<environment id="development">
<!-- 配置JDBC事务管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置JDBC数据源连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--test11是我的数据库,此处需要改成你自己的,用户名和密码也改成你自己的-->
<property name="url"
value="jdbc:mysql://localhost:3306/test11"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--配置结束-->
</configuration>
5、MyBatis开发有两种方式
- 使用原生接口
- Mapper代理实现自定义接口
上述配置为基础配置,不管是使用原生接口还是代理接口都需要先完成以上配置。
原生接口按着文章顺序往下看使用原生接口配下去就行。
想直接了解代理接口跳过原生接口部分即可,建议按照文章顺序阅读,先了解原生接口。
使用原生接口
1、创建包com.test.mapper,在该包下创建Mapper文件UserMapper.xml
直接右键mapper包,New File,命名为UserMapper.xml
UserMapper.xml文件体,注意mapper文件体跟config的文件体不一样
<?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="">
</mapper>
完整的UserMapper.xml如下:
-
namespace通常设置为文件所在包 + 文件名,可以自定义
-
parameterType为参数数据类型,resultType为返回数值数据类型
<?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.test.mapper.UserMapper">
<!--此处开始自定义SQL-->
<select id="get" parameterType="Integer"
resultType="com.test.entity.User">
<!--写SQL,id就是传进来的参数-->
select * from user where id = #{id}
</select>
</mapper>
MyBatis 需要知道如何将 SQL 查询返回的数据库记录(ResultSet)转换成Java 对象。
所以resultType="com.test.entity.User"明确告知框架,将查询结果映射到com.test.entity.User类的实例。
2、在全局配置文件config.xml中注册UserMapper.xml
<configuration>
<!-- 注册UserMapper.xml -->
<mappers>
<mapper resource="com/test/mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
完整的config.xml如下,分为两步:
- MyBaits运行环境配置
- 注册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>
<!--此处开始配置-->
<!--MyBaits运行环境配置-->
<environments default="development">
<environment id="development">
<!-- 配置JDBC事务管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置JDBC数据源连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/test11"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--配置结束-->
<!-- 注册UserMapper.xml -->
<mappers>
<mapper resource="com/test/mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
为什么路径用“/“不用”.“ com/test/repository/UserRepository.xml” ------>“com.test.entity.User”
因为UserRepository.xml有”.“,”.“是文件名的一部分,所以前面不能有”.“,不然文件层级逻辑错误。
3、在mapper包下创建测试类Tset,调用原生接口执行SQL语句获取结果
分为3步
- 加载MyBatis配置文件
- 获取SqlSession
- 调用MyBatis原生接口执行SQL
com.test.mapper.Test
package com.test.mapper;
import com.test.entity.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
public class Test {
public static void main(String[] args) {
//加载MyBatis配置文件
InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
//获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//调用MyBatis原生接口执行SQL
String statement = "com.test.mapper.UserMapper.get";
User user = sqlSession.selectOne(statement, 2);
System.out.println(user);
}
}
4、在 pom.xml设置允许读取java以及resources路径下的 XML 文件的权限
运行测试类Test,会报错Caused by: java.io.IOException: Could not find resource com/test/mapper/UserMapper.xml
因为本项目工程路径下的java里面的xml文件是不让访问的(没有权限)。则需要在 pom.xml 中设置允许读取 java 以及resources路径下的 XML 文件。添加后记得更新maven。
<project>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
</project>
运行成功会显示User{id=1, username='张三', password='123456', age=22}
完整的pom.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.ping</groupId>
<artifactId>MyBaitis-1</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
</project>
使用自定义接口
实际开发中,更推荐第二种方式:自定义接口,开发者不需要实现该接口,只需要定义即可,具体的实现工作由Mapper代理结合配置文件完成,实现逻辑(SQL语句)配置在Mapper.xml中即可。
1、创建包com.test.repository,自定义数据访问接口(Interface)com.test.repository.UserRepository
UserRepository接口
package com.test.repository;
import com.test.entity.User;
public interface UserRepository {
public int add(User user);
public int delete(Integer id);
public int update(User user);
public User getById(Integer id);
}
2、在com.test.repository包下创建UserRepository.xml文件
直接右键repository包,New File,命名为UserRepository.xml
在UserRepository.xml自定义一套增删改查的方法,文件体同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">
<!--namespace就是命名空间,把文件位置写出来就行 -->
<mapper namespace="">
</mapper>
定义接口方法对应的SQL语句,Statement标签根据SQL执行的业务可以选择insert、delete、update、select,MyBatis会根据规则自动创建UserRepository接口实现类的代理对象。
Statement标签,每一组SQL都是一个Statement标签,显然下面有四组。
<!--增-->
<insert id="add" parameterType="com.test.entity.User">
insert into user(username,password,age) values
(#{username},#{password},#{age})
</insert>
<!--删-->
<delete id="delete" parameterType="java.lang.Integer">
delete from user where id=#{id}
</delete>
<!--改-->
<update id="update" parameterType="com.test.entity.User">
update user set username=#{username},password=#{password},age=#{age}
where id=#{id}
</update>
<!--查-->
<select id="getById" parameterType="java.lang.Integer"
resultType="com.test.entity.User">
<!--写SQL,id就是传进来的参数-->
select * from user where id = #{id}
</select>
规则如下:
- UserRepository.xml中namespace为接口的全类名
- UserRepository.xml中的Statement的id为接口中对应的方法名
- UserRepository.xml中的Statement的parameter和接口中对应方法的参数类型一致
- UserRepository.xml中的Statement的resultType和接口中对应方法的返回值类型一致
完整的UserRepository.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.test.repository.UserRepository">
<!--此处开始自定义SQL-->
<!--增-->
<insert id="add" parameterType="com.test.entity.User">
insert into user(username,password,age) values
(#{username},#{password},#{age})
</insert>
<!--删-->
<delete id="delete" parameterType="java.lang.Integer">
delete from user where id=#{id}
</delete>
<!--改-->
<update id="update" parameterType="com.test.entity.User">
update user set username=#{username},password=#{password},age=#{age}
where id=#{id}
</update>
<!--查-->
<select id="getById" parameterType="java.lang.Integer"
resultType="com.test.entity.User">
<!--写SQL,id就是传进来的参数-->
select * from user where id = #{id}
</select>
</mapper>
只有“查”select需要返回结果类型。
MyBatis 需要知道如何将 SQL 查询返回的数据库记录(ResultSet)转换成Java 对象。
所以resultType="com.test.entity.User"明确告知框架,将查询结果映射到com.test.entity.User类的实例。
3、在全局配置文件config.xml中注册UserRepository.xml
<configuration>
<!-- 注册xml文件-->
<mappers>
<!-- 注册UserMapper.xml -->
<mapper resource="com/test/mapper/UserMapper.xml"></mapper>
<!--注册UserRepository.xml-->
<mapper resource="com/test/repository/UserRepository.xml"></mapper>
</mappers>
</configuration>
完整的config.xml如下,分为两步:
- MyBaits运行环境配置
- 注册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>
<!--此处开始配置-->
<!--MyBaits运行环境配置-->
<environments default="development">
<environment id="development">
<!-- 配置JDBC事务管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置JDBC数据源连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/test11"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--配置结束-->
<!-- 注册xml文件-->
<mappers>
<!-- 注册UserMapper.xml -->
<mapper resource="com/test/mapper/UserMapper.xml"></mapper>
<!--注册UserRepository.xml-->
<mapper resource="com/test/repository/UserRepository.xml"></mapper>
</mappers>
</configuration>
4、在mapper包下创建测试类Tset,调用原生接口执行SQL语句获取结果
如果在原生接口已经创建过了,则无需再创建,直接改代码即可。
分为4步
- 加载MyBatis配置文件
- 获取SqlSession
- 获取实现接口的代理对象
- 调用自定义接口执行SQL
Test测试接口——增
package com.test.mapper;
import com.test.entity.User;
import com.test.repository.UserRepository;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
public class Test {
public static void main(String[] args) {
//加载MyBatis配置文件
InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
//获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取实现接口的代理对象
UserRepository userRepository = sqlSession.getMapper(UserRepository.class);
//新增用户
User user = new User();
user.setUsername("李四");
user.setPassword("qwerty");
user.setAge(18);
System.out.println(userRepository.add(user));
sqlSession.commit();
}
}
测试成功输出:1
数据库表User:
| id | username | password | age |
|---|---|---|---|
| 1 | 张三 | 123456 | 22 |
| 2 | 李四 | qwerty | 23 |
Test测试接口——删
代码直接从“第四步——调用自定义接口执行SQL”开始写,前三步都是一样的就不重复了
//删除用户
System.out.println(userRepository.delete(2));
sqlSession.commit();
测试成功输出:1
数据库表User:
| id | username | password | age |
|---|---|---|---|
| 1 | 张三 | 123456 | 22 |
Test测试接口——改
//修改用户
User user = userRepository.getById(1);
user.setUsername("王五");
user.setPassword("qwerty");
user.setAge(17);
System.out.println(userRepository.update(user));
sqlSession.commit();//除了查询都要提交
测试成功输出:1
数据库表User:
| id | username | password | age |
|---|---|---|---|
| 1 | 王五 | qwerty | 17 |
Test测试接口——查
//查询用户
System.out.println(userRepository.getById(1));
测试成功输出User{id=1, username='王五', password='qwerty', age=17}
5、增删改查代码对比
//新增用户
User user = new User();
user.setUsername("李四");
user.setPassword("qwerty");
user.setAge(18);
System.out.println(userRepository.add(user));
sqlSession.commit();
//删除用户
System.out.println(userRepository.delete(2));
sqlSession.commit();
//修改用户
User user = userRepository.getById(1);
user.setUsername("王五");
user.setPassword("qwerty");
user.setAge(17);
System.out.println(userRepository.update(user));
sqlSession.commit();//除了查询都要提交
//查询用户
System.out.println(userRepository.getById(1));
代码对比总结
-
很显然删除和查询是最简单的,直接调用定义的UserRepository接口定义好的方法即可。
-
只有查询不需要提交
sqlSession.commit(); -
添加和修改是类似的,就是第一步不同,添加需要new一个User,修改需要先确认id
原生接口 vs 自定义接口对比
| 特性 | 原生接口 | 自定义接口 |
|---|---|---|
| 实现方式 | 直接调用SqlSession的API | 接口定义+动态代理实现 |
| 代码耦合度 | 高(SQL ID硬编码在Java代码中) | 低(SQL与Java代码解耦) |
| 类型安全 | 弱(参数类型需手动匹配) | 强(编译时检查方法签名) |
| 维护性 | 修改SQL需查找字符串 | 修改XML即可,接口不变 |
| 开发效率 | 简单场景快速实现 | 需要定义接口但长期收益高 |
| 可读性 | 业务逻辑与SQL调用混杂 | 清晰的接口分层 |
| 错误检测 | 运行时发现SQL映射错误 | 编译时发现方法签名错误 |
| 推荐场景 | 快速原型验证/简单查询 | 生产环境/复杂业务系统 |
架构选择建议:
- 小型工具类项目:原生接口更快捷
- 企业级应用:必须使用自定义接口
- Spring Boot项目:结合
@MapperScan实现零配置
关键问题解析
1. XML路径为何用/而非.?
<mapper resource="com/test/mapper/UserMapper.xml"/>
- 路径分隔符:文件系统路径使用
/(Windows/Linux通用) - 避免歧义:
com.test.mapper中的.会被误认为文件名
2. 增删改为何需要commit?
session.commit(); // 非查询操作必须提交
- 事务控制:MyBatis默认关闭自动提交
- 确保操作:显式提交保证数据持久化
- 批量优化:多次操作后统一提交提升性能
3. 何时需要指定parameterType?
<select id="get" parameterType="Integer">...
- 简单类型:Java基本类型/包装类需声明
- 对象类型:可省略(MyBatis自动推断)
- 多参数场景:需使用
@Param注解
最佳实践总结
-
目录规范:
- 实体类:
com.xxx.entity - Mapper接口:
com.xxx.repository - XML映射:与接口同包同名(如
UserRepository.xml)
- 实体类:
-
事务控制:
try (SqlSession session = factory.openSession()) { // 业务操作 session.commit(); // 成功时提交 } catch (Exception e) { session.rollback(); // 异常回滚 } -
SQL优化:
<!-- 使用结果映射 --> <resultMap id="userMap" type="User"> <id property="id" column="id"/> <result property="username" column="name"/> <!-- 字段别名映射 --> </resultMap>
进阶提示:生产环境建议结合Spring管理SqlSession,使用声明式事务控制

被折叠的 条评论
为什么被折叠?



