当前位置: 首页 > news >正文

Mybatis总结

Mybatis 是Java生态中主流的ORM框架。

基础概念

1、Mybatis、和Jdbc、Hibernate的区别:
定义:Mybatis是一款半自动化的ORM框架,基于XML文件或注解配置SQL语句,将Java对象与数据库表进行映射,简化JDBC代码编写(不需要手动处理connention、ResultSet等),同时保留SQL的灵活性。

对比JDBC和HIbernate:

维度JDBCMyBatisHibernate
ORM 类型无(手动映射)半自动(需手动写 SQL)全自动(无需手动写 SQL)
SQL 控制度完全手动编写,灵活但冗余手动编写 SQL,灵活且简化代码自动生成 SQL,灵活性低
学习成本低(原生 API)中(需理解配置与映射规则)高(需掌握 HQL、缓存、级联等)
适用场景简单项目、需极致控制 SQL中小型项目、需灵活调优 SQL大型项目、SQL 无需频繁调整
代码冗余度高(重复处理连接、结果集)低(框架封装通用操作)极低(几乎无 SQL 代码)

2、Mybatis的主要组成,各自功能
Mybatis各个组件主要围绕:SQL执行流程开展。主要有:

  • SqlSessionFactoryBuilder:构建器,基于XML或Java配置创建SqlSessionFactory。创建后即可销毁(生命周期最短)。
  • SqlSessionFactory:工厂,创建SqlSession的单例对象(整个应用生命周期内唯一),负责初始化Mybatis核心配置(如数据源。映射文件)。
  • SqlSession:会话,代表与数据库的一次交互(生命周期为一次请求/事务),提供增删改查的API(如:selectOne()、insert()),可直接执行SQL或调用Mapper接口。
  • Mapper接口:映射器,无实现类的接口,Mybatis通过动态代理生成 其实现类。将接口方法与XML/注解中的SQL语句绑定(原理:接口+SQL映射)。
  • Excutor:执行器,Mybatis核心执行组件(由SqlSession内部调用),负责解析SQL,管理缓存,执行JDBC操作。分为3类型:
    • SimpleExecutor:默认,每次执行SQL都创建一个新的Statement;
    • ReuseExcutor:复用Statement(根据SQL语句缓存);
    • BatchExecutor:批量执行SQL(使用批量插入/更新);
  • MapperStatement:映射语句,封装XML/注解中的SQL配置(如SQL语句、参数类型、结果类型),是Mybatis解析SQL的核心载体。

配置与映射规则

1、Mybatis的核心配置文件(mybatis-config.xml)包含的关键节点。
核心配置文件定义 MyBatis 全局参数,节点需按固定顺序排列(否则报错),关键节点及作用:

  • properties:引入外部属性文件(如 db.properties),避免硬编码数据库连接信息;
  • settings:配置 MyBatis 全局开关(如缓存开启、驼峰命名映射、日志实现);
  • typeAliases:为 Java 类型定义别名(如 com.example.User 别名 User),简化映射文件中的类型配置;
  • typeHandlers:自定义类型处理器(如将 Java 枚举与数据库 VARCHAR 类型映射);
  • objectFactory:自定义对象工厂(默认使用 DefaultObjectFactory,用于创建结果集映射的 Java 对象);
  • plugins:配置插件(如分页插件 PageHelper、逻辑删除插件),通过拦截器增强 MyBatis 功能;
  • environments:配置数据库环境(支持多环境,如开发、测试、生产),包含transactionManager(事务管理器)和 dataSource(数据源);
  • mappers:注册 SQL 映射文件或 Mapper 接口(核心,告诉 MyBatis 去哪里找 SQL)。

2、Mybati中如何实现【表字段名与Java对象属性名不一致问题】的映射。
解决方式:

  • SQL别名(简单直接):在SQL中给字段起别名,与Java属性对应。
  • resultMap映射(推荐,可复用):在映射文件中定义resultMap,指定子u但与属性映射关系
  • 开启驼峰命名自动映射(全局配置)。
  • 自定义TypeHandler(特殊场景):针对复杂场景(如JSON字段与Java对象,自定义Type Handler处理映射逻辑)。

3、Mybatis中#{}和${}区别,推荐使用#{}
两者都是 用于向SQL中注入参数的,但是底层实现和安全性不同

