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设置值为null不起作用问题及解决

《mybatis和mybatis-plus设置值为null不起作用问题及解决》Mybatis-Plus的FieldStrategy主要用于控制新增、更新和查询时对空值的处理策略,通过配置不同的策略类型... 目录MyBATis-plusFieldStrategy作用FieldStrategy类型每种策略的作

SpringBoot+MyBatis-Flex配置ProxySQL的实现步骤

《SpringBoot+MyBatis-Flex配置ProxySQL的实现步骤》本文主要介绍了SpringBoot+MyBatis-Flex配置ProxySQL的实现步骤,文中通过示例代码介绍的非常详... 目录 目标 步骤 1:确保 ProxySQL 和 mysql 主从同步已正确配置ProxySQL 的

MyBatis-Flex BaseMapper的接口基本用法小结

《MyBatis-FlexBaseMapper的接口基本用法小结》本文主要介绍了MyBatis-FlexBaseMapper的接口基本用法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具... 目录MyBATis-Flex简单介绍特性基础方法INSERT① insert② insertSelec

在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码

《在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码》在MyBatis的XML映射文件中,trim元素用于动态添加SQL语句的一部分,处理前缀、后缀及多余的逗号或连接符,示... 在MyBATis的XML映射文件中,<trim>元素用于动态地添加SQL语句的一部分,例如SET或W

Mybatis官方生成器的使用方式

《Mybatis官方生成器的使用方式》本文详细介绍了MyBatisGenerator(MBG)的使用方法,通过实际代码示例展示了如何配置Maven插件来自动化生成MyBatis项目所需的实体类、Map... 目录1. MyBATis Generator 简介2. MyBatis Generator 的功能3

Mybatis提示Tag name expected的问题及解决

《Mybatis提示Tagnameexpected的问题及解决》MyBatis是一个开源的Java持久层框架,用于将Java对象与数据库表进行映射,它提供了一种简单、灵活的方式来访问数据库,同时也... 目录概念说明MyBATis特点发现问题解决问题第一种方式第二种方式问题总结概念说明MyBatis(原名

SpringBoot基于MyBatis-Plus实现Lambda Query查询的示例代码

《SpringBoot基于MyBatis-Plus实现LambdaQuery查询的示例代码》MyBatis-Plus是MyBatis的增强工具,简化了数据库操作,并提高了开发效率,它提供了多种查询方... 目录引言基础环境配置依赖配置(Maven)application.yml 配置表结构设计demo_st

解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题

《解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题》本文主要讲述了在使用MyBatis和MyBatis-Plus时遇到的绑定异常... 目录myBATis-plus-boot-starpythonter与mybatis-spring-b

Spring Boot 中整合 MyBatis-Plus详细步骤(最新推荐)

《SpringBoot中整合MyBatis-Plus详细步骤(最新推荐)》本文详细介绍了如何在SpringBoot项目中整合MyBatis-Plus,包括整合步骤、基本CRUD操作、分页查询、批... 目录一、整合步骤1. 创建 Spring Boot 项目2. 配置项目依赖3. 配置数据源4. 创建实体类

Mybatis拦截器如何实现数据权限过滤

《Mybatis拦截器如何实现数据权限过滤》本文介绍了MyBatis拦截器的使用,通过实现Interceptor接口对SQL进行处理,实现数据权限过滤功能,通过在本地线程变量中存储数据权限相关信息,并... 目录背景基础知识MyBATis 拦截器介绍代码实战总结背景现在的项目负责人去年年底离职,导致前期规