mybatis的SqlSession

 先来看一下sqlsession接口,发现它为我们定义了很多对数据库数据操作的相关方法。

public interface SqlSession extends Closeable {<T> T selectOne(String var1);<T> T selectOne(String var1, Object var2);<E> List<E> selectList(String var1);<E> List<E> selectList(String var1, Object var2);<E> List<E> selectList(String var1, Object var2, RowBounds var3);<K, V> Map<K, V> selectMap(String var1, String var2);<K, V> Map<K, V> selectMap(String var1, Object var2, String var3);<K, V> Map<K, V> selectMap(String var1, Object var2, String var3, RowBounds var4);<T> Cursor<T> selectCursor(String var1);<T> Cursor<T> selectCursor(String var1, Object var2);<T> Cursor<T> selectCursor(String var1, Object var2, RowBounds var3);void select(String var1, Object var2, ResultHandler var3);void select(String var1, ResultHandler var2);void select(String var1, Object var2, RowBounds var3, ResultHandler var4);int insert(String var1);int insert(String var1, Object var2);int update(String var1);int update(String var1, Object var2);int delete(String var1);int delete(String var1, Object var2);void commit();void commit(boolean var1);void rollback();void rollback(boolean var1);List<BatchResult> flushStatements();void close();void clearCache();Configuration getConfiguration();<T> T getMapper(Class<T> var1);Connection getConnection();
}

主要功能:

  1. 创建SqlSession实例:

    1. 当需要与数据库进行交互时,首先从SqlSessionFactory(通过SqlSessionFactoryBuilder创建)获得一个SqlSession实例。每个SqlSession对象代表一个数据库会话,它不是线程安全的,因此每个线程都应该拥有自己的SqlSession。

  2. 内部结构与关键对象:

    1. SqlSession内部主要依靠Executor(执行器)来执行SQL语句。Executor根据配置的不同,可以有不同的行为模式,如简单执行器、重用执行器和批量执行器等。

    2. Executor在执行过程中会利用StatementHandler来处理具体的SQL语句(包括预编译SQL、设置参数等),并通过ParameterHandler处理SQL参数。
    3. 当执行查询操作时,ResultHandler会处理结果集,将数据库返回的结果转换为Java对象。
  3. 执行 CRUD 操作

    • insert(): 执行插入操作,用于保存新的数据。
    • update(): 执行更新操作,用于更新数据库中的现有数据。
    • delete(): 执行删除操作,用于从数据库中删除数据。
    • selectOne()selectList()selectMap()selectCursor()selectBatchResult(): 执行查询操作,用于从数据库中检索数据。
  4. 事务管理

    SqlSession 支持开启、提交和回滚事务。在开启 SqlSession 后,所有的数据库操作都在同一事务中进行,直到调用 commit() 或 rollback() 结束事务。
  5. 一级缓存与二级缓存:

    • SqlSession内部的一级缓存是指在一个SqlSession生命周期内,对同一个SQL查询结果的缓存。一旦SqlSession关闭,一级缓存也就失效。

    • 二级缓存是在多个SqlSession之间共享查询结果的一种机制,需要在全局配置和Mapper配置中明确启用,并且适用于读多写少的场景。当在不同SqlSession中执行相同的查询时,如果开启了二级缓存,MyBatis会在一级缓存未命中时尝试从二级缓存中获取数据。
  6. 获取 Mapper

    通过 SqlSession 可以获取到 Mapper 接口的代理对象,从而执行 Mapper 中定义的 SQL 映射方法。
  7. 关闭

    在完成一系列数据库操作后,应调用 SqlSession 的 close() 方法将其关闭,以释放资源并确保事务得到正确的提交或回滚。

 SqlSession和Executor怎样结合的?

SqlSession是MyBatis对外提供的主要API,它扮演着一个数据库会话的角色,提供了诸如增删改查等数据库操作的方法。而Executor(执行器)则是SqlSession背后真正执行这些操作的核心组件。

