mybatis3.4.6 源码分析笔记

目录:使用+使用中的异常+源码

从使用开始,一些常用功能,梳理一下代码调用流程,整理一些功能的实现,值得学习参考的地方,最后对于框架中不理解的地方提出的疑问

资源:本章节的用到的测试代码,mybatis的功能测试及手写mybatis的代码
https://github.com/shenwuwu/mybatis-mybatisTest
mybatis源码:含少量注释,个人理解
https://github.com/shenwuwu/mybatis-mybatis-3.4.6

欢迎大家在评论中指出错误,有什么问题也可以共同交流共同学习,感谢!

网配置教程:
http://www.mybatis.org/mybatis-3/
源码下载:
mybatis3.4.6 源码分析笔记_第1张图片

ORM(来自baidu):
对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换

自我梳理了一下mybatis,欢迎大神批评指正,交流学习,感谢!

常用使用说明

  1. 使用mybatis集成pom配置
    使用我的练习项目;第一次自己搭maven
    mybatis3.4.6 源码分析笔记_第2张图片
    可以在一个maven工程里放子工程,这个方式还挺好的;两个子项目可以共用父项目的pom配置


	<dependencies>
		
		<dependency>
			<groupId>mysqlgroupId>
			<artifactId>mysql-connector-javaartifactId>
			<version>8.0.13version>
		dependency>
		
		
		<dependency>
		  <groupId>org.mybatisgroupId>
		  <artifactId>mybatisartifactId>
		  <version>3.4.6version>
		dependency>
		
		
		<dependency>
            <groupId>org.apache.logging.log4jgroupId>
            <artifactId>log4j-coreartifactId>
            <version>${log4j2.version}version>
        dependency>
        <dependency>
            <groupId>org.apache.logging.log4jgroupId>
            <artifactId>log4j-apiartifactId>
            <version>${log4j2.version}version>
        dependency>
        
        
        <dependency>
		    <groupId>org.javassistgroupId>
		    <artifactId>javassistartifactId>
		    <version>3.21.0-GAversion>
		dependency>
		
		<dependency>
		    <groupId>ognlgroupId>
		    <artifactId>ognlartifactId>
		    <version>2.7.3version>
		dependency>
		
		
		
		
		<dependency>
		    <groupId>com.github.pagehelpergroupId>
		    <artifactId>pagehelperartifactId>
		    <version>5.1.7version>
		dependency>
		
	dependencies>

maven工程配置,pom文件配置;如果需要jar包可以在这里搜
https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api/5.3.1

  1. 使用generator插件使用
    pom配置
  <build>
  	<plugins>
        <plugin>
            <groupId>org.mybatis.generatorgroupId>
            <artifactId>mybatis-generator-maven-pluginartifactId>
            <version>1.3.7version>
             <configuration>
             	
                <verbose>trueverbose>
                
                <overwrite>trueoverwrite>
                <configurationFile>src/main/resources/config/generatorConfig.xmlconfigurationFile>
            configuration>
        plugin>
    plugins>
  build>

generator.xml配置



    
     
      
     
    <generatorConfiguration>
   
    
        
    
         
      <classPathEntry location="D:\TSBrowserDownloads\maven\mavenSource\mysql\mysql-connector-java\8.0.13\mysql-connector-java-8.0.13.jar" />
    <context id="DB2Tables" targetRuntime="MyBatis3">
      <commentGenerator>
        <property name="suppressAllComments" value="true"/>  
        <property name="suppressDate" value="true" /> 
      commentGenerator>
      <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
            connectionURL="jdbc:mysql://localhost:3306/zhaowd?serverTimezone=GMT"
            userId="root" password="12345">
        jdbcConnection>
        
      <javaTypeResolver>
       
         <property name="forceBigDecimals" value="false"/>
      javaTypeResolver>
        
      <javaModelGenerator targetPackage="zhaowd.source" targetProject="src/main/java">
      
          <property name="enableSubPackages" value="true"/>
             
          <property name="trimStrings" value="true"/>
      javaModelGenerator>
       
      <sqlMapGenerator targetPackage="sqlmap" targetProject="src/main/resources">
           <property name="enableSubPackages" value="true"/>
      sqlMapGenerator>
       
      <javaClientGenerator type="XMLMAPPER" targetPackage="zhaowd.mapper" targetProject="src/main/java">
        <property name="enableSubPackages" value="true"/>
      javaClientGenerator>
      
         
      <table schema="zhaowd" tableName="user_info" domainObjectName="UserInfo" enableCountByExample="false" enableSelectByExample="true" enableUpdateByExample="false" enableDeleteByExample="false">
       
      table>
    context>
      
    generatorConfiguration>

