• Mybatis学习笔记,挺全的!


    第一部分:自定义持久层框架

    在该部分中主要学习到了以下几个关键知识点:
    在这里插入图片描述

    1.1 分析手动编写JDBC操作面临的问题

    1. 数据库连接频繁创建、销毁造成资源浪费,影响系统性能;
    2. sql语句硬编码,不易维护;
    3. 使用preparedStatement传递sql参数存在硬编码,不易维护;
    4. 对查询结果集解析以及封装成实体类存在硬编码,不易维护;

    1.2 针对性的给出问题的解决思路

    1. 针对问题1,可以使用“享元模式”即“池化”技术,使用数据库连接池来维护数据库连接的创建、回收等;
    2. 针对问题2,可以将sql语句从代码中抽离出来,放到单独的xml配置文件中;
    3. 针对问题3和4,可以使用反射、内省等技术自动将查询结果集绑定到实体类上;

    1.3 尝试编写自定义框架解决面临的问题

    在这里插入图片描述

    1. 配置文件:分为Mybatis全局配置文件和mapper映射文件;
    2. Configuration:上述配置文件对应的Java对象;
    3. SqlSessionFactoryBuilder:拥有一个build()方法,它会将上述的配置文件字节流进行xml解析封装成Configuration对象,再将Configuration对象设置到new出来的SqlSessionFactory并返回;
    4. SqlSessionFactory:拥有一个openSession()方法,用来根据Configuration创建SqlSession对象;
    5. SqlSession:持有Executor的引用,封装了数据库的查询方法;
    6. Executor:真正去实现JDBC的CRUD操作;

    上面自定义的框架会发现和工作中使用的Mybatis框架用法有点出入,这是因为考虑到:

    • 自定义框架使用中存在重复的代码,整个操作的过程模板重复(创建sqlsession,调用sqlsession方 法,
      关闭 sqlsession);
    • 自定义框架使用中存在硬编码,调用sqlsession的方法时,参数statement的id硬编码;

    因此可以针对xml文件定义对应的mapper接口,然后使用动态代理来生成具体的mapper实现类来帮我们自动完成上述操作。

    第二部分:Mybatis相关概念

    在这里插入图片描述

    2.1 简介

    Mybatis是一个半自动化的ORM(对象/关系映射)框架,它支持定制化SQL、存储过程以及高级映
    射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以使用简单的
    XML或注解来配置和映射原生类型、接口和Java的POJO (Plain Old Java Objects,普通老式Java对 象)
    为数据库中的记录。

    2.2 历史

    原是apache的一个开源项目iBatis, 2010年6月这个项目由apache software foundation 迁移到了
    google code,随着开发团队转投Google Code旗下,ibatis3.x正式更名为Mybatis ,代码于2013年11
    月迁移到Github。
    iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框
    架包括SQL Maps和Data Access Objects(DAO)。

    2.3 优势

    Mybatis是一个半自动化的持久层框架,对开发人员开说,核心sql还是需要自己进行优化,sql和java编
    码进行分离,功能边界清晰,一个专注业务,一个专注数据。
    分析图示如下:
    在这里插入图片描述
    相比于Hibernate这种全自动化的ORM框架它更灵活、更轻量。

    第三部分:Mybatis基本应用

    在这里插入图片描述

    3.1 入门

    基本开发步骤:

    ①添加MyBatis的pom依赖
    ②创建user数据表
    ③编写User实体类
    ④编写映射文件UserMapper.xml
    ⑤编写核心文件SqlMapConfig.xml
    ⑥编写测试类

    3.2 常用开发方式

    3.2.1 传统开发方式

    1. 编写Dao接口;
    2. 实现Dao接口,和基本开发步骤类似,主要是通过statementId来定位sql并执行数据库操作;

    3.2.2 代理开发方式

    Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis 框架根据接口
    定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
    Mapper 接口开发需要遵循以下规范:

    1. Mapper.xml文件中的namespace与mapper接口的全限定名相同;
    2. Mapper接口方法名和Mapper.xml中定义的每个statement的id相同;
    3. Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同;
    4. Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同;

    第四部分:Mybatis配置文件深入

    在这里插入图片描述

    4.1 核心配置文件

    SqlMapConfig.xml

    4.1.1 层级关系

    在这里插入图片描述

    4.1.2 常用配置

    1)environments标签
    数据库环境的配置,支持多环境配置
    其中,事务管理器(transactionManager)类型有两种:
    JDBC:这个配置就是直接使用了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作
    用域。
    MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生
    命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接,然而一些容器并不希望这样,因
    此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。
    其中,数据源(dataSource)类型有三种:
    UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。
    POOLED:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来。
    JNDI:这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置
    数据源,然后放置一个 JNDI 上下文的引用。
    2)mapper标签
    该标签的作用是加载映射的,加载方式有如下几种:
    •使用相对于类路径的资源引用,例如:

    •使用完全限定资源定位符(URL),例如:

    •使用映射器接口实现类的完全限定类名,例如:

    •将包内的映射器接口实现全部注册为映射器,例如:

    3)Properties标签

    实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的
    properties文件,该标签必须放在配置文件顶部!
    4)typeAliases标签
    类型别名,是为Java 类型设置一个短的名字。配置方式有:

    • 单个配置,<typeAliases><typeAlias type="com.User" alias="user"></typeAlias></typeAliases>
    • 包配置,<typeAliases><package name="com.jarry.entity"></typeAlias></typeAliases> ,这种方式的别名为类名,不区分大小写

    4.2 映射配置文件

    xxxMapper.xml

    4.2.1 动态sql之if标签

    <select id="findByCondition" parameterType="user" resultType="user">
    select * from User
    <where>
    <if test="id!=0">
    and id=#{id}
    </if>
    <if test="username!=null">
    and username=#{username}
    </if>
    </where>
    </select>
    

    4.2.2 动态sql之foreach标签

    <select id="findByIds" parameterType="list" resultType="user">
    select * from User
    <where>
    <foreach collection="list" open="id in(" close=")" item="id"
    separator=",">
    #{id}
    </foreach>
    </where>
    </select>
    

    4.2.3 动态sql之SQL片段抽取

    <sql id="selectUser" select * from User</sql>
    
    <select id="findById" parameterType="int" resultType="user">
    <include refid="selectUser"></include> where id=#{id}
    </select>
    <select id="findByIds" parameterType="list" resultType="user">
    <include refid="selectUser"></include>
    <where>
    <foreach collection="array" open="id in(" close=")" item="id"
    separator=",">
    #{id}
    </foreach>
    </where>
    </select>
    

    第五部分:Mybatis复杂映射开发

    在这里插入图片描述

    5.1 一对一查询

    public class Order {
    private int id;
    private Date ordertime;
    private double total;
    //代表当前订单从属于哪一个客户
    private User user;
    } p
    ublic class User {
    private int id;
    private String username;
    private String password;
    private Date birthday;
    }
    

    想要从数据库中查询出Order对象,而Oder对象持有一个User对象。

    对应的mapper.xml如下:

    <mapper namespace="com.jarry.mapper.OrderMapper">
    <resultMap id="orderMap" type="com.jarry.domain.Order">
    <result column="uid" property="user.id"></result>
    <result column="username" property="user.username"></result>
    <result column="password" property="user.password"></result>
    <result column="birthday" property="user.birthday"></result>
    </resultMap>
    <select id="findAll" resultMap="orderMap">
    select * from orders o,user u where o.uid=u.id
    </select>
    </mapper>
    

    或者

    <resultMap id="orderMap" type="com.jarry.domain.Order">
    <result property="id" column="id"></result>
    <result property="ordertime" column="ordertime"></result>
    <result property="total" column="total"></result>
    <!--该标签为单个对象封装标签,javaType表示实体该字段的类型-->
    <association property="user" javaType="com.jarry.domain.User">
    <result column="uid" property="id"></result>
    <result column="username" property="username"></result>
    <result column="password" property="password"></result>
    <result column="birthday" property="birthday"></result>
    </association>
    </resultMap>
    

    5.2 一对多查询

    public class Order {
    private int id;
    private Date ordertime;
    private double total;
    //代表当前订单从属于哪一个客户
    private User user;
    } p
    ublic class User {
    private int id;
    private String username;
    private String password;
    private Date birthday;
    //代表当前用户具备哪些订单
    private List<Order> orderList;
    }
    

    从数据库中查询User对象,该User对象持有一个Oder对象的list。

    对应的mapper.xml如下:

    <mapper namespace="com.jarry.mapper.UserMapper">
    <resultMap id="userMap" type="com.jarry.domain.User">
    <result column="id" property="id"></result>
    <result column="username" property="username"></result>
    <result column="password" property="password"></result>
    <result column="birthday" property="birthday"></result>
    <!--该标签为集合封装标签, ofType表示该实体字段集合的泛型类型-->
    <collection property="orderList" ofType="com.jarry.domain.Order">
    <result column="oid" property="id"></result>
    <result column="ordertime" property="ordertime"></result>
    <result column="total" property="total"></result>
    </collection>
    </resultMap>
    <select id="findAll" resultMap="userMap">
    select *,o.id oid from user u left join orders o on u.id=o.uid
    </select>
    </mapper>
    

    5.3 多对多查询

    双向一对多,参考5.2。

    第六部分:Mybatis注解开发

    在这里插入图片描述

    6.1 常用注解

    @Insert:实现新增
    @Update:实现更新
    @Delete:实现删除
    @Select:实现查询
    @Result:实现结果集封装
    @Results:可以与@Result 一起使用,封装多个结果集
    @One:实现一对一结果集封装
    @Many:实现一对多结果集封装

    6.2 一对一

    Mapper接口方法写法如下:

    @Select("select * from orders")
    @Results({
    @Result(id=true,property = "id",column = "id"),
    @Result(property = "ordertime",column = "ordertime"),
    @Result(property = "total",column = "total"),
    @Result(property = "user",column = "uid",
    javaType = User.class,
    one = @One(select = "com.lagou.mapper.UserMapper.findById"))
    })
    List<Order> findAll();
    

    6.3 一对多

    Mapper接口方法写法如下:

    public interface UserMapper {
    @Select("select * from user")
    @Results({
    @Result(id = true,property = "id",column = "id"),
    @Result(property = "username",column = "username"),
    @Result(property = "password",column = "password"),
    @Result(property = "birthday",column = "birthday"),
    @Result(property = "orderList",column = "id",
    javaType = List.class,
    many = @Many(select =
    "com.lagou.mapper.OrderMapper.findByUid"))
    })
    List<User> findAllUserAndOrder();
    } p
    ublic interface OrderMapper {
    @Select("select * from orders where uid=#{uid}")
    List<Order> findByUid(int uid);
    }
    

    6.4多对多

    双向一对多,参考6.3。

    第七部分:Mybatis缓存

    在这里插入图片描述
    在这里插入图片描述

    为了加快查询效率,Mybatis引入了缓存机制。

    ①、一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数
    据结构(HashMap)用于存储缓存数据。不同的sqlSession
    之间的缓存数据区域(HashMap)是互相不影响的。
    ②、二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession
    可以共用二级缓存,二级缓存是跨SqlSession的。

    缓存查询顺序:二级缓存------>一级缓存------->数据库

    7.1 一级缓存

    • 默认开启。
    • SqlSession级别,不同的SqlSession不共享缓存。
    • 底层是一个HashMap结构。
    • 一级缓存的维护是在Executor 类中执行。
    • 执行SqlSession的commit或者clear会导致一级缓存清空,并转存到二级缓存。
    • 在sql标签上配置flushCache=true,可以使一级缓存失效。

    7.2 二级缓存

    • 默认不生效,需要在mapper.xml使用标签,或者在mapper接口上添加@CacheNamespace注解使其生效。
    • Mapper/Namespace级别,和SqlSession无关,不同的SqlSession可以共享同一个Mapper/Namespace的二级缓存。
    • 底层也默认是HashMap结构
    • 开启二级缓存后pojo要实现Serializable接口,使其可以持久化到其他存储介质。
    • 执行增删改,并且提交SqlSession以后会清空对应的二级缓存。

    7.3 二级缓存接入Redis

    Mybatis提供了一个Cache接口,可以实现自己的缓存策略。

    基于HashMap实现换粗无法适用集群或分布式环境,因为他是JVM进程级别的。因此需要整合分布式缓存框架,如Redis。

    mybatis提供了一个针对cache接口的redis实现类。

    使用步骤:

    1. 添加如下maven依赖:
    <dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-redis</artifactId>
    <version>1.0.0-beta2</version>
    </dependency
    
    1. 在mapper.xml加入二级缓存开启标签或者在mapper接口上添加@CacheNamespace(implementation = RedisCache.class)注解
    2. 添加redis配置文件:

    redis.properties

    redis.host=localhost
    redis.port=6379
    redis.connectionTimeout=5000
    redis.password=
    redis.database=0
    

    第八部分:Mybatis插件

    在这里插入图片描述

    8.1 Mybatis插件介绍

    在这里插入图片描述
    mybatis提供四大扩展点:

    • 执行器Executor (update、query、commit、rollback等方法);
    • SQL语法构建器StatementHandler (prepare、parameterize、batch、updates query等方 法);
    • 参数处理器ParameterHandler (getParameterObject、setParameters方法);
    • 结果集处理器ResultSetHandler (handleResultSets、handleOutputParameters等方法);

    8.2 插件原理

    • 基于JDK动态代理;
    • 插件会被保存到interceptorChain;
    • 在执行SQL时,需要先通过DefaultSqlSessionFactory 创
      建 SqlSession。Executor 实例会在创建 SqlSession 的过程中被创建, Executor实例创建完毕后,
      MyBatis会通过JDK动态代理为实例生成代理类。这样,插件逻辑即可在 Executor相关方法被调用前执
      行;

    8.3 自定义插件

    Intercepts ({//注意看这个大花括号,也就这说这里可以定义多个@Signature对多个地方拦截,都用这
    个拦截器
    @Signature (type = StatementHandler .class , //这是指拦截哪个接口
    method = "prepare",//这个接口内的哪个方法名,不要拼错了
    args = { Connection.class, Integer .class}),//// 这是拦截的方法的入参,按顺序写到这,不要多也不要少,如果方法重载,可是要通过方法名和入参来确定唯一的
    })
    public class MyPlugin implements Interceptor {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    // //这里是每次执行操作的时候,都会进行这个拦截器的方法内
    Override
    public Object intercept(Invocation invocation) throws Throwable {
    //增强逻辑
    System.out.println("对方法进行了增强....");
    return invocation.proceed(); //执行原方法
    }
    /**获取配置文件的属性**/
    //插件初始化的时候调用,也只调用一次,插件配置的属性从这里设置进来
    Override
    public void setProperties(Properties properties) {
    System.out.println("插件配置的初始化参数:"+properties );
    }
    }
    

    sqlMapConfig.xml

    <plugins>
    <plugin interceptor="com.lagou.plugin.MySqlPagingPlugin">
    <!--配置参数-->
    <property name="name" value="Bob"/>
    </plugin>
    </plugins>
    

    第九部分:Mybatis架构原理

    在这里插入图片描述

    9.1 总体架构

    在这里插入图片描述
    Mybatis的功能架构分为三层:
    (1) API接口层:提供给外部使用的接口 API,开发人员通过这些本地API来操纵数据库。接口层一接收到
    调用请求就会调用数据处理层来完成具体的数据处理。
    MyBatis和数据库的交互有两种方式:
    a. 使用传统的MyBati s提供的API ;
    b. 使用Mapper代理的方式
    (2) 数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根
    据调用的请求完成一次数据库操作。
    (3) 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是
    共 用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑

    9.2 主要组件

    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述

    9.3 总体流程

    (1) 加载配置并初始化
    触发条件:加载配置文件
    配置来源于两个地方,一个是配置文件(主配置文件conf.xml,mapper文件*.xml),—个是java代码中的 注
    解,将主配置文件内容解析封装到Configuration,将sql的配置信息加载成为一个mappedstatement 对
    象,存储在内存之中
    (2) 接收调用请求
    触发条件:调用Mybatis提供的API
    传入参数:为SQL的ID和传入参数对象
    处理过程:将请求传递给下层的请求处理层进行处理。

    (3) 处理操作请求
    触发条件:API接口层传递请求过来
    传入参数:为SQL的ID和传入参数对象
    处理过程:
    (A) 根据SQL的ID查找对应的MappedStatement对象。
    (B) 根据传入参数对象解析MappedStatement对象,得到最终要执行的SQL和执行传入参数。
    (C) 获取数据库连接,根据得到的最终SQL语句和执行传入参数到数据库执行,并得到执行结果。
    (D) 根据MappedStatement对象中的结果映射配置对得到的执行结果进行转换处理,并得到最终的处理
    结果。
    (E) 释放连接资源。
    (4) 返回处理结果
    将最终的处理结果返回。

    第十部分:Mybatis源码剖析

    10.1 延迟加载

    就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。

    • 优点:
      先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表
      速度要快。
    • 缺点:
      因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时
      间,所以可能造成用户等待时间变长,造成用户体验下降。
    • 在多表中:
      一对多,多对多:通常情况下采用延迟加载
      一对一(多对一):通常情况下采用立即加载
    • 注意:
      延迟加载是基于嵌套查询来实现的

    10.1.1 局部延迟加载

    在association和collection标签中都有一个fetchType属性,通过修改它的值,可以修改局部的加载策
    略。

    <!-- 开启一对多 延迟加载 -->
    <resultMap id="userMap" type="user">
    <id column="id" property="id"></id>
    <result column="username" property="username"></result>
    <result column="password" property="password"></result>
    <result column="birthday" property="birthday"></result>
    <!--
    fetchType="lazy" 懒加载策略
    fetchType="eager" 立即加载策略
    -->
    <collection property="orderList" ofType="order" column="id"
    select="com.lagou.dao.OrderMapper.findByUid" fetchType="lazy">
    </collection>
    </resultMap>
    <select id="findAll" resultMap="userMap">
    SELECT * FROM `user`
    </select>
    

    10.1.2 全局延迟加载

    在Mybatis的核心配置文件中可以使用setting标签修改全局的加载策略。

    <settings>
    <!--开启全局延迟加载功能-->
    <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
    

    局部配置优先于全局配置。

    10.2 延迟加载原理

    • 基于动态代理技术,主要使用:Javassist,Cglib实现。
    • 为pojo生成代理,在调用字段的getter方法时,调用代理方法完成sql的延迟执行。

    第十一部分:设计模式

    在这里插入图片描述
    Mybati s至少用到了以下的设计模式:

    在这里插入图片描述
    在这里插入图片描述

    11.1 Builder模式

    Builder模式的定义是"将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表
    示。”,它属于创建类模式,一般来说,如果一个对象的构建比较复杂,超出了构造函数所能包含的范
    围,就可以使用工厂模式和Builder模式,相对于工厂模式会产出一个完整的产品,Builder应用于更加
    复杂的对象的构建,甚至只会构建产品的一个部分,直白来说,就是使用多个简单的对象一步一步构建
    成一个复杂的对象

    Mybatis中的体现:
    在这里插入图片描述
    SqlSessionFactory 的构建过程:
    Mybatis的初始化工作非常复杂,不是只用一个构造函数就能搞定的。所以使用了建造者模式,使用了
    大 量的Builder,进行分层构造,核心对象Configuration使用了 XmlConfigBuilder来进行构造

    在Mybatis环境的初始化过程中,SqlSessionFactoryBuilder会调用XMLConfigBuilder读取所有的
    MybatisMapConfig.xml 和所有的 *Mapper.xml 文件,构建 Mybatis 运行的核心对象 Configuration
    对 象,然后将该Configuration对象作为参数构建一个SqlSessionFactory对象。

    11.2 工厂模式

    在Mybatis中比如SqlSessionFactory使用的是工厂模式,该工厂没有那么复杂的逻辑,是一个简单工厂
    模式。
    简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于创
    建型模式。
    在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建
    其他类的实例,被创建的实例通常都具有共同的父类

    Mybatis 体现:

    Mybatis中执行Sql语句、获取Mappers、管理事务的核心接口SqlSession的创建过程使用到了工厂模
    式。
    有一个 SqlSessionFactory 来负责 SqlSession 的创建
    在这里插入图片描述
    可以看到,该Factory的openSession ()方法重载了很多个,分别支
    持autoCommit、Executor、Transaction等参数的输入,来构建核心的SqlSession对象。

    11.3 代理模式

    代理模式(Proxy Pattern):给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式 的
    英文叫做Proxy,它是一种对象结构型模式,代理模式分为静态代理和动态代理,我们来介绍动态代 理。

    Mybatis中实现:

    代理模式可以认为是Mybatis的核心使用的模式,正是由于这个模式,我们只需要编写Mapper.java接
    口,不需要实现,由Mybati s后台帮我们完成具体SQL的执行。
    当我们使用Configuration的getMapper方法时,会调用mapperRegistry.getMapper方法,而该方法又
    会调用 mapperProxyFactory.newInstance(sqlSession)来生成一个具体的代理:

    public class MapperProxyFactory<T> {
    private final Class<T> mapperInterface;
    private final Map<Method, MapperMethod> methodCache = new
    ConcurrentHashMap<Method, MapperMethod>();
    public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
    } p
    ublic Class<T> getMapperInterface() {
    return mapperInterface;
    } p
    ublic Map<Method, MapperMethod> getMethodCache() {
    return methodCache;
    @SuppressWarnings("unchecked")
    protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(),
    new
    Class[] { mapperInterface },
    mapperProxy);
    } p
    ublic T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession,
    mapperInterface, methodCache);
    return newInstance(mapperProxy);
    }
    }
    

    在这里,先通过T newInstance(SqlSession sqlSession)方法会得到一个MapperProxy对象,然后调用
    newInstance(MapperProxy mapperProxy)生成代理对象然后返回,该MapperProxy类实现了InvocationHandler接口,并且实现了该接口的invoke方法。通
    过这种方式,我们只需要编写Mapper.java接口类,当真正执行一个Mapper接口的时候,就会转发给
    MapperProxy.invoke方法,而该方法则会调用后续的
    sqlSession.cud>executor.execute>prepareStatement 等一系列方法,完成 SQL 的执行和返回。


    文章来源:拉勾教育Java高新训练营15期

  • 相关阅读:
    linux性能指令分析进阶篇
    数据库提升篇
    linux之基础命令大全
    数据库事务测试以及级联更新级联删除
    【Comet OJ】—模拟赛测试 Day1题解
    【Comet OJ】—模拟赛测试 Day1题解
    【LOJ # 6268】—分拆数(生成函数+多项式Ln/Exp+NTT)
    【LOJ # 6268】—分拆数(生成函数+多项式Ln/Exp+NTT)
    【LOJ #6041】【雅礼集训 2017 Day7】—事情的相似度(后缀自动机+LCT+树状数组)
    【LOJ #6041】【雅礼集训 2017 Day7】—事情的相似度(后缀自动机+LCT+树状数组)
  • 原文地址:https://www.cnblogs.com/xuxiaojian/p/14785303.html
Copyright © 2020-2023  润新知