2020年8月25日20:55:29

自定义持久层框架

  • 持久层框架 是对jdbc 的封装, 并解决了jdbc存在的问题
jdbc 代码基础回顾
try{
    Class.formName("com.mysql.jdbc.Driver");
    connection = .....
}cache(Exception e){
    
}
  • 传统jdbc 存在 数据库配置信息存在硬编码问题 当更换数据库后需要再次对数据库驱动信息进行更改
  • 频繁创建释放数据库连接
  • sql语句 设置参数 获取结果集等参数均存在硬编码问题
  • 手动封装结果集 较为繁琐
解决传统jdbc存在的问题
  • 硬编码 –> 配置文件
  • 硬编码 –> 连接池
  • 手动封装结果集 –> 反射 内省
自定义持久层框架设计思路
使用端 –> 项目
  • 引入自定义持久层jar
  • 提供数据库配置信息及sql配置信息
    • sql配置信息
      • sql语句
      • 参数类型
      • 返回值类型
  • 使用配置文件提供外上述两种配置信息
  • sqlMapConfig.xml 存放数据库的配置信息,存入mapper.xml全路径
  • mapper.xml 存放sql配置信息
自定义持久层框架本身
  • 创建为项目工程,本质是对jdbc代码进行封装-->底层为传统的jdbc

    • 数据库配置信息
    • sql 配置信息 占位符 参数 sql语句等
    • 根据调用处传递的配置信息进行解析
      • 加载配置文件 --> 以字节输入流的形式加载 --> 存储在内存中
      • 创建Resource类,getResourceAsStream(String path)
      • 创建2个javaBean(容器对象),存放的是对配置文件解析出的内容
        • Configuration:核心配置类: 存放sqlMapperConfig.xml解析的内容
        • MappedStrement:映射配置类:存放mapper.xml解析的内容
      • 解析配置文件:Dom4j
        • 创建类:SqlSessionFactoryBuilder,存在方法:build(InputStream in)
        • build方法实现逻辑:
          • 使用dom4j解析配置文件,将解析结果封装到容器对象内
          • 创建sqlSessionFactory对象,生产sqlSession(会话对象),避免重复创建连接 --> 工厂模式 降低耦合
      • 创建sqlSessionFactory接口及实现类DefaultSqlSessionFactory
        • openSession方法 : 创建 sqlSession对象
      • 创建SqlSession 接口及实现类DefaultSqlSession 定义对数据库的CRUD方法
        • selectList()
        • selectOne()
        • update()
        • delete()
      • 创建Excutor接口及实现类 SimpleExcutor 实现类
        • query(Configuration conf,MappedStatement mapped,Object …params):执行JDBC代码

    graph TB
    b("工程项目")
    
    subgraph 工程项目
    d("mapper.xml") --"mapper.xml全路径"--> c("sqlMapConfig.xml")
    b --"sql执行语句"--> d
    b --"数据库配置"--> c
    end
    
    b --"引用"--> a
    
    subgraph 自定义持久层
    tip("本质是对jdbc代码的封装")
    a("自定义持久层")
    
    tip --> a
    a --"1. 创建"--> a1("Resources类")
    a1 --> a1a("InputStream()")
    a1 --"加载配置文件为字节输入流"--> a1b("getResourceAsStream(String path)")
    
    
    a --"2. 创建"--> a2("容器javaBean")
    
    subgraph 容器
    a2 --"创建核心配置类"--> a2a("Configuration")
    a2a --"存放"--> a21a("sqlMapConfig.xml 解析的内容")
    a2 --"创建核心配置类"--> a2b("MappedStatement")
    a2b --"映射配置类"--> a2b1("mapper.xml 解析的内容")
    end
    
    a --"3. 创建"--> a3("SqlSessionFactory")
    a3 --"实现类"--> a3a("DefaultSqlSessionFactory")
    a3a --"方法"--> a3a1("openSession()")
    a3a1 --"生产"--> a3a1a("Sqlsession")
    
    a --"4. 解析配置文件dom4j"--> a4("SqlSessionFactoryBuilder")
    a4 --"方法"--> a41("build(inputStream in)")
    a41 --"使用dom4j解析配置文件" --> a4a1a("解析结果")
    a4a1a --"封装到容器对象"--> a2
    a41 --"创建"--> a41b("SqlSessionFactory对象")
    a41b  --"工厂模式生产"--> a41b1("sqlSession会话对象")
    
    a --"5. 创建"--> a5("SqlSession接口")
    a5 --"实现类"--> a5a("DefaultSession")
    a5a --"列表查询"--> a5a1("selectList()")
    a5a --"查询单个"--> a5a2("selectONe()")
    a5a --"修改"--> a5a3("update()")
    a5a --"删除"--> a5a4("delete()")
    
    a --"6. 创建"--> a6("Excutor接口")
    a6 --"实现类"--> a6a("SimpleExcutor")
    a6a --"成员方法"--> a6a1("query(Configuration conf,MappedStatement st,Object ...params);")
    a6a1 --"执行jdbc代码" -->a6a1a("sql语句")
    end
    
    