维度#{}${}
实现原理预编译SQL(使用?占位符),参数通过PreparedStatement注入字符串拼接(直接将参数替换到SQL中
安全性防止SQL注入风险(参数当作值,不解析SQL语法)存在SQL注入风险(参数可能拼接为SQL关键字)
适用场景普通参数注入(条件查询、新增数据的字段值)动态SQL片段(如表名、排序字段,需保证参数安全)

:除非需要动态拼接 表名/字段名(且参数需要严格验证),否则优先使用#{}避免SQL注入。

动态SQL和关联查询

1、Mybatis 提供的动态SQL标签:

  • if 条件判断,满足条件则拼接
  • where:自动处理条件中的AND/OR(若条件都不满足则不拼接where,若第一个条件带AND则自动删除)
  • choose when otherwise:类似于if else if-else,只执行第一个满足条件的where,否则执行otherwise
  • foreach:遍历集合(List、Array),常用于In条件或批量插入;
  • set:用于更新语句。
  • trim:自定义 拼接规则,可替代where和if
  • sql和include:抽取重复SQL片段,通过include复用,减少冗余。

2、Mybatis 处理一对一和 一对多问题。
关联查询的核心:通过ResultMap中的 <association/ >(一对一)和<collection/ >(一对多)标签映射关系。
1)一对一映射:
核心标签:<association/ > ,映射「单个关联对象」,属性如下:

  • property:Java 对象中关联属性名(如 userCard);
  • javaType:关联属性的类型(如 com.example.UserCard);
  • column:关联查询的外键字段(如 user_id,用于子查询);
  • select:子查询的 ID(用于「分步查询」),或直接在 resultMap 中配置字段映射(用于「关联查询」)。
<resultMap id="UserWithCardMap" type="User"><id column="user_id" property="userId"/><result column="user_name" property="userName"/><!-- 一对一关联 UserCard --><association property="userCard" javaType="UserCard"><id column="card_id" property="cardId"/><result column="card_no" property="cardNo"/></association>
</resultMap><select id="getUserWithCard" resultMap="UserWithCardMap">SELECT u.user_id, u.user_name, c.card_id, c.card_noFROM user uLEFT JOIN user_card c ON u.user_id = c.user_idWHERE u.user_id = #{userId}
</select>

2)一对多
核心标签:,映射「关联对象集合」,属性如下:

  • property:Java 对象中集合属性名(如 orders);
  • ofType:集合中元素的类型(如 com.example.Order,注意区别于 javaType);
  • column:外键字段,其他属性与 类似。
<resultMap id="UserWithOrdersMap" type="User"><id column="user_id" property="userId"/><result column="user_name" property="userName"/><!-- 一对多关联 Order 集合 --><collection property="orders" ofType="Order"><id column="order_id" property="orderId"/><result column="order_no" property="orderNo"/><result column="create_time" property="createTime"/></collection>
</resultMap><select id="getUserWithOrders" resultMap="UserWithOrdersMap">SELECT u.user_id, u.user_name, o.order_id, o.order_no, o.create_timeFROM user uLEFT JOIN `order` o ON u.user_id = o.user_idWHERE u.user_id = #{userId}
</select>

缓存机制

Mybatis提供两级缓存

1、Mybatis提供两级缓存,各自的特点:
一级缓存(本地缓存)、二级缓存(全局缓存)。核心是减少数据库查询次数。

缓存级别作用范围生命周期开启方式核心特点
一级缓存SqlSession内部(会话级)随着SQLSession关闭而销毁默认开启,无需配置基于Hash Map实现,同一SqlSession内重复查询同一SQL会命中缓存
二级缓存SqlSessionFactory全局(应用级)随着应用关闭而销毁需要手动开启(映射文件附加<cache/ >)基于HashMap或三方缓存(Redis)实现, 不同SQL session可共享缓存

2、一级缓存失效场景:(一级默认开启,但可能失效)

  • 同一Sqlsession中执行更新操作(insert/update/delete),Mybatis会清空当前sqlsession的一级缓存(避免缓存与数据库数据不一致);
  • 手动调用SqlSession.clearCache()方法;主动清理缓存;
  • 同一sqlsession中查询不同的SQL或参数;缓存的可以组成:SQL语句+参数+环境+映射ID。不同key导致未命中。
  • SqlSession关闭或提交,SQLSession生命周期结束,缓存随即销毁、

3、开启二级缓存,以及二级缓存的注意事项
开启步骤:
1. 全局配置开启二级缓存(默认已开启,可省略)
在mybatis.xml文件中配置

<settings><setting name="cacheEnabled" value="true"/>
</settings>
  1. 在映射文件中声明二级缓存
    在需要开启二级缓存的Mapper.xml文件中添加<cache/ >标签;
<!-- UserMapper.xml -->
<cache eviction="LRU"        <!-- 缓存淘汰策略:LRU(最近最少使用)、FIFO  -->flushInterval="60000" <!-- 缓存自动刷新时间(毫秒) -->size="1024"           <!-- 缓存最大条目数 -->readOnly="true"/>     <!-- 是否只读(true:返回缓存对象的引用,性能高;false:返回拷贝,安全) -->
  1. 实体类实现序列化接口
    二级缓存可能需要将对象写入磁盘(如使用Ehcache时),需保证实体类implement Serializable。