具体来说:

  1. 创建SqlSession时生成Executor

    • 当通过SqlSessionFactory打开一个新的SqlSession时,工厂会根据配置信息创建一个合适的Executor实例。比如,如果配置了批量操作,可能会创建BatchExecutor;如果没有特殊配置,会选择默认的Executor实现。
  2. Executor处理SQL请求

    • 当调用SqlSession的方法(如selectOne()insert()update()delete())时,SqlSession实际上委托给内部持有的Executor来执行相应的任务。
  3. 执行过程

    • Executor负责处理SQL语句的实际执行流程,包括但不限于:
      • 根据Mapper接口方法及XML映射文件生成MappedStatement对象。
      • 通过StatementHandler处理SQL语法和预编译。
      • 利用ParameterHandler设置SQL参数。
      • 执行SQL并获取结果,通过ResultHandler处理结果集,转化为Java对象。
      • 如果配置了缓存,Executor还会参与到一级缓存(本地缓存,存在于SqlSession层面)的管理中,以及在合适的情况下与二级缓存进行交互。
  4. 事务管理

    • Executor同样参与事务管理,根据SqlSession的事务属性来协调数据库的事务边界。

其实就是SqlSession作为一个门面模式的实现,提供了简洁的API供用户调用,而Executor作为它的内部协作组件,承担起实际的SQL执行和事务处理职责。

那我们工作中平时自定义的mapper接口是怎样和sqlsession搭上关系的呢?比如:

@Mapper
public interface OrderMapper extends BaseMapper<Order> {@Select({"SELECT o.order_no, SUM(i.price * i.count) AS amount","FROM t_order o JOIN t_order_item i ON o.order_no = i.order_no","GROUP BY o.order_no"})List<OrderVo> getOrderAmount();
}

我们继承了BaseMapper,而 BaseMapper又继承了Mapper接口给我们定义了一堆抽象方法。

public interface BaseMapper<T> extends Mapper<T> {int insert(T entity);int deleteById(Serializable id);int deleteByMap(@Param("cm") Map<String, Object> columnMap);int delete(@Param("ew") Wrapper<T> wrapper);int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);int updateById(@Param("et") T entity);int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);T selectById(Serializable id);List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);T selectOne(@Param("ew") Wrapper<T> queryWrapper);Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}

在Spring与MyBatis Plus 或者MyBatis集成的环境中,一般不会直接使用原始的SqlSession,而是使用SqlSessionTemplate,因为它更好地支持Spring的事务管理和线程安全。Spring会通过SqlSessionTemplateMapperFactoryBean等组件来代理和注入Mapper接口的实例。

当Spring容器初始化时,对于每一个Mapper接口,MyBatis会通过动态代理(如JDK动态代理或CGLIB代理)技术生成一个代理对象,如MapperProxy或MybatisMapperProxy。这个代理对象在其invoke方法中,当调用Mapper接口的方法时,会利用内部持有的SqlSession来执行相应的SQL语句,即通过SqlSession的API来完成数据库操作。

BaseMapper接口中定义了一系列方法,如插入、更新、删除和查询等CRUD操作,这些方法并不包含实际执行SQL的逻辑。对于BaseMapper或其子接口中的每个方法,通常会在对应的XML映射文件中定义SQL语句和结果映射(ResultMap)。例如,对于selectById方法,会在对应的UserMapper.xml中写好一个select标签,定义查找用户信息的SQL查询语句,并指定它与方法的映射关系。

当调用BaseMapper的某个方法时,实际上是调用代理对象的方法,代理对象内部通过SqlSession找到对应的MappedStatement(已解析好的SQL语句和参数映射信息),然后调用Executor执行SQL,最后将数据库结果转换为Java对象并返回。

那么mybatis是怎样解析xml这种mapper文件的呢?