mybatis 简介

  • 持久层框架

  • 基于orm:Object Relation Mapping 实体类和数据库表建立映射关联关系

  • 半自动 可以对sql进行优化 hibernate -> 全自动

  • 轻量级:启动的过程中需要的资源比较少

  • 底层: 对jdbc执行代码 进行封装 规避硬编码,频繁开闭数据源

sqlMapConfig.xml 节点说明
  • environments 数据库环境的配置,支持多环境配置
  • environments.default--> 指定mybatis 使用的默认环境名称
  • environment.id-->当前环境的名称
  • environment – transcationManager.type=”JDBC” 指定事务管理类型为jdbc
  • environment – dataSource.type=”POOLED” 指定数据源类型为连接池
  • environment – dataSource
    • property.driver 数据库驱动
    • property.url 数据库地址 注意连接编码格式
    • property.user 数据库连接用户名
    • property.password 数据库连接用密码
  • mapper 配置的四种方式:
    • mapper.resource 相对于类路径的引用
    • mapper.url 完全限定资源定位符
    • mapper.class 接口对应的全路径
    • package.name 批量加载 保证映射文件与接口同包同名

传统dao层开发方式
dao层开发方式
mybatis 外部properties 文件
  • 设置mybatis xml配置文件的约束头
  • 在resources下创建外部配置文件 格式:对象.属性=值
  • 加载外部配置文件
    • 在 configutation 后第一个节点之前 引入外部配置文件 <properties resource='路径'/>
mybatis aliasType
  • 在mybatis 配置文件中的typeAliases 节点中设置
    <typeAliases>
        <typeAlias type="pojo类路径的全限定名" alais="别名"></typeAlias>
    </typeAliases>
    // 对于基础数据类型 mybatis 已定义了别名
    string ==> String
    long ==> Long
    int ==> Integer
    double ==> Double
    boolean ==> Boolean
    
  • 当存在多个pojo时不适用以上方法,采用package模式[批量起别名]
    • package模式 不要单独指定alias属性 默认为类本身的类名,且不区分大小写
    <typeAliases>
        <package name="pojo类所在包的全限定名"></typeAlias>
        // 不要单独指定alias属性 默认为类本身的类名,且不区分大小写
    </typeAliases>
    
mapper.xml
动态sql
  • if 标签 判断入参是否符合条件, 不符合不拼接
  • where 标签 自动拼接where 同时去掉where后的第一个and 关键字
  • foreach 标签

    • collection array 注意便携式不要使用#{}
    • open 循环前追加
    • close 循环结束后追加
    • item 单次循环内的数据对象 生成的变量
    • separator 前后循环数据之间的分隔符
  • sql 标签 抽取sql片段

    • id sql语句的标识
    • 内容为具体的sql语句 可用于封装 分页 和 查询某张表时的前面部分