注意事项

  • 二级缓存按Mapper划分:不同Mapper的缓存应相互独立,若需要跨Mapper共享缓存,需要配置cache-ref(引用其他Mapper的缓存);
  • 避免缓存频繁更新的数据
  • 复杂关联查询(如一对多),需要考虑是否缓存。优先使用一级缓存或使用三方缓存

性能优化

1、Mybatis常见的性能优化

  • SQL优化
    • 避免Select *,只查询需要的字段
    • 合理利用索引
    • 减少关联查询
  • 缓存优化
    • 开启二级缓存(针对高频,低频更新的数据)
    • 集成三方缓存,替代默认缓存。
  • 执行器优化:
    • 批量操作时,使用BatchExecutor,需要手动设置SqlSessiond 执行器类型
  • 分页优化:
    • 使用分页插件(如Page Helper),避免手动在这里插入代码片拼接limit语句。
    • 避免全表查询后分页。会导致内存溢出
  • 参数优化
    • 避免大字段查询
  • 延迟加载(懒加载)
    • 开启全局懒加载,避免关联查询一次性查出所有数据(按需加载)。
<settings><setting name="lazyLoadingEnabled" value="true"/> <!-- 开启懒加载 --><setting name="aggressiveLazyLoading" value="false"/> <!-- 关闭积极加载(按需加载单个属性) -->
</settings>

2、Mybatis的延时加载,
定义:延迟加载(懒加载)是指 **关联对象在需要时才会加载,**而不是在主对象加载时,一次性加载。如:加载用户订单时,先加载用户信息,只有调用user.getOrder()时,才查询订单数据。
原理通过动态代理实现延迟加载.

  1. 开启懒加载,Mybatis会为实体类(如:User)生成动态代理对象;
  2. 初始查询只加载主对象User的基本属性,关联属性如order会被设置为【代理对象]
  3. 当调用关联查询属性的getter方法时,代理对象会触发Mybatis的懒加载机制逻辑。执行关联SQL并填充数据。
  4. 若未调用关联属性,则不会执行关联查询,减少数据库压力。

MyBatis的事务:Mybatis本身不提供事务管理,而是依赖底层数据源和Spring管理。

  • 原生Mybatis事务管理:通过SqlSession控制事务,默认关闭自动提交,需要手动commit()或rollback();
SqlSession sqlSession = sqlSessionFactory.openSession(false); // false:关闭自动提交
try {UserMapper mapper = sqlSession.getMapper(UserMapper.class);mapper.insertUser(user1);mapper.insertUser(user2);sqlSession.commit(); // 手动提交
} catch (Exception e) {sqlSession.rollback(); // 异常回滚
} finally {sqlSession.close();
}
  • Spring整合Mybatis事务管理
    通过Spring的@Transactional注解或者xml配置文件声明事务,无需手动控制SqlSession ;
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;@Transactional(rollbackFor = Exception.class) // 声明事务,异常回滚public void batchInsert(List<User> userList) {for (User user : userList) {userMapper.insertUser(user);}}
}
http://www.xdnf.cn/news/1374607.html

相关文章:

  • 【如何解决Java中的ClassCastException类转换异常问题】
  • 基于Matlab结合肤色检测与卷积神经网络的人脸识别方法研究
  • 基于MATLAB/Simulink的单机带负荷仿真系统搭建
  • 分布式2PC理论
  • 使用 html2canvas + jspdf 实现页面元素下载为pdf文件
  • UE5 查找组件
  • 云原生安全架构设计与零信任实践
  • 预测模型及超参数:1.传统机器学习:SVR与KNN
  • 工业网络安全:保护制造系统和数据
  • HIVE的Window functions窗口函数【二】
  • 【Hadoop】Zookeeper、HBase、Sqoop
  • 全球位置智能软件CR10为73%,市场集中度高
  • Java中高效获取IP地域信息方案全解析:从入门到生产实践
  • jQuery版EasyUI的ComboBox(下拉列表框)问题
  • JS(面试)
  • Proxmox VE 中启用 CentOS 虚拟机的串口终端(xterm.js 控制台)
  • 深度剖析HTTP和HTTPS
  • .NetCore 接入 Nacos,实现配置中心和服务注册
  • 本地windows电脑部署html网页到互联网:html+node.js+ngrok/natapp
  • oracle 表空间扩容(增加新的数据文件)
  • 使用appium对安卓(使用夜神模拟器)运行自动化测试
  • STM32八大模式
  • 基于单片机空调温度控制测温ds18b20系统Proteus仿真(含全部资料)
  • 人机交互如何变革科普展示?哪些技术正成吸睛焦点?
  • 初春养生指南模板页
  • Rust 登堂 之 迭代器Iterator(三)
  • el-carousel在新增或者删除el-carousel-item时默认跳到第一页的原因和解决
  • betaflight configurator 如何正确烧写飞控
  • 基于muduo库的图床云共享存储项目(二)
  • Linux 云服务器内存不足如何优化