使用方法:右键项目–>run as–>maven Build
自动生成mybatis需要的内容,mapper接口,mapper.xml,表实体
默认直接覆盖原有的,所以尽量不要在生成的文件中编写自己的代码,使用单独的文件,防止覆盖

  1. 分页
    mybatis自带方法里的分页参数是对结果集进行分页的,就是假分页
    方法1:就是使用sql语句的拼装去分页,直接使用数据库的sql
    方法2:使用分页插件,比如pagehelper
    • pom配置见上面mybatis的配置
    • 使用说明:再查询之前增加PageHelper.startPage(当前页,限制数量);即可
    • 注意事项见图片代码注释
      mybatis3.4.6 源码分析笔记_第3张图片

使用过程中的异常

  1. Caused by: java.lang.IllegalStateException: Cannot enable lazy loading because Javassist is not available. Add Javassist to your classpath.
Caused by: java.lang.IllegalStateException: Cannot enable lazy loading because Javassist is not available. Add Javassist to your classpath.
	at org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory.<init>(JavassistProxyFactory.java:55)
	at org.apache.ibatis.session.Configuration.<init>(Configuration.java:131)
	at org.apache.ibatis.builder.xml.XMLConfigBuilder.<init>(XMLConfigBuilder.java:86)
	at org.apache.ibatis.builder.xml.XMLConfigBuilder.<init>(XMLConfigBuilder.java:82)
	at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:77)
	... 25 more
Caused by: java.lang.ClassNotFoundException: Cannot find class: javassist.util.proxy.ProxyFactory

缺少jar依赖

        <dependency>
		    <groupId>org.javassistgroupId>
		    <artifactId>javassistartifactId>
		    <version>3.21.0-GAversion>
		dependency>
  1. Caused by: java.lang.RuntimeException: MemberAccess implementation must be provided!
    ognl版本不对,可能太高了
修改成:
		<dependency>
		    <groupId>ognlgroupId>
		    <artifactId>ognlartifactId>
		    <version>2.7.3version>
		dependency>

源码分析

程序调用链条如下图所示:

1.流程调用图(简化版)
mybatis3.4.6 源码分析笔记_第4张图片

2.复杂点的(这有点乱,结合简化版的看)
mybatis3.4.6 源码分析笔记_第5张图片

  1. 目录结构说明
    annotations:注解定义
    binding:绑定mapper接口与mapper.xml的关系
    builder:注解+配置解析
    cache:缓存
    cursor:
    datasource:数据源
    exceptions:异常
    executor:sql的实际执行者
    io:读文件
    jdbc:底层相关
    lang:
    logging:日志
    mappering:映射到实体
    parsing:解析配置+注解
    plugin:插件,拦截器
    reflection:反射
    scripting:参数处理
    session:session
    transaction:
    type:类型

源码

源码的调用流程见上图