mybatis复杂映射开发

sqlMapConfig.xml 内引入 mapper.xml

<package name="与接口同包同名的包名"><package>
一对一查询
  • resultMap 手动配置实体属性与表字段的映射关系 可用于mybatis 的resultMMap

    • id
    • type 按照封装对象的全路径
    <resultMap id="orderMap" type="com.lagou.pojo.Order">
        <result property="id" column="id"></result>
        <result property="orderTime" column="orderTime"></result>
        <result property="total" column="total"></result>
    
        <association property="user" javaType="com.lagou.pojo.User">
            <result property="id" column="uid"></result>
            <result property="username" column="username"></result>
        </association>
    </resultMap>
    
    <!--resultMap:手动来配置实体属性与表字段的映射关系-->
    <select id="findOrderAndUser" resultMap="orderMap">
        select * from orders o,user u where o.uid = u.id
    </select>
    
一对多查询
    <resultMap id="userMap" type="com.lagou.pojo.User">
        <result property="id" column="uid"></result>
        <result property="username" column="username"></result>
        <collection property="orderList" ofType="com.lagou.pojo.Order">
            <result property="id" column="id"></result>
            <result property="orderTime" column="orderTime"></result>
            <result property="total" column="total"></result>
        </collection>
    </resultMap>

    <select id="findAll" resultMap="userMap">
        select * from user u left join orders o on u.id = o.uid
    </select>
多对多查询
  • 查询用户的同时查询出用户的角色
   <resultMap id="userRoleMap" type="com.lagou.pojo.User">
       <result property="id" column="userid"></result>
       <result property="username" column="username"></result>
       <collection property="roleList" ofType="com.lagou.pojo.Role">
           <result property="id" column="roleid"></result>
           <result property="roleName" column="roleName"></result>
           <result property="roleDesc" column="roleDesc"></result>
       </collection>
   </resultMap>

   <select id="findAllUserAndRole" resultMap="userRoleMap">
       select * from user u left join sys_user_role ur on u.id = ur.userid
   		left join sys_role r on r.id = ur.roleid
   </select>

mybatis 注解开发

使用注解开发 无需编写任何配置文件

  • @Insert 增
  • @Update 删
  • @Delete 改
  • @Select 查
  • @Result 实现对结果集的封装 替代result标签节点
  • @Results 替代resultMap 标签节点
  • @One 替代单个pojo对象 替代 association 标签节点
  • @Many 如果属性为集合时 则采用 此注解