MyBatis解析mapper文件的过程主要包括以下几个步骤,主要构建为MappedStatement:

  1. 资源加载

    • 当SqlSessionFactory构建时,或者在运行时动态添加新的mapper资源时,MyBatis会加载mapper XML文件作为资源。
  2. XML解析器初始化

    • MyBatis使用内置的XML解析器读取mapper文件内容,通常基于DOM或SAX解析器来解析XML文档结构。
  3. 解析主元素

    • 解析过程从根元素<mapper>开始,通过调用XMLMapperBuilder#parse()方法来处理整个mapper文件的内容。
    • 首先检查资源是否已经被加载过,避免重复解析。
  4. 解析内部元素

    • 对mapper文件内的各个SQL映射元素(如<select><insert><update><delete>等)进行遍历和解析。
    • 每个元素的属性和嵌套元素(如parameterType、resultType或resultMap等)都会被提取出来,并根据它们的定义构建相应的MappedStatement对象。
  5. 构建MappedStatement

    • MappedStatement是MyBatis中最关键的数据结构之一,它包含了SQL语句、参数类型、结果类型以及可能的结果映射等信息。
    • 解析器会对SQL语句中的动态元素(如${}#{}表达式)进行初步识别,但实际的动态解析将在执行阶段由ParameterHandler和BoundSql完成。
  6. 注册Mapper

    • 解析完成后,MappedStatement会被注册到MyBatis的Configuration对象中,这样在执行SQL时,就可以通过Mapper接口方法名找到对应的MappedStatement来执行。
  7. 延迟解析与处理

    • 在解析过程中,有些依赖的ResultMap或其他元素可能还未完全加载,因此在解析完mapper文件后,还需要调用parsePendingResultMaps()parsePendingCacheRefs()parsePendingStatements()等方法,以确保所有的依赖项都被正确解析和注册。

那比如上面的注解呢?如何转为MappedStatement的呢?

在MyBatis中,使用注解的方式来定义SQL语句时,例如@Select注解,MyBatis框架会在启动或刷新配置的过程中自动扫描和解析带有注解的Mapper接口和方法。

以下是注解如何被解析为MappedStatement的大致步骤:

  1. Mapper接口扫描

    • MyBatis会按照配置扫描指定包下的Mapper接口,或者是通过@Mapper注解标记的接口。
  2. 方法解析

    • 对于Mapper接口中的每个方法,MyBatis会检查是否存在诸如@Select@Insert@Update@Delete等SQL注解。
    • 当发现这些注解时,会读取注解上的SQL字符串值。
  3. 构建MappedStatement

    • 根据注解信息和方法签名,MyBatis会创建一个MappedStatement对象。
    • MappedStatement会记录下注解中SQL语句、方法的全限定名(即接口名+方法名)、方法参数类型(作为参数映射的基础)、结果类型(可能是实体类或基本类型数组等)以及其它相关的配置信息。
  4. 注册MappedStatement

    • 创建好的MappedStatement会被注册到MyBatis的Configuration对象中,这样在后续执行SQL时,可以根据方法名快速定位到对应的MappedStatement来执行。
  5. 动态SQL处理

    • 即使使用注解,MyBatis仍然支持动态SQL的部分特性,例如在@Select注解中可以使用${}表达式等。
    • 虽然注解中的SQL是静态文本,但在实际执行前,MyBatis会利用org.apache.ibatis.builder.annotation.ProviderContext上下文信息,配合@SelectProvider注解引入的SQL提供类来动态生成SQL语句,如果有的话。

总结来说,BaseMapper中的方法与SqlSession的方法关联的整个过程是这样的:

  • 开发者定义了一个继承自BaseMapper的接口,并在XML映射文件中映射SQL语句。
  • MyBatis通过动态代理技术创建一个代理对象,该对象在接收到方法调用时,会借助SqlSession找到并执行相应的SQL。
  • SqlSession内部维护了方法与SQL语句之间的映射关系,负责真正执行数据库操作,并确保结果能够正确映射到Java对象上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/1912.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PLC无线通讯技术在汽车喷涂车间机械手臂上的应用

一、项目背景 在汽车生产装配工艺中&#xff0c;机械臂目前已经广泛地应用于装配、搬运等工业生产中&#xff0c;在机械臂系列产品中&#xff0c;汽车喷漆自动控制喷涂机械装置以其独特的优势&#xff0c;能够根据油漆喷涂量的大小&#xff0c;严格控制喷嘴与喷漆面之间距离等…

flink Unsupported operand types: IF(boolean, NULL, String)

问题&#xff1a;业务方存储了NULL 字符串&#xff0c;需要处理为 null select if(anull&#xff0c;null&#xff0c;a); 结果遇到了 Unsupported operand types: IF(boolean, NULL, String)&#xff0c;根据报错反馈&#xff0c;很明显应该是没有对 null 自动转换&#xff…

vue里面事件修饰符.stop使用案例

Vue.js 事件修饰符 .stop 用于阻止事件继续传播&#xff0c;即阻止事件冒泡。这在处理父子组件之间的事件通信时特别有用&#xff0c;可以防止事件从子组件冒泡到父组件&#xff0c;或者在一个元素上绑定多个事件处理函数时&#xff0c;阻止后续事件处理函数的执行。 下面是一个…

直播预告:拥抱AI-探索AI大模型在邮件反钓鱼检测的应用

随着ChatGPT的问世&#xff0c;生成式AI技术迅速渗透到我们生活的各个角落&#xff0c;以ChatGPT为代表的生成式AI技术&#xff0c;依托其强大的AI模型和海量数据&#xff0c;赢得了广泛的欢迎。 然而&#xff0c;生成式AI的不断演进也带来了新的挑战。大型语言模型&#xff08…

前端常用的数据加密方式

前端开发中&#xff0c;数据安全是至关重要的一个方面。数据加密是保护用户隐私和信息安全的关键方法之一。 前端常用的数据加密方式涵盖了对传输数据的加密、存储数据的加密以及客户端与服务器端之间通信的加密。 1. 对称加密算法 对称加密算法使用相同的密钥进行加密和解密…

IUG-CF论文精读

Neural collaborative filtering with ideal user group labels &#xff08;具有理想用户组标签的神经协同过滤&#xff09; 论文地址&#xff1a;https://www.sciencedirect.com/science/article/pii/S0957417423023898 摘要&#xff1a; 人口统计信息是推荐系统(RSs)的关键…

社交媒体数据恢复:钉钉

在数字化办公日益普及的今天&#xff0c;钉钉作为一款综合性的企业级通讯工具&#xff0c;已经深入到众多企业和个人的工作与生活中。然而&#xff0c;在日常使用过程中&#xff0c;我们难免会遇到一些意外情况导致数据丢失的问题。本文将针对钉钉数据恢复这一主题&#xff0c;…

达梦数据库的DMRMAN工具-管理备份(备份集删除)

达梦数据库的DMRMAN工具-管理备份&#xff08;备份集删除&#xff09; 基础信息 OS版本&#xff1a; Red Hat Enterprise Linux Server release 7.9 (Maipo) DB版本&#xff1a; DM Database Server 64 V8 DB Version: 0x7000c 03134284132-20240115-215128-200811 概述 DMRM…

色彩空间转换在AI去衣技术中的应用与探索

在人工智能&#xff08;AI&#xff09;的广阔领域中&#xff0c;图像处理和计算机视觉技术一直占据着举足轻重的地位。其中&#xff0c;AI去衣技术作为一种新兴的图像处理技术&#xff0c;近年来受到了广泛关注。在AI去衣的实现过程中&#xff0c;色彩空间转换技术发挥着至关重…

文心一言 VS 讯飞星火 VS chatgpt (242)-- 算法导论17.4 1题

一、假定我们希望实现一个动态的开地址散列表。为什么我们需要当装载因子达到一个严格小于 1 的值 a 时就认为表满&#xff1f;简要描述如何为动态开地址散列表设计一个插入算法&#xff0c;使得每个插入操作的摊还代价的期望值为 O(1) 。为什么每个插入操作的实际代价的期望值…

文旅IP孵化打造抖音宣传推广运营策划方案

【干货资料持续更新&#xff0c;以防走丢】 文旅IP孵化打造抖音宣传推广运营策划方案 部分资料预览 资料部分是网络整理&#xff0c;仅供学习参考。 PPT可编辑&#xff08;完整资料包含以下内容&#xff09; 目录 文旅IP抖音运营方案 1. 项目背景与目标 - 背景&#xff1a…

【无监督+自然语言】GPT,GPT-2,GPT-3 方法概述 (Generative Pre-Traning)

主要参考 【GPT&#xff0c;GPT-2&#xff0c;GPT-3 论文精读【李沐论文精读】-2022.03.04】 https://www.bilibili.com/video/BV1AF411b7xQ/ 大语言模型综述&#xff1a; http://t.csdnimg.cn/4obR4 发展节点 2017.06 Transformer: 所有大语言模型LLMs的基础结构 , Attent…

【六十二】【算法分析与设计】买苹果_牛客题霸_牛客网,牛牛爱博弈,829. 连续整数求和,对数器找规律法,博弈论2^k移动对3取余规律,取余的性质整除性

买苹果_牛客题霸_牛客网 描述 小易去附近的商店买苹果&#xff0c;奸诈的商贩使用了捆绑交易&#xff0c;只提供6个每袋和8个每袋的包装(包装不可拆分)。 可是小易现在只想购买恰好n个苹果&#xff0c;小易想购买尽量少的袋数方便携带。如果不能购买恰好n个苹果&#xff0c;小易…

2元4mm2高精度温度湿度传感器GXHTC3

温湿度传感器芯片GXHTC3 前言&#xff1a; 该温湿度传感器为国产&#xff0c;批量价格约2元&#xff0c;精度较高&#xff0c;DHT11该被淘汰了&#xff0c;这个才是传感器。 特点 超低功耗 宽工作电压范围(1.62 – 5.5 V) 小型 DFN 封装: 2 2 0.75 mm3 典型精度: 湿度 2 %R…

创新与乐趣的融合 —— 探索我们独家录音变音芯片在学舌玩具领域的应用

一&#xff1a;概述 学舌玩具&#xff0c;又称作复读玩具或模仿玩具&#xff0c;是一类设计用来录制人声并重复播放的互动式玩具。这类玩具以其能够模仿人类语音的特性而受到小朋友和宠物主人的喜爱。这些玩具通常具有以下特点和功能&#xff1a; 1. 录音和播放功能&#xff…

sc2024项目consul

1. 什么是consul HashiCorp Consul是一款服务网络解决方案&#xff0c;可让团队管理服务之间以及内部部署和多云环境及运行时的安全网络连接。consul提供服务发现、服务治理、流量管理和对网络基础设施设备的自动更新。(添加链接描述)Consul使用Go语言开发 2. 功能 多数据中…

Mysql基础(二)数据类型和约束

一 数据类型 讲解主要的数据类型,不面面俱到,后续遇到具体问题再查询补充扩展&#xff1a; 知识点的深度和广度以工作为导向 ① int float M : 表示显示宽度&#xff0c;M的取值范围是(0, 255)例如: int(5),当数据宽度小于5位的时候在数字前面需要用字符填满宽度说明&…

单链表题目

1.单向链表中的每个结点都需要动态分配内存空间。✔ 2.用链表代替数组进行数据操作时&#xff0c;查询更加方便。✘ 数组进行数据查询会更方便 3.链表是动态存储分配的数据结构。根据需要动态地开辟内存空间&#xff0c;可以比较自由方便地插入新元素&#xff08;结点)&#x…

【Linux】对system V本地通信的内核级理解

一、system V版本的进程间通信技术 通过之前的学习&#xff0c;我们大致可以感受出来&#xff0c;共享内存&#xff0c;消息队列和信号量在使用的时候是有很多共性的。它们三个的接口&#xff0c;包括接口中传的参数有的都有很大的相似度。其实&#xff0c;共享内存&#xff…