mybatis3.4.6 源码分析笔记

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

资源:https://download.csdn.net/download/u013523089/10781601

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

网配置教程:
http://www.mybatis.org/mybatis-3/
源码下载:
在这里插入图片描述

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

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

常用使用说明

  1. 使用mybatis集成pom配置
    使用我的练习项目;第一次自己搭maven
    在这里插入图片描述
    可以在一个maven工程里放子工程,这个方式还挺好的;两个子项目可以共用父项目的pom配置


	<dependencies>
		<!-- mysql -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.13</version>
		</dependency>
		
		<!-- mybatis -->
		<dependency>
		  <groupId>org.mybatis</groupId>
		  <artifactId>mybatis</artifactId>
		  <version>3.4.6</version>
		</dependency>
		
		<!-- log4j -->
		<dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        
        <!-- mybatis会用到 start -->
        <dependency>
		    <groupId>org.javassist</groupId>
		    <artifactId>javassist</artifactId>
		    <version>3.21.0-GA</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/ognl/ognl -->
		<dependency>
		    <groupId>ognl</groupId>
		    <artifactId>ognl</artifactId>
		    <version>2.7.3</version>
		</dependency>
		<!-- mybatis会用到 end -->
		
		<!-- mybatis 分页插件 -->
		<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
		<dependency>
		    <groupId>com.github.pagehelper</groupId>
		    <artifactId>pagehelper</artifactId>
		    <version>5.1.7</version>
		</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.generator</groupId>
            <artifactId>mybatis-generator-maven-plugin</artifactId>
            <version>1.3.7</version>
             <configuration>
             	<!--允许移动生成的文件-->
                <verbose>true</verbose>
                <!--允许覆盖生成的文件-->
                <overwrite>true</overwrite>
                <configurationFile>src/main/resources/config/generatorConfig.xml</configurationFile>
            </configuration>
        </plugin>
    </plugins>
  </build>

generator.xml配置

<?xml version="1.0" encoding="UTF-8" ?>

    <!DOCTYPE generatorConfiguration 
      PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
      "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
     
      <!-- 注意这个插件是增量向文件中添加,会重复 -->
     
    <generatorConfiguration>
   
    
        <!-- 引入配置文件   
    <properties resource="jdbc.properties"/>  -->
    
         <!--数据库驱动路径-->
      <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>
      <!-- 是否使用bigDecimal, false可自动转化以下类型(Long, Integer, Short, etc.) --> 
         <property name="forceBigDecimals" value="false"/>
      </javaTypeResolver>
      <!-- 生成实体类的包名和位置 注意targetProject的值为实体类放在工程中具体位置的相对路径,-->  
      <javaModelGenerator targetPackage="zhaowd.source" targetProject="src/main/java">
      <!-- 是否在当前路径下新加一层schema,eg:fase路径com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] -->
          <property name="enableSubPackages" value="true"/>
           <!-- 是否针对string类型的字段在set的时候进行trim调用 -->  
          <property name="trimStrings" value="true"/>
      </javaModelGenerator>
       <!--XML映射文件,生成的位置(目标包),源代码文件夹-->
      <sqlMapGenerator targetPackage="sqlmap" targetProject="src/main/resources">
           <property name="enableSubPackages" value="true"/>
      </sqlMapGenerator>
       <!--XML对应的Mapper类-->
      <javaClientGenerator type="XMLMAPPER" targetPackage="zhaowd.mapper" targetProject="src/main/java">
        <property name="enableSubPackages" value="true"/>
      </javaClientGenerator>
      
         <!--下面是数据库表名和项目中需要生成类的名称,建议和数据库保持一致,如果有多个表,添加多个节点即可   enable*ByExample   
                是否生成 example类-->
      <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(当前页,限制数量);即可
    • 注意事项见图片代码注释
      在这里插入图片描述

使用过程中的异常

  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.javassist</groupId>
		    <artifactId>javassist</artifactId>
		    <version>3.21.0-GA</version>
		</dependency>
  1. Caused by: java.lang.RuntimeException: MemberAccess implementation must be provided!
    ognl版本不对,可能太高了
修改成:
		<dependency>
		    <groupId>ognl</groupId>
		    <artifactId>ognl</artifactId>
		    <version>2.7.3</version>
		</dependency>

源码分析

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

1.流程调用图(简化版)
在这里插入图片描述

2.复杂点的(这有点乱,结合简化版的看)
在这里插入图片描述

  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之间缓存都是独立的
        一级缓存是在取二级缓存之后(如果二级开关开启的话)
        在这里插入图片描述

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

      在这里插入图片描述

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

      • 同一个namespace下的upd,del会清掉该space下的缓存同一个namespace下的upd,del会清掉该space下的缓存
      • 如果是关联查询,缓存也只是当前namespace下的;如果另外一个namespace对数据有更新,不会影响其他namespace下的缓存,哪怕是关联查询的第二条sql
        在这里插入图片描述

在这里插入图片描述

  1. plugin机制 拦截

    • InterceptorChain.pluginAll方法,拦截器的开始;拦截的内容就是下图中的类,所有类的创建都会调用这个方法
      在这里插入图片描述
    • 拦截器的过程
    • 如果有多个plugin,pluginAll里会循环的去做代理;即已经被代理的实例,可以再被代理;代理先走最外层的
      在这里插入图片描述

    重复代理示例:

    1. 初始状态
      在这里插入图片描述
    2. 第一次被代理
      在这里插入图片描述
    3. 第二次被代理
      在这里插入图片描述
  2. ObjectFactory 创建结果对象的实例

    • 拿到结果集,创建结果映射对象,就是实体对象(通过反射调用无参构造,如有自定义objectFactory,调用create创建)之后;这个时候还没有映射
    • 入参设置同理
  3. laze Loading机制
    *
    在这里插入图片描述

    • 如果lazyLoading开启,默认是javassist,可选cglib/自定义;会通过config去创建一个proxyFactory(java、cglib)的代理的代理对象
      位置:org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(ResultSetWrapper, ResultMap, ResultLoaderMap, String)
    • 在使用这个对象做get的时候,会调用invoke、intercept方法懒加载查询内容
      在这里插入图片描述
      扩展反射知识:https://blog.csdn.net/u013523089/article/details/83959984
  4. 异常机制
    使用一个ThreadLocal LOCAL去存每个线程的异常信息,如果有异常输出,这个会打印出每个设置的调用步骤的信息
    在这里插入图片描述

  5. log日志:以log4j2为例

  6. 连接池:自己做连接池的时候可以有个参考
    在这里插入图片描述

  7. 事务
    sqlsession–>executor–>transaction{jdbc(使用jdbc的事务,connection),manager(不处理事务,用于集成,由spring管理),自定义}

问题:

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

猜你喜欢

转载自blog.csdn.net/u013523089/article/details/83828154