01-MyBatis核心详解

张开发
2026/4/11 20:49:46 15 分钟阅读

分享文章

01-MyBatis核心详解
MyBatis核心详解一、知识概述MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects)为数据库中的记录。本文将深入讲解 MyBatis 的核心原理,包括 SqlSession 的生命周期、Mapper 代理机制、缓存机制等,帮助你理解 MyBatis 的工作原理,更好地使用和优化 MyBatis。二、核心组件详解2.1 MyBatis 整体架构┌─────────────────────────────────────────────────────────────┐ │ 应用程序层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Mapper 接口 │ │ Service 层 │ │ Controller │ │ │ └──────┬──────┘ └──────┬──────┘ └─────────────┘ │ └─────────┼────────────────┼──────────────────────────────────┘ │ │ ┌─────────┼────────────────┼──────────────────────────────────┐ │ ▼ ▼ MyBatis 框架层 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ SqlSession │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ Configuration │ │ Executor │ │ │ │ │ └──────────────┘ └──────────────┘ │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ StatementHan │ │ ParameterHan │ │ │ │ │ │ dler │ │ dler │ │ │ │ │ └──────────────┘ └──────────────┘ │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ ResultSetHan │ │ TypeHandler │ │ │ │ │ │ dler │ │ │ │ │ │ │ └──────────────┘ └──────────────┘ │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 数据库层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ MySQL │ │ Oracle │ │ PostgreSQL │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────────┘2.2 核心组件介绍/** * MyBatis 核心组件层次结构 * * SqlSessionFactoryBuilder → SqlSessionFactory → SqlSession → Mapper * * 每个组件的职责: * 1. SqlSessionFactoryBuilder: 解析配置,构建 SqlSessionFactory * 2. SqlSessionFactory: 创建 SqlSession 的工厂(单例) * 3. SqlSession: 执行 SQL 的会话(非线程安全,每次请求创建) * 4. Mapper: 接口代理,执行具体 SQL */publicclassMyBatisCoreComponents{publicstaticvoidmain(String[]args){// 1. SqlSessionFactoryBuilder - 构建 SqlSessionFactory// 生命周期:方法局部,用完即弃SqlSessionFactoryBuilderbuilder=newSqlSessionFactoryBuilder();// 2. SqlSessionFactory - 工厂单例// 生命周期:应用级别,整个应用运行期间存在// 最佳实践:通过单例模式或 Spring 容器管理SqlSessionFactorysqlSessionFactory=builder.build(Resources.getResourceAsStream("mybatis-config.xml"));// 3. SqlSession - 数据库会话// 生命周期:请求/方法级别,非线程安全// 最佳实践:每次数据库操作创建,用完关闭try(SqlSessionsession=sqlSessionFactory.openSession()){// 4. Mapper 接口 - 执行 SQL// 生命周期:随 SqlSession,每次获取新实例UserMappermapper=session.getMapper(UserMapper.class);Useruser=mapper.selectById(1L);System.out.println(user);}}}2.3 配置详解!-- mybatis-config.xml - MyBatis 核心配置文件 --?xml version="1.0" encoding="UTF-8"?!DOCTYPEconfigurationPUBLIC"-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"configuration!-- 1. 属性配置 - 可从外部文件加载 --propertiesresource="db.properties"propertyname="username"value="root"/propertyname="password"value="123456"//properties!-- 2. 设置 - 全局配置参数 --settings!-- 开启驼峰命名自动映射 --settingname="mapUnderscoreToCamelCase"value="true"/!-- 开启二级缓存 --settingname="cacheEnabled"value="true"/!-- 延迟加载全局开关 --settingname="lazyLoadingEnabled"value="true"/!-- 设置超时时间 --settingname="defaultStatementTimeout"value="30"/!-- 日志实现 --settingname="logImpl"value="SLF4J"//settings!-- 3. 类型别名 - 为 Java 类型设置缩写 --typeAliases!-- 单个类别名 --typeAliastype="com.example.entity.User"alias="User"/!-- 包扫描别名(默认首字母小写) --packagename="com.example.entity"//typeAliases!-- 4. 类型处理器 - 自定义类型转换 --typeHandlerstypeHandlerjavaType="java.util.Date"handler="com.example.handler.DateTypeHandler"//typeHandlers!-- 5. 插件 - 拦截器 --pluginsplugininterceptor="com.example.plugin.MyPlugin"propertyname="someProperty"value="100"//plugin/plugins!-- 6. 环境配置 --environmentsdefault="development"environmentid="development"!-- 事务管理器 --transactionManagertype="JDBC"/!-- 数据源 --dataSourcetype="POOLED"propertyname="driver"value="${driver}"/propertyname="url"value="${url}"/propertyname="username"value="${username}"/propertyname="password"value="${password}"/!-- 连接池配置 --propertyname="poolMaximumActiveConnections"value="20"/propertyname="poolMaximumIdleConnections"value="10"/propertyname="poolMaximumCheckoutTime"value="20000"//dataSource/environment/environments!-- 7. 数据库厂商标识 --databaseIdProvidertype="DB_VENDOR"propertyname="MySQL"value="mysql"/propertyname="Oracle"value="oracle"//databaseIdProvider!-- 8. 映射器配置 --mappers!-- 使用 XML 配置 --mapperresource="mapper/UserMapper.xml"/!-- 使用接口配置 --mapperclass="com.example.mapper.UserMapper"/!-- 包扫描 --packagename="com.example.mapper"//mappers/configuration三、SqlSession 源码解析3.1 SqlSession 创建过程/** * SqlSession 创建流程源码分析 */publicclassSqlSessionCreationAnalysis{/** * SqlSessionFactory 接口定义 */publicinterfaceSqlSessionFactory{// 创建默认 SqlSession(非自动提交)SqlSessionopenSession();// 创建指定自动提交的 SqlSessionSqlSessionopenSession(booleanautoCommit);// 使用指定 Connection 创建 SqlSessionSqlSessionopenSession(Connectionconnection);// 指定事务隔离级别SqlSessionopenSession(TransactionIsolationLevellevel);// 指定执行器类型SqlSessionopenSession(ExecutorTypeexecType);}/** * DefaultSqlSessionFactory.openSession() 实现 */publicclassDefaultSqlSessionFactoryimplementsSqlSessionFactory{privatefinalConfigurationconfiguration;@OverridepublicSqlSessionopenSession(){returnopenSessionFromDataSource(configuration.getDefaultExecutorType(),// 执行器类型configuration.getDefaultTransactionIsolationLevel(),// 事务隔离级别false// 自动提交);}privateSqlSessionopenSessionFromDataSource(ExecutorTypeexecType,TransactionIsolationLevellevel,booleanautoCommit){Transactiontx=null;try{// 1. 从 Configuration 获取 Environment(包含数据源和事务配置)finalEnvironmentenvironment=configuration.getEnvironment();// 2. 创建事务TransactionFactorytransactionFactory=getTransactionFactoryFromEnvironment(environment);tx=transactionFactory.newTransaction(environment.getDataSource(),level,autoCommit);// 3. 创建执行器(关键!)Executorexecutor=configuration.newExecutor(tx,execType);// 4. 创建 DefaultSqlSessionreturnnewDefaultSqlSession(configuration,executor,autoCommit);}catch(Exceptione){closeTransaction(tx);throwExceptionFactory.wrapException("Error opening session. Cause: "+e,e);}}}}3.2 SqlSession 执行流程/** * SqlSession 执行 SQL 的完整流程 */publicclassSqlSessionExecutionFlow{publicstaticvoidmain(String[]args){SqlSessionFactoryfactory=SqlSessionFactoryBuilder.build(...);try(SqlSessionsession=factory.openSession()){// 查询操作Useruser=session.selectOne("com.example.mapper.UserMapper.selectById",1L);// 插入操作introws=session.insert("com.example.mapper.UserMapper.insert",user);// 更新操作introws=session.update("com.example.mapper.UserMapper.update",user);// 删除操作introws=session.delete("com.example.mapper.UserMapper.deleteById",1L);// 提交事务(如果非自动提交)session.commit();}}/** * DefaultSqlSession.selectOne 源码 */publicclassDefaultSqlSessionimplementsSqlSession{privatefinalConfigurationconfiguration;privatefinalExecutorexecutor;@OverridepublicTTselectOne(Stringstatement,Objectparameter){// 调用 selectList,取第一个结果ListTlist=this.TselectList(statement,parameter);if(list.size()==1){returnlist.get(0);}elseif(list.size()1){thrownewTooManyResultsException("Expected one result but found: "+list.size());}returnnull;}@OverridepublicEListEselectList(Stringstatement,Objectparameter){returnselectList(statement,parameter,RowBounds.DEFAULT);}@OverridepublicEListEselectList(Stringstatement,Objectparameter,RowBoundsrowBounds){try{// 1. 从 Configuration 获取 MappedStatementMappedStatementms=configuration.getMappedStatement(statement);// 2. 委托给 Executor 执行returnexecutor.query(ms,wrapCollection(parameter),rowBounds,Executor.NO_RESULT_HANDLER);}catch(Exceptione){throwExceptionFactory.wrapException("Error querying database. Cause: "+e,e);}}}}四、Mapper 代理机制4.1 Mapper 接口绑定/** * Mapper 接口代理机制详解 * * MyBatis 通过 JDK 动态代理为 Mapper 接口创建代理对象 * 代理对象拦截方法调用,将其转换为 SQL 执行 */publicclassMapperProxyMechanism{/** * Mapper 接口定义 */publicinterfaceUserMapper{UserselectById(Longid);ListUserselectAll();intinsert(Useruser);intupdate(Useruser);intdeleteById(Longid);}/** * 对应的 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.example.mapper.UserMapper" select resultType="User" SELECT * FROM user WHERE id = #{id} /select select resultType="User" SELECT * FROM user /select insert parameterType="User" INSERT INTO user(name, email, age) VALUES(#{name}, #{email}, #{age}) /insert update parameterType="User" UPDATE user SET name=#{name}, email=#{email}, age=#{age} WHERE id=#{id} /update delete DELETE FROM user WHERE id = #{id} /delete /mapper *//** * MapperProxy 核心源码分析 */publicclassMapperProxyTimplementsInvocationHandler,Serializable{privatestaticfinallongserialVersionUID=-6424540398559729838L;privatefinalSqlSessionsqlSession;privatefinalClassTmapperInterface;privatefinalMapMethod,MapperMethodmethodCache;publicMapperProxy(SqlSessionsqlSession,ClassTmapperInterface,MapMethod,MapperMethodmethodCache){this.sqlSession=sqlSession;this.mapperInterface=mapperInterface

更多文章