mybatis的SqlSession

2024-04-23 06:36
文章标签 mybatis sqlsession

本文主要是介绍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对象上。

这篇关于mybatis的SqlSession的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/928036

相关文章

将Mybatis升级为Mybatis-Plus的详细过程

《将Mybatis升级为Mybatis-Plus的详细过程》本文详细介绍了在若依管理系统(v3.8.8)中将MyBatis升级为MyBatis-Plus的过程,旨在提升开发效率,通过本文,开发者可实现... 目录说明流程增加依赖修改配置文件注释掉MyBATisConfig里面的Bean代码生成使用IDEA生

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

Spring Boot结成MyBatis-Plus最全配置指南

《SpringBoot结成MyBatis-Plus最全配置指南》本文主要介绍了SpringBoot结成MyBatis-Plus最全配置指南,包括依赖引入、配置数据源、Mapper扫描、基本CRUD操... 目录前言详细操作一.创建项目并引入相关依赖二.配置数据源信息三.编写相关代码查zsRArly询数据库数

Spring Boot 整合 MyBatis 连接数据库及常见问题

《SpringBoot整合MyBatis连接数据库及常见问题》MyBatis是一个优秀的持久层框架,支持定制化SQL、存储过程以及高级映射,下面详细介绍如何在SpringBoot项目中整合My... 目录一、基本配置1. 添加依赖2. 配置数据库连接二、项目结构三、核心组件实现(示例)1. 实体类2. Ma

Mybatis从3.4.0版本到3.5.7版本的迭代方法实现

《Mybatis从3.4.0版本到3.5.7版本的迭代方法实现》本文主要介绍了Mybatis从3.4.0版本到3.5.7版本的迭代方法实现,包括主要的功能增强、不兼容的更改和修复的错误,具有一定的参考... 目录一、3.4.01、主要的功能增强2、selectCursor example3、不兼容的更改二、

mybatis-plus分页无效问题解决

《mybatis-plus分页无效问题解决》本文主要介绍了mybatis-plus分页无效问题解决,原因是配置分页插件的版本问题,旧版本和新版本的MyBatis-Plus需要不同的分页配置,感兴趣的可... 昨天在做一www.chinasem.cn个新项目使用myBATis-plus分页一直失败,后来经过多方

mybatis-plus 实现查询表名动态修改的示例代码

《mybatis-plus实现查询表名动态修改的示例代码》通过MyBatis-Plus实现表名的动态替换,根据配置或入参选择不同的表,本文主要介绍了mybatis-plus实现查询表名动态修改的示... 目录实现数据库初始化依赖包配置读取类设置 myBATis-plus 插件测试通过 mybatis-plu

MyBatis-Plus中Service接口的lambdaUpdate用法及实例分析

《MyBatis-Plus中Service接口的lambdaUpdate用法及实例分析》本文将详细讲解MyBatis-Plus中的lambdaUpdate用法,并提供丰富的案例来帮助读者更好地理解和应... 目录深入探索MyBATis-Plus中Service接口的lambdaUpdate用法及示例案例背景

MyBatis-Plus中静态工具Db的多种用法及实例分析

《MyBatis-Plus中静态工具Db的多种用法及实例分析》本文将详细讲解MyBatis-Plus中静态工具Db的各种用法,并结合具体案例进行演示和说明,具有很好的参考价值,希望对大家有所帮助,如有... 目录MyBATis-Plus中静态工具Db的多种用法及实例案例背景使用静态工具Db进行数据库操作插入