注解一对多
@Results({
    @Result(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.IUserMapper.findUserById"))
})
@Select("select * from orders")
public List<Order> findOrderAndUser();
注解多对多
# IUserMapper
    //查询所有用户、同时查询每个用户关联的角色信息
    @Select("select * from user")
    @Results({
            @Result(property = "id",column = "id"),
            @Result(property = "username",column = "username"),
            @Result(property = "roleList",column = "id",javaType = List.class,
             many = @Many(select = "com.lagou.mapper.IRoleMapper.findRoleByUid"))
    })
    public List<User> findAllUserAndRole();
# IRoleMapper
    @Select("select * from sys_role r,sys_user_role ur where r.id = ur.roleid and ur.userid = #{uid}")
    public List<Role> findRoleByUid(Integer uid);
mybatis 缓存
一级缓存

使用同一个sqlSession 对象时,数据会被缓存
mybatis 一级缓存过程图解

  1. 第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从
    数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。
  2. 如果中间sqlSession去执行commit操作(执行插入、更新、删除),则会清空SqlSession中的
    一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
  3. 第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直
    接从缓存中获取用户信息
一级缓存分析

一级缓存分析 流程图

  • 一级缓存到底是什么
    底层是一个hashMap 参照上述流程图
    
  • 一级缓存什么时候被创建
    缓存key创建类: Excustor.class.createCacheKey()
    BaseExcutor.createCacheKey() //创建一级缓存的key
    
    CacheKey.update()
      - updateList.add(configuration.getEnviroment().getId());
    
  • 一级缓存的工作流程是怎样的
  • 一级缓存的清空 sqlSession.close() 或者执行带有事务的操作
  • 在分布式环境下也会存在脏读问题 解决:禁用一级缓存或调整缓存为statement 级别
二级缓存
  • 原理 类似 一级缓存
  • 操作的sqlSession 执行了事务操作后 会清空二级缓存
  • 一级缓存 默认开启
  • 二级缓存需要手动配置开启
    1. xml开发形式
    <setting>
        <setting name="cacheEnabled" value="true" />
    </setting>
    2. 注解形式
    在dao接口上添加注解 @CacheNamespace
    
  • 二级缓存 缓存的不是对象 而是对象中的数据
    • pojo类需要实现 Serializable 接口
    • 二级缓存的存储机制是多样的,可能存储在硬盘上 或者内存中
  • 当执行带有事务的操作后,二级缓存会被清空
  • 当基于xml配置时还可以配置
    • useCache 属性 false 禁用二级缓存 每次查询都发送sql去数据库查询 默认为true
    • 注解形式:@select 注解之前添加 @Options(cache="false")
    • flushCache 属性: 每次增删改操作后 清空缓存 默认true

二级缓存整合redis

mybatis二级缓存结构示意图

  • PerpetualCache 是mybatis默认实现缓存功能的类
  • 二级缓存的底层数据结构 还是 HashMap org.apache.ibatis.cache.impl.PerpetualCache --> private Map<Object, Object> cache = new HashMap()
  • 指定mybatis二级缓存的实现类
    在dao接口上添加注解 
    @CacheNamespace(implementation=PerpetualCache.class) 
    PerpetualCache.class 更换为自定义缓存实现类
    如 : @CacheNamespace(implementation = RedisCache.class)
    
  • 二级缓存 存在的问题
    • 单服务器下 –> 没问题
    • 分布式 –> 无法实现分布式缓存
  • 分布式缓存技术
    • redis 官方提供有mybatis-redis实现类
    <dependency>
        <groupId>org.mybatis.caches</groupId>
        <artifactId>mybatis-redis</artifactId>
        <version>1.0.0-beta2</version>
    </dependency>
    
    配置配置文件 : redis.properties
    配置以下属性:
      host=localhost
      port=6379
      connectionTimeout=5000
      password=123456
      database=0
    
    • memcached
    • ehcache
  • 二级缓存存在的脏读问题分析
    二级缓存namespace级别产生脏读问题分析
redis-cache 分析
  • redis-cache 是如何存取值的
    1. 必须实现mybatis 的cache 接口
    2. 使用 jedis.hget 进行取值
    
  • redis-cache 使用的是哪种redis 数据结构
    • redis 的 hash 数据类型

mybatis的插件

  • 一种形式的拓展点
    • 增加灵活性
    • 根据实际需求 自行拓展
  • mybatis 的四大组件 及允许拦截的方法
    • Executor 执行器
      • update
      • query
      • commit
      • rollback 等
    • StatementHandler sql语法构建器
      • prepare
      • parameterize
      • batch
      • update
      • query 等
    • ParameterHandler 参数处理器
      • getParameterObject
      • setParameterObject
    • ResultSetHandler 结果集处理器
      • handleResultSets
      • handleOutputParameters
  • 插件拦截器底层是对以上四个组件的拦截,采用动态代理实现
以上组件的创建原理
  1. 每个创建出来的对象不是直接返回的,而是interceptorChain.pluginAll(parameterHandler)
  2. 获取到所有的Interceptor(拦截器)(插件需要实现的接口);调用interceptor.plugin(target);返回target包装后的对象
  3. 插件机制,我们可以使用插件为目标对象创建一个代理对象;AOP(面向切面)我们的插件可以为四大对象创建出代理对象,代理对象就可以拦截到四大对象的每一个执行;
  4. 由于使用了jdk动态代理,那么就回去执行 invoke 方法,可以在拦截器 的前置和后置处理器内做相应的处理操作
@Intercepta({
    @signature(
        type=Executor.class,
        method="query",
        args=(MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class}
    )
})
public class ExamplePlugin implements Interceptor{
//省略逻辑
}
自定义mybatis 插件
  • 插件 –> 拦截器
org.apache.ibatis.plugin.Interceptor 类
# 拦截方法:只要被拦截的目标对象的目标方法被执行时,每次都会执行intercept方法
Interceptor.intercept 
# 主要为了把当前的拦截器生成代理存到拦截器链中
Interceptor.plugin
# 获取配置文件的参数
Interceptor.setProperties
  • 定义

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;

import java.sql.Connection;
import java.util.Properties;

# 可以多个Signature 
@Intercepts({
    @Signature(type= StatementHandler.class,method = "prepare",args = {Connection.class,Integer.class}),
    @Signature(type= Executor.class,method = "prepare",args = {Connection.class,Integer.class})
})
public class MyPlugin implements Interceptor {
    /*
        拦截方法:只要被拦截的目标对象的目标方法被执行时,每次都会执行intercept方法
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("对方法:" + invocation.getMethod().getName() + " 进行了增强...." );
        return invocation.proceed(); //原方法执行
    }
    /*
       主要为了把当前的拦截器生成代理存到拦截器链中
     */
    @Override
    public Object plugin(Object target) { Object wrap = Plugin.wrap(target, this); return wrap; }
    /*
        获取配置文件的参数
     */
    @Override
    public void setProperties(Properties properties) { System.out.println("获取到的配置文件的参数是:"+properties); }
}
  • 配置
<plugins>
    <plugin interceptor="com.lagou.plugin.MyPlugin">
        <property name="name" value="tom"/> <!-- 设置参数 -->
    </plugin>
</plugins>
  • 使用
1. MyPlugin.plugin --> MyPlugin.intercept  --> MyPlugin.setProperties 
mybatis的第三方插件
  • PageHelper
    • 导入maven 依赖
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>3.7.5</version>
    </dependency>
    
    • 在mybatis配置文件中配置PageHelper
    在 plugins 节点内 添加 plugin 并设置属性 `property` 方言 `dialect` 值设 `mysql`
    <plugin interceptor="com.github.pagehelper.PageHelper">
        <property name="dialect" value="mysql"/>
    </plugin>
    
  • 通用 mapper
    • 导入依赖
    <dependency>
        <groupId>tk.mybatis</groupId>
        <artifactId>mapper</artifactId>
        <version>3.1.2</version>
    </dependency>
    
    • mybatis 的配置文件内配置 通用mapper 的plugin
    <plugin interceptor="tk.mybatis.mapper.mapperhelper.MapperInterceptor">
        <!--指定当前通用mapper接口使用的是哪一个-->
        <property name="mappers" value="tk.mybatis.mapper.common.Mapper"/>
    </plugin>
    
    • 实体类设置关联
    @Table(name = "user")
    public class User implements Serializable {
    
        @Id //对应的是注解id
        @GeneratedValue(strategy = GenerationType.IDENTITY) 
        // @GeneratedValue strategy 设置主键的生成策略
        // GenerationType.IDENTITY 底层必须支持自增长
        // GenerationType.SEQUENCY 底层不支持自增长
        // GenerationType.TABLE 从表中取值 生成主键
        // GenerationType.AUTO 自动选择合适的生成主键
        private Integer id;
        
        @Column(name="123") 当与表的字段不同时,采用@Column 保持同步
        private String username;
        // Get Set 略
    }
    
    • 创建dao接口 继承tk.mybatis.mapper.common.Mapper传入泛型
    egg: public interface UserMapper  extends Mapper<User> {}
    
    • 使用
      • 传统调用
      InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
      SqlSession sqlSession = sqlSessionFactory.openSession();
      UserMapper mapper = sqlSession.getMapper(UserMapper.class);
      User user = new User();
      user.setId(1);
      User user1 = mapper.selectOne(user);
      System.out.println(user1);
      
      • Example 方式调用
      InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
      SqlSession sqlSession = sqlSessionFactory.openSession();
      UserMapper mapper = sqlSession.getMapper(UserMapper.class);
      // example 方式调用
      Example example = new Example(User.class);
      // 查询User表中的全部记录
      example.createCriteria().andEqualTo("id",1);
      // 执行查询,获得结果
      List<User> users = mapper.selectByExample(example);
      for (User user2 : users) {
          System.out.println(user2);
      }
      

随堂测试01 自定义持久层框架

  1. 自定义持久层框架IPersistence是如何解决JDBC存在的问题:() [多选题]

    • [x] A. 用配置文件解决了硬编码问题
    • [x] B.使用了C3P0连接池解决了频繁创建释放数据库连接问题
    • [x] C.在simpleExecute中使用到了反射进行了参数的设置
    • [x] D.在simpleExecute中使用了内省进行了返回结果集的封装
  2. 在进行自定义持久层框架IPersistence优化时,主要为了解决那些问题:() [多选题]

    • [x] A.应用在Dao层,整个操作的模板代码重复
    • [x] B.调用sqlSession方法时、参数statementId硬编码
    • [ ] C.无法保证statementId的唯一性
    • [ ] D.参数存在硬编码
  3. 下列关于Configuration及MappedStatement配置类,说法正确的是:() [多选题]

    • [x] A.使用dom4j对sqlMapConfig.xml解析时,会将解析出来的内容以不同形式封装到Configuration对象中
    • [ ] B.使用dom4j对mapper.xml解析时,每个标签的内容均对应一个MappedStatement对象
      [x] C.Configuration中包含了MappedStatement的引用
      [ ] D.MappedStatement对象对应Mapper.xml,一个Mapper.xml对应一个MappedStatement对象

      下列关于GenericTokenParser类,说法正确的是:() [多选题]

      [x] A.该类只能通过有参构造进行创建
      [x] B.GenericTokenParser是通用的标记解析类
      [x] C.GenericTokenParser在解析#{}占位符时必须要通过标记处理类TokenHandler的配合
      [x] D.GenericTokenParse三个构造参数分别为开始标记、结束标记、标记处理器

      随堂测试02 MyBatis基础回顾及高级应用

      在一个MyBatis的应用中,关于SlqessionFactoyfBuilder,SqlsessionFactory以及Sqlsession的应用范围和生命周期,以下说法错误的是:()

      [ ] A.SqlSessionFactoryBuilder的最佳范围为方法范围,即可要定义为本地方法变量
      [ ] B.SqlSessionFactory的最佳范围是应用范围
      [ ] C.SqlSession的最佳范围是方法范围或请求范围
      [x] D.SqlSession执行CRUD操作,不同线程可以共享使用

      在Mybatis中,下列关于ResultType说法错误的是:()

      [ ] A.ResultType表示返回值类型为:完整类名或别名,Mybatis也允许使用基本的数据类型,包括String、int类型
      [ ] B.ResultType和ResultMap的数据结构是一样的,都是Map结构
      [x] C.如果POJO的属性名与SQL语句查询出来的字段名不一致的话,也可使用resultType来进行结果的自动映射
      [ ] D.ResultType和ResultMap不能同时使用

      使用MyBatis的时候,除了可以使用@Param注解来实现多参数入参,还可以用()传递多个参数值:()

      [x] A.用Map对象可以实现传递多参数值
      [ ] B.用List对象可以实现传递多参数值
      [ ] C.用数组的方式传递
      [ ] D.用Set集合的方式传递

      Mapper接口开发需要遵循下列哪些规范? [多选题]

      [x] A.Mapper.xml文件中的namespace与mapper接口的类路径相同
      [x] B.Mapper接口方法名和Mapper.xml 中定义的每个statement的id相同
      [x] C.Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
      [x] D.Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

      mybatis架构原理
      2020年8月25日21:20:04

      接口层

      传统方式 –> sqlSession.selectList()…
      mapper代理方式 –> 代理对象 –> 内省

      数据处理层
      框架支撑层

      层次结构示意图

      mybatis传统方式源码分析

      Configuration
      SqlSession 是Mybatis 中用于和数据库交互的顶层类,通常与ThreadLocal绑定,一个会话使用一个SqlSession,并且在使用完毕后需要close

      DefaultSqlSession 默认
      SqlSession中较为重要的两个参数 configuration与初始化时相同,Executor为执行器
      openSession 生产DefaultSqlSession实例对象,设置事务不自动提交,完成Executor对象的创建

      Mapper代理方式

      如何对mapper接口产生代理对象
      代理对象在调用方法时,底层的invoke方法是如何执行的

      设计模式

      Builder模式(构建者模式) –>

      如果某个对象的构建比较复杂或超出了构建函数所能包含的范围时,就可以使用工厂模式和构建者模式
      使用多个简单对象 一步一步 构建出一个复杂的对象
      egg: 构建电脑 –> 各个组件的构建

      工厂方法模式

      简单工厂模式 根据传入的参数不同创建其他不同的实例
      被创建的实例一般都具有相同父类

      单例模式
      代理模式
      组合模式
      模板方法模式
      适配器模式
      装饰者模式
      迭代器模式

      mybatis 执行流程图解

      mybatis延迟加载

      一对多,延迟加载,多对一 立即加载 当同时配置了局部和全局, 那么局部优先于全局
      主要通过动态代理的方式实现的,通过代理拦截到指定的方法,执行数据加载

      局部延迟

      <1–关闭一对一延迟加载–>
      <resultMap id=”orderMap”type=”order”>
      <id column=”id”property=”id”></id>
      <result column=”ordertime”property=”ordertime”></result>
      <result column=”total”property=”total”></result>
      <!–
      fetchrype=”lazy”懒加载策略
      fetchType=”eager”立即加载策略
      –>
      <association property=”user”column=”uid”javarype=”user”
      select=”com.lagou.dao.UserMapper.findById”fetchrype=”eager”I
      </association>
      </resultMap>

      全局延迟
      在核心配置文件中的setting 标签

      <settings>
      <1–开启全局延迟加载功能–>
      <setting name=”lazytoadingEnabled”value=”true”/>
      </settings>I

      idea 调试延迟加载的注意点

      mybatis 动态sql相关类

      SqlNode 接口
      SqlSource Sql 源接口
      BoundSql 类

      XMLConfigBuilder 在执行过程中会调用 XMLMapperBuilder

      XMLMapperBuilder 内部使用XMLStatementBuilder 处理xml中的各个节点

      XMLStatementBuilder

      解析xml文件中的各个节点,如select,insert,update,delete节点,
      内部会使用XMLScriptBuilder处理节点的sql部分,
      遍历产生的数据会丢到Configuration的mappedStatements中。

      XMLScriptBuilder 解析sql内容,会使用到LanguageDriver接口极其实现类,该接口的主要作用是构建SQL

      LanguageDriver –> 追踪 mybatis 拼接sql的具体执行部分

      mybatis 四大对象的生命周期及应用范围

      SqlSession :现成不安全,作用于请求或方法期间

      常用的数据库连接池

      c3p0 架构复杂
      dbcp 迭代了一个版本
      druid 功能全面 中文文档

      mybatis 查询数据量大的时候会造成oom 如何处理

      ?

版权声明:本文为Yount原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/Yount/p/13902939.html