学习:

  1. Configuration
    目前mybatis支持两种方式的实现功能
    • 编程式:只是单纯的使用mybaits去作为持久化层去使用,mybatis提供xml的形式去简化配置
    • 集成式:比如集成在spring中使用,可以使用Configuration去设置配置参数
      编程式在使用过程中,也会将xml映射到Configuration上
      Configuration与SqlSessionFactory一一对应
  2. 缓存
    1. 一级缓存:默认开启,session级别的,第一查询进行缓存,第二次查询从缓存里取

      • 如果同一个sesssion,在两次查询之间有更新数据的操作(update,delete)并提交,session的所有缓存都会清
      • 如果有不同的session,在两次查询之间有更新数据的操作(update,delete),第二次查询的数据就是脏数据了,session之间缓存都是独立的
        一级缓存是在取二级缓存之后(如果二级开关开启的话)
        mybatis3.4.6 源码分析笔记_第6张图片

      设置一级缓存的时候会使用一个占位符去占位,作用:比如在联合查询中,第二个sql在执行时,可能会命中第二个sql在单独执行时的一级缓存,如果获取到缓存的值是这个占位符,表示这个缓存不能使用;应该就是这个联合查询的第二个sql不加载到缓存里,由正在处理的加

      mybatis3.4.6 源码分析笔记_第7张图片

    2. 二级缓存:默认关闭,一般使用第三方实现(redies),nameSpace级别的,共享给所有的sqlSession

      • 同一个namespace下的upd,del会清掉该space下的缓存同一个namespace下的upd,del会清掉该space下的缓存
      • 如果是关联查询,缓存也只是当前namespace下的;如果另外一个namespace对数据有更新,不会影响其他namespace下的缓存,哪怕是关联查询的第二条sql
        mybatis3.4.6 源码分析笔记_第8张图片

mybatis3.4.6 源码分析笔记_第9张图片

  1. plugin机制 拦截

    • InterceptorChain.pluginAll方法,拦截器的开始;拦截的内容就是下图中的类,所有类的创建都会调用这个方法
      mybatis3.4.6 源码分析笔记_第10张图片
    • 拦截器的过程
    • 如果有多个plugin,pluginAll里会循环的去做代理;即已经被代理的实例,可以再被代理;代理先走最外层的
      mybatis3.4.6 源码分析笔记_第11张图片

    重复代理示例:

    1. 初始状态
      在这里插入图片描述
    2. 第一次被代理
      mybatis3.4.6 源码分析笔记_第12张图片
    3. 第二次被代理
      mybatis3.4.6 源码分析笔记_第13张图片

重复代理的重点:
这两个是不能一样的,否则会陷入死循环的代理中
在这里插入图片描述

  1. ObjectFactory 创建结果对象的实例
    • 拿到结果集,创建结果映射对象,就是实体对象(通过反射调用无参构造,如有自定义objectFactory,调用create创建)之后;这个时候还没有映射
    • 入参设置同理
  2. laze Loading机制
    *
    mybatis3.4.6 源码分析笔记_第14张图片
    • 如果lazyLoading开启,默认是javassist,可选cglib/自定义;会通过config去创建一个proxyFactory(java、cglib)的代理的代理对象
      位置:org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(ResultSetWrapper, ResultMap, ResultLoaderMap, String)
    • 在使用这个对象做get的时候,会调用invoke、intercept方法懒加载查询内容
      mybatis3.4.6 源码分析笔记_第15张图片
      扩展反射知识:https://blog.csdn.net/u013523089/article/details/83959984
  3. 异常机制
    使用一个ThreadLocal LOCAL去存每个线程的异常信息,如果有异常输出,这个会打印出每个设置的调用步骤的信息
    mybatis3.4.6 源码分析笔记_第16张图片
  4. log日志:以log4j2为例
  5. 连接池:自己做连接池的时候可以有个参考
    PooledConnection还对连接做了代理,每次操作连接的时候都会校验,如果连接已经断开了,会将连接状态validFlag=fase标记等操作,这个状态的连接会在获取连接的时候处理;返回null
    mybatis3.4.6 源码分析笔记_第17张图片
  6. 事务
    sqlsession–>executor–>transaction{jdbc(使用jdbc的事务,connection),manager(不处理事务,用于集成,由spring管理),自定义}

问题:

  1. 这个连接超时的含义是什么? sql执行时间过长的限制? 连接超时被断开?
    后者的可能性好像大些

你可能感兴趣的:(mybatis,源码分析)