MyBatis 基础配置与执行流程全解析(从入门到实践) MyBatis 作为 Java 生态中轻量级且灵活的持久层框架,其核心是通过配置文件解耦 SQL 与业务代码 ,同时简化 JDBC 冗余操作。配置细节优化、执行流程原理、工程化实践 及常见问题排查 ,帮助你彻底掌握 MyBatis 的基础使用与核心逻辑。
配置文件:从基础到优化 MyBatis 的配置体系分为「全局配置文件(mybatis-config.xml)」和「映射文件(XxxMapper.xml)」,两者分工明确 —— 全局配置负责框架级参数,映射文件负责业务 SQL 与实体映射。
全局配置文件(mybatis-config.xml)深度解读 (1)全局配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 <?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 > <properties resource ="db.properties" > <property name ="jdbc.username" value ="default_root" /> </properties > <settings > <setting name ="mapUnderscoreToCamelCase" value ="true" /> <setting name ="logImpl" value ="STDOUT_LOGGING" /> <setting name ="cacheEnabled" value ="true" /> <setting name ="aggressiveLazyLoading" value ="false" /> </settings > <typeAliases > <typeAlias type ="com.zhanghe.study.mybatis.model.User" alias ="User" /> <package name ="com.zhanghe.study.mybatis.model" /> </typeAliases > <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}" /> <property name ="poolMaximumActiveConnections" value ="20" /> <property name ="poolMaximumIdleConnections" value ="5" /> </dataSource > </environment > <environment id ="production" > <transactionManager type ="MANAGED" /> <dataSource type ="POOLED" > <property name ="driver" value ="${prod.jdbc.driver}" /> <property name ="url" value ="${prod.jdbc.url}" /> <property name ="username" value ="${prod.jdbc.username}" /> <property name ="password" value ="${prod.jdbc.password}" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="mapper/UserMapper.xml" /> </mappers > </configuration >
(2)外部属性文件(db.properties) 将数据库配置单独抽取到 src/main/resources/db.properties,便于维护和环境切换:
1 2 3 4 5 6 7 8 9 10 11 jdbc.driver =com.mysql.cj.jdbc.Driver # MySQL 8.0+需用cj驱动,5.x用com.mysql.jdbc.Driver jdbc.url =jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC&characterEncoding=utf8 jdbc.username =root jdbc.password =123456 prod.jdbc.driver =com.mysql.cj.jdbc.Driver prod.jdbc.url =jdbc:mysql://192.168.1.100:3306/prod_db?useSSL=true&serverTimezone=UTC prod.jdbc.username =prod_user prod.jdbc.password =prod_123456
映射文件(UserMapper.xml) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <?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.zhanghe.study.mybatis.mapper.UserMapper" > <cache eviction ="LRU" flushInterval ="60000" size ="1024" readOnly ="true" /> <resultMap id ="UserResultMap" type ="User" > <id column ="user_id" property ="userId" /> <result column ="user_name" property ="userName" /> <result column ="user_age" property ="userAge" /> <result column ="create_time" property ="createTime" jdbcType ="TIMESTAMP" /> </resultMap > <select id ="selectUser" parameterType ="Integer" resultMap ="UserResultMap" > SELECT user_id, user_name, user_age, create_time FROM users WHERE user_id = #{id} </select > <select id ="selectUserByNameAndAge" resultMap ="UserResultMap" > SELECT * FROM users WHERE user_name = #{name} AND user_age = #{age} </select > <insert id ="insertUser" parameterType ="User" useGeneratedKeys ="true" keyProperty ="userId" > INSERT INTO users (user_name, user_age, create_time) VALUES (#{userName}, #{userAge}, #{createTime}) </insert > </mapper >
对应的 Mapper 接口(UserMapper.java) 接口方法需与映射文件的 id、参数类型、返回值类型完全匹配 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.zhanghe.study.mybatis.mapper;import com.zhanghe.study.mybatis.model.User;import org.apache.ibatis.annotations.Param;public interface UserMapper { User selectUser (Integer userId) ; User selectUserByNameAndAge (@Param("name") String userName, @Param("age") Integer userAge) ; int insertUser (User user) ; }
执行流程:从配置加载到 SQL 执行 MyBatis 的执行流程可拆解为「配置加载→核心对象创建→SQL 执行→资源释放」四步,每一步都有明确的职责和生命周期管理要求。
核心流程拆解 (1)步骤 1:加载配置,创建 SqlSessionFactory SqlSessionFactory 是 MyBatis 的 “工厂”,负责创建 SqlSession,其生命周期是全局唯一 (应用启动时创建一次,避免重复创建导致连接泄漏)。
1 2 3 4 5 6 7 8 9 10 11 public static SqlSessionFactory createFactory () { try { InputStream is = Resources.getResourceAsStream("mybatis-config.xml" ); return new SqlSessionFactoryBuilder ().build(is); } catch (IOException e) { throw new RuntimeException ("MyBatis配置文件加载失败!" , e); } }
关键原理 :SqlSessionFactoryBuilder 会解析 mybatis-config.xml 和所有 Mapper.xml,将配置信息封装到 Configuration 对象中,最终基于 Configuration 创建 SqlSessionFactory(默认实现是 DefaultSqlSessionFactory)。
(2)步骤 2:创建 SqlSession SqlSession 相当于 JDBC 的 Connection,代表一次数据库会话,生命周期是单次业务请求 (线程不安全,需及时关闭)。
1 2 3 4 5 6 7 8 9 10 11 12 13 SqlSession session = sqlSessionFactory.openSession(true );SqlSession session = sqlSessionFactory.openSession();try { session.commit(); } catch (Exception e) { session.rollback(); } finally { session.close(); }
核心注意事项 :
SqlSession 线程不安全,不可跨线程共享;
必须在 finally 块中关闭 SqlSession,避免数据库连接泄漏;
手动提交模式下,未调用 commit() 会导致事务未提交,数据不生效。
(3)步骤 3:执行 SQL(新旧版本对比) MyBatis 提供两种执行 SQL 的方式,新版本的「Mapper 接口代理」是主流(类型安全、可读性强)。
执行方式
代码示例
优缺点对比
老版本(SqlSession 直接调用)
User user = session.selectOne("com.zhanghe.study.mybatis.mapper.UserMapper.selectUser", 2);
优点:无需定义接口; 缺点:字符串硬编码(易写错)、无类型校验、可读性差。
新版本(Mapper 接口代理)
UserMapper mapper = session.getMapper(UserMapper.class); User user = mapper.selectUser(2);
优点:类型安全(编译期校验)、代码简洁、可维护性强; 缺点:需定义接口。
原理补充 : MyBatis 会为 Mapper 接口动态生成代理对象(基于 JDK 动态代理),调用接口方法时,代理对象会解析 namespace + methodName 找到对应的 SQL,执行后返回结果。
(4)步骤 4:资源释放 无论 SQL 执行成功或失败,都需关闭 SqlSession,释放数据库连接(归还到连接池):
1 2 3 4 5 6 7 8 9 10 11 SqlSession session = null ;try { session = sqlSessionFactory.openSession(true ); UserMapper mapper = session.getMapper(UserMapper.class); User user = mapper.selectUser(2 ); System.out.println(user); } finally { if (session != null ) { session.close(); } }
工程化优化:工具类封装 为避免重复代码,推荐封装 MyBatisUtil 工具类,统一管理 SqlSessionFactory 和 SqlSession:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package com.zhanghe.study.mybatis.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;public class MyBatisUtil { private static SqlSessionFactory sqlSessionFactory; static { try { String resource = "mybatis-config.xml" ; InputStream is = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder ().build(is); } catch (IOException e) { throw new ExceptionInInitializerError ("MyBatis初始化失败!" , e); } } public static SqlSession getSqlSession () { return sqlSessionFactory.openSession(true ); } public static void closeSqlSession (SqlSession session) { if (session != null ) { session.close(); } } }
工具类使用示例 :
1 2 3 4 5 6 7 8 9 10 SqlSession session = null ;try { session = MyBatisUtil.getSqlSession(); UserMapper mapper = session.getMapper(UserMapper.class); User user = mapper.selectUser(2 ); System.out.println(user); } finally { MyBatisUtil.closeSqlSession(session); }
常见问题与解决方案 1. 映射文件找不到(Invalid bound statement (not found))
原因 1 :mybatis-config.xml 的 <mappers> 配置路径错误(如 resource 路径不是 classpath 下的路径);
原因 2 :Mapper 接口与映射文件不同包同名 (如接口在 com.mapper,映射文件需在 resources/com/mapper 下且名为 UserMapper.xml);
解决方案 :使用 <package name="com.zhanghe.study.mybatis.mapper"/> 批量扫描 Mapper 接口,确保接口与映射文件同包同名。
2. 驼峰命名不生效(数据库字段 user_name → 实体属性 userName 为 null)
3. SQL 注入风险(使用 ${} 占位符)
原因 :${} 是字符串直接拼接(如 ${id} → 替换为参数值,无预编译),#{} 是预编译占位符(推荐);
解决方案 :除动态表名 / 排序字段(如 ORDER BY ${field})外,全部使用 #{}。
4. SqlSession 未关闭导致连接泄漏
原因 :未在 finally 块中关闭 SqlSession,异常时资源未释放;
解决方案 :使用工具类的 closeSqlSession 方法,在 finally 中强制关闭。
总结 MyBatis 的基础使用核心是 “配置 + 接口 + 映射 ”:
配置文件 :全局配置管理数据库和框架参数,映射文件定义 SQL 和实体映射;
执行流程 :SqlSessionFactory(全局唯一)→ SqlSession(单次会话)→ Mapper 代理(执行 SQL);
最佳实践 :封装工具类管理核心对象、开启驼峰映射简化配置、使用接口代理避免硬编码