转载

mybatis原理,配置介绍及源码分析

  • jdbc是sun公司提出的一系列对数据库操作的规范
  • java程序对数据库的连接都通过jdbc规范进行,它统一了接口,使用者在使用时无需关心各个数据库厂商底层的差异
  • 不同数据库底层具体实现由数据库厂商实现,也就是数据库驱动程序

2. 使用jdbc进行开发的流程

  • 加载驱动,Driver接口
  • 建立连接,Connection接口
  • 创建执行SQL的Statement
  • 通过Statement执行SQL,执行结果返回到ResultSet并处理
  • 释放资源

3. 总结与反思

  • jdbc编程工作量大,需要处理连接,事务,数据类型,各种Connection,Statement,ResultSet,关闭连接等等
  • 实际开发中不会直接使用jdbc编程,而是使用对象关系模型(ORM)框架。

二. mybatis介绍

1. 概述

mybatis是一款优秀的持久层框架,支持定制SQL语句,避免了几乎所有JDBC代码和手动设置参数,结果集获取

2. 如何使用

  • pom文件中添加mybatis的依赖
  • 读取配置文件,将配置信息传给SqlSessionFactoryBuilder的build方法,构造出SqlSessionFactory
  • 用SqlSessionFactory取得SqlSession
  • 调用SqlSession的getMapper得到mapper接口
  • 调用mapper接口中的增删该查方法操作数据库

3. 核心组件和API

  • SqlSession:mybatis最核心的组件,可以发送sql去执行并返回结果,也可以获取Mapper接口。类似于jdbc的Connection对象
  • SqlSessionFactory:创建SqlSession的工厂类,包含所有创建SqlSession实例的方法
  • SqlSessionFactoryBuilder: 根据配置信息Configuration或代码构建SqlSessionFactory对象
  • SQL Mapper:由Java接口和xml文件构成,并给出对应的sql和映射规则,负责发送sql执行并返回

SqlSessionFactoryBuilder

  • 一旦创建了SqlSessionFactory之后,就不再需要它了,最佳作用域是局部变量
  • 包含的函数如下图所示,允许通过不同的方法创建SqlSessionFactory
  • configuration 类包含你可能需要了解 SqlSessionFactory 实例的所有内容
SqlSessionFactory build(InputStream inputStream)
SqlSessionFactory build(InputStream inputStream, String environment)
SqlSessionFactory build(InputStream inputStream, Properties properties)
SqlSessionFactory build(InputStream inputStream, String env, Properties props)
SqlSessionFactory build(Configuration config)
复制代码

SqlSessionFactory

  • 每个Mybatis应用都是以SqlSessionFactory实例为中心的,它的任务是创建SqlSession
  • 每个数据库对应一个,在MyBatis应用的整个生命周期中,设计为单例或静态单例模式最佳
  • 构建方法:xml配置方式和代码方式
  • 包含的函数如下图所示
//默认获取的方式,不自动提交(开启事务)
SqlSession openSession()
//是否自动提交
SqlSession openSession(boolean autoCommit)
SqlSession openSession(Connection connection)
//事务的隔离级别:None,RU,RC,RR,Serial
SqlSession openSession(TransactionIsolationLevel level)
//查询类型:simple,batch,reuse
SqlSession openSession(ExecutorType execType,TransactionIsolationLevel level)
SqlSession openSession(ExecutorType execType)
SqlSession openSession(ExecutorType execType, boolean autoCommit)
SqlSession openSession(ExecutorType execType, Connection connection)
//获取mybatis配置信息
Configuration getConfiguration();
复制代码

SqlSession

  • 每个线程都应该有他自己的SqlSession实例
  • 是一个接口类,扮演门面的作用,真正干活的是Executor接口
  • 生命周期在请求数据库处理事务的过程中,不是线程安全的对象,不能作为类的静态变量。多线程要小心
  • 每次使用时打开一个SqlSession,操作完就关闭它
//带参数的增删改查方法
<T> T selectOne(String statement, Object parameter)
<E> List<E> selectList(String statement, Object parameter)
<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey)
int insert(String statement, Object parameter)
int update(String statement, Object parameter)
int delete(String statement, Object parameter)

//不带参数的增删改查方法
<T> T selectOne(String statement)
<E> List<E> selectList(String statement)
<K,V> Map<K,V> selectMap(String statement, String mapKey)
int insert(String statement)
int update(String statement)
int delete(String statement)

//高级版本的增删该查方法,支持自定义返回行数和结果控制
<E> List<E> selectList (String statement, Object parameter, RowBounds rowBounds)
<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowbounds)
void select (String statement, Object parameter, ResultHandler<T> handler)
void select (String statement, Object parameter, RowBounds rowBounds, ResultHandler<T> handler)

//事务控制相关方法
void commit()
void commit(boolean force)
void rollback()
void rollback(boolean force)

//清除缓存。mybatis提供了本地缓存和二级缓存
void clearCache()

//关闭session
void close()

//获得configuration实例
Configuration getConfiguration()

//获得映射器
<T> T getMapper(Class<T> type)
复制代码

mapper

  • 用来绑定映射SQL语句的接口
  • 由java接口和xml组成,提供的功能有
    • 定义参数类型
    • 描述缓存
    • 描述sql语句
    • 定义查询结果和POJO的映射关系
  • 生命周期小于SqlSession,如同jdb中一条sql的执行
  • 用过之后不需要显示关闭mapper

4. mybatis配置说明

4.1 主配置文件

所有支持的配置项介绍文档:mybatis配置文件说明,最外层标签为configuration,子标签有:

  • propertiess, 可以外部配置且动态替换

  • typeAliases,定义别名。用于减少冗长的类限定名,只和xml配置有关

    <typeAlias>
        <typeAlia alias="role" type="XXX"/>
        <package name="xxx"/>
    </typeAlias>
    复制代码
  • mappers,定义映射器,告诉mybatis去哪里找映射器

    <mappers>
        <mapper resource="xxx"/>
        <mapper url="file:://xxx"/>
        <mapper class="xxx"/>
        <!--包内的所有接口都注册为映射器-->
        <package name="xxx" />
    </mappers>
    复制代码
  • typeHandlers,用于将获取的值转化为合适的java类型

    <typeHandlers>
        <typeHandler handler="xxx">
    </typeHandlers>
    复制代码

    mybatis提供了很多默认的类型处理器,简单列举几个

    • BooleanTypeHandler:boolean-bool
    • StringTypeHandler:String-varchar,char
    • IntegerTypeHandler:Integer-int
    • DateTypeHandler:Date-timestamp
    • EnumTypeHandler:存储枚举类字符串
    • EnumOrdinalTypeHandler:存储枚举类下标

    如果标准处理器满足不了需求,可自定义处理器选择性映射到某个JDBC类型,具体步骤:

    • 实现org.apache.ibatis.type.TypeHandler接口
    • 指定该处理器要映射的jdbc类型:配置文件typeHandler中指定jdbc=“xxx”,或者处理类上使用@MappedJdbcTypes
    • 指定该处理器要映射的java类型:
  • environments,定义了如何配置数据库环境信息

    <environments>
        <environment>
            <transactionManager type="JDBC">
            </transactionManager>
            <dataSource type="POOLED">
                <property name="url" value="xxx">
                ...
            </dataSource>
        </environment>
    </environments>
    复制代码
  • settings,很重要的参数

    <settings>
      <!--全局开启映射器已经配置的任何缓存-->
      <setting name="cacheEnabled" value="true"/>
      <!--延迟加载的全局开关-->
      <setting name="lazyLoadingEnabled" value="true"/>
      <!--是否运行单一语句返回多条结果集-->
      <setting name="multipleResultSetsEnabled" value="true"/>
      <!--列标签代替列名-->
      <setting name="useColumnLabel" value="true"/>
      <!--运行jdbc支持自增长主键-->
      <setting name="useGeneratedKeys" value="false"/>
      <!--如何自动映射列到字段属性-->
      <setting name="autoMappingBehavior" value="PARTIAL"/>
      <!---->
      <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
      <!--默认的执行器-->
      <setting name="defaultExecutorType" value="SIMPLE"/>
      <!--超时时间-->
      <setting name="defaultStatementTimeout" value="25"/>
      <!--日志框架,可选值有:SLF4J,LOG4J,JDK_LOGGING,COMMONS_LOGGING,STDOUT_LOGGING,NO_LOGGING-->
      <setting name="logImpl" value="LOG4J"/>
      <!---->
      <setting name="defaultFetchSize" value="100"/>
      <!---->
      <setting name="safeRowBoundsEnabled" value="false"/>
      <!--是否开启自动驼峰命名规则:下划线列名转驼峰变量名-->
      <setting name="mapUnderscoreToCamelCase" value="false"/>
      <!---->
      <setting name="localCacheScope" value="SESSION"/>
      <!---->
      <setting name="jdbcTypeForNull" value="OTHER"/>
      <!---->
      <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
    </settings>
    复制代码
  • objectFactory:创建结果对象的工厂类,可自定义覆盖默认的

    <objectFactory type="XXX">
        <property name="xx", value="xx"/>
    </objectFactory>
    复制代码
  • plugins:插件运行定义拦截器,拦截mybatis执行过程中的某些调用

4.2 Mapper映射文件

映射文件定义了接口要执行的sql语句,所有支持的映射文件介绍文档:mybatis映射文件说明

  • select
    <select
        id="调用接口的函数名称,唯一标识"
        parameterType="参数类型,可省略,会根据typehandler自动推断"
        parameterMap="被废弃的选项"
        resultType="返回结果的类型,不能与resultMap同时存在"
        resultMap="返回结果的外部集合映射,不能与resultType同时存在。resultType为bean时,底层使用了resultMap"
        flushCache="设置为true表示任何时候调用都会清除本地和二级缓存,默认false"
        useCache="是否开启本地和二级缓存,默认为true"
        timeout="驱动等待数据库响应时间,默认为unset,依赖驱动"
        fetchSize="驱动每次批量返回结果数"
        statementType="默认preparedStatement"
        resultSetType="结果集类型,逗号分开">
        select id, name from table_name where id = #{id}
    </select>
    复制代码
  • insert/update/delete:很多属性同insert
    <insert 
        ...
        useGeneratedKeys="是否取出数据库自增长得到的id,默认false"
        keyProperty=“generatedKey的目标属性字段”
        keyColumn=“generatedKey的目标列名,主键列不是第一列需要设置”
        >
    </insert>
    复制代码
  • sql:定义可重用的sql语句
    <sql id="xxx">
    </sql>
    <!--调用的地方-->
    <include refid="xxx"/>
    复制代码
  • resultMap:mybatis只最重要最强大的元素
    <resultMap>
        <!--注入结果到构造方法中-->
        <constructor>
            <idArg column="" javatype="">
            <arg>
        </constructor>
        <!--复杂类型的关联-->
        <association>
        </association>
        <!--复杂类型的集合-->
        <collection>
        </collection>
    </resultMap>
    复制代码
  • cache:开启缓存,默认情况下是不开启缓存的,除了局部session
    <!--开启可读可写缓存,所有select都被缓存,insert,delete和update刷新缓存,-->
    <cache
        <!--回收策略:包括LRU(默认),FIFO,SOFT,WEAK-->
        eviction="LRU"
        <!--刷新时间,单位毫秒-->
        flushInternval="60000"
        readOnly="true"
        <!--缓存存储的引用数量,默认1024-->
        size="512"
    />
    <cache type="自定义缓存,必须实现org.mybatis.cache.Cache接口"/>
    复制代码
  • cache-ref:引用另外一个缓存

5. 动态SQL

动态SQL:用于根据条件包含where字句的一部分。动态SQL包括if,choose,trim,foreach

<select/insert id="xx">
        select id, name, status
        from table_name
        where status = #{status}
        <!--普通的条件判断语句-->
        <if test="name != null">
        and name like #{name}
        </if>
        <!--条件分支语句,类似与switch-->
        <choose>
            <when test="name != null">
            </when>
            <otherwise>
            </otherwise>
        </choose>
        <!--会自动去除条件不满足时多余的where,and,or等关键字-->
        <where>
        </where>
        <!--自定义去除某些符号的功能-->
        <trim prefix="WHERE" prefixOverrides="AND|OR">
        </trim>
        <set>
            <if>
        </set>
        <foreach item="" index="" collection="">
        </foreach>
    </select>
复制代码

三. Mybatis Spring

1. 概述

  • 无缝的将mybatis整合到spring中,使用这个类库,spring会加载必要到工厂类和session类
  • 允许mybatis参与到spring的事务管理中,利用了spring的DataSourceTransactionManger
  • 使用mybatis-spring,需要在上下文中定义sqlSessionFactory和至少一个数据映射器类

2. 如何使用

  • pom中添加mybatis-spring依赖
  • spring的xml文件中传入数据源,并配置sqlSessionFactory
  • spring的xml文件中配置mapper映射接口
  • 业务代码中获取自动注入到容器的映射接口,并调用增删改查方法操作数据库

3. SqlSessionFactoryBean

  • 前面介绍原生Mybatis中,通过SqlSessionFactoryBuilder创建SqlSessionFactory。而mybati-spring中由SqlSessionFactoryBean创建
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
      <!--必须的属性,配置数据源-->
      <property name="dataSource" ref="dataSource" />
      <!--可选属性,配置映射文件路径-->
       <property name="mapperLocations" value="classpath*:sample/config/mappers/**/*.xml" />
    </bean>
    复制代码
  • SqlSessionFactoryBean实现了spring的FactoryBean接口
  • 它必须注入dataSource属性

4. 配置事务

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!--数据源必须和SqlSessionFactoryBean配置的数据源一致-->
  <property name="dataSource" ref="dataSource" />
</bean>
复制代码

5. 使用SqlSession

  • 原生mybatis中,通过SqlSessionFactory获取SqlSession,在mybatis-spring中,不再需要直接使用SqlSessionFactory,因为SqlSession已经以线程安全的Bean的方式自动注入了
  • SqlSessionTemplate是mybatis-spring的核心,实现了SqlSession接口,负责管理SqlSession。它是线程安全的,可以被多个Dao调用。还负责SqlSession的的生命周期,包括关闭,提交和回滚操作
  • SqlSessionTemplate被设计用于替换默认的DefaultSqlSession

6. 注入映射器

  • 为了代替手工调用SqlSessionTemplate编写DAO层业务代码,mybatis-spring提供了动态代理的实现类:MapperFactoryBean,该类是设计成泛型,将mapper接口类自动注入到service类中,无需自己写实现类,内部会自动创建代理
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
复制代码
  • MapperFactoryBean创建的代理类实现了UserMapper接口,并注入到应用程序中
  • 为了代替手工注册每个映射器,可以使用MapperScannerConfigurer,它会创建路径下所有映射器,被自动创建MapperFactoryBean
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="org.mybatis.spring.sample.mapper" />
</bean>
复制代码

四. Mybatis Springboot Starter

1. 概述

  • 基于springboot快速构建mybatis应用程序
  • 使用mybatis-spring,我们需要在xml中配置SqlSessionFactory和mapper映射接口
  • 使用mybatis-springboot-starter,会自动检测dataSource,并根据数据源,使用SqlSessionFactoryBean自动创建并注册一个SqlSessionFactory,同时将创建SqlSessionTemplate,自动扫描mapper,关联到SqlSessionTemplate并注入到容器中
  • 默认扫描所有带@Mapper的接口,自定义扫描某些包,需要使用@MapperSacn注解

2. 如何使用

  • pom中添加mybatis-spring-boot-starter依赖
  • application.xml中添加数据源和mybatis相关配置信息
  • 映射接口上添加@Mapper注解,或使用@MapperScan扫描整个包的mapper
  • 业务代码中获取自动注入到容器的mapper接口,调用mapper的增删改查方法操作数据库

3. 配置文件

  • 配置信息放在application.properties或application.yml文件中,以mybatis作为配置的前缀。参数配置同前面介绍的原生mybatis配置
# application.properties
# 指定mybatis-config.xml文件的位置
mybatis.config-location=classpath:mybatis-config.xml
# 指定mapper的xml文件路径
mybatis.mapper-locations=classpath:com/xx
mybatis.executor-type=SIMPLE
# 指定别名的包,多个用逗号分开
mybatis.type-aliases-package=com.example.domain.model
mybatis.type-handlers-package=com.example.typehandler
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.default-fetch-size=100
mybatis.configuration.default-statement-timeout=30
复制代码

五. Mybatis源码分析

1. mybatis相关jar包说明

1.1 mybatis-spring-boot-starter.jar

mybatis原理,配置介绍及源码分析
  • 只有一个pom文件和spring.provides文件,官方提供的一些starter格式大致都是这个套路。真正处理自动配置功能的是XXX-autoconfigure.jar完成
  • pom中依赖项:jdbc, mybatis, mybatis-spring, mybatis-spring-boot-autoconfigure(真正完成自动配置的jar包)
  • provides:说明这个starter配置以后,自动引入的包有哪些

1.2 mybatis-spring-boot-autoconfigure.jar

mybatis原理,配置介绍及源码分析
  • xxx-autoconfigure是开发一个starter默认使用的自动配置包
  • META-INF/spring.factories: 指定了自动配置的类名是MybatisAutoConfiguration
  • MybatisProperties: 指明了application.properties文件中配置信息对应的属性类
  • MybatisAutoConfiguration:自动配置实现类,函数入口的地方。根据DataSource自动注入SqlSessionFactory,再根据SqlSessionFactory自动注入SqlSessionTemplate。SqlSessionTemplate内部的操作都是通过创建SqlSession的代理sqlSessionProxy来操作的

1.3 mybatis-spring.jar

mybatis原理,配置介绍及源码分析
  • mybatis和spring的集成包

1.4 mybatis.jar

mybatis原理,配置介绍及源码分析
  • 最原生的mybatis包

2. 配置文件加载

2.1 UML图

mybatis原理,配置介绍及源码分析
  • 访问数据库层,最基本的接口是SqlSession,它的默认实现为DefaultSqlSession, 在mybatis-spring中使用SqlSessionTemplate
  • SqlSession通过SqlSessionFactory工厂来创建,而sqlSessionFactory通过建造者SqlSessionFactoryBuilder创建
  • SqlSessionFactoryBuilder是通用的构造类类,通过它构造出SqlSessionFactory。可以手工直接调用SqlSessionFactoryBuilder。
  • mybatis为了和spring集成,提供了mybatis-spring这个jar包。提供的SqlSessionFactoryBean类,内部封装了对SqlSessionFactoryBuilder的调用
  • springboot进一步提供了MybatisAutoConfiguration做自动配置,内部的sqlSessionFactory方法,最终调用了SqlSessionFactoryBean
  • Configuration提供两类数据,一类是输入类:Environment,通过给定的配置文件,将配置信息

2.2 源码跟踪

  • MybatisAutoConfiguration类内部构造了SqlSessionFactoryBean对象

    mybatis原理,配置介绍及源码分析
  • SqlSessionFactoryBean实现了FactoryBean接口,所以getBean获取实例时实际调用他的getObject方法。内部调用了afterPropertiesSet方法。afterPropertiesSet方法被重写,内部调用buildSqlSessionFactory

    mybatis原理,配置介绍及源码分析
  • buildSqlSessionFactory内部创建了XMLConfigBuilder,用于解析mybatis的配置文件

    mybatis原理,配置介绍及源码分析
  • 真正解析配置文件的地方

    mybatis原理,配置介绍及源码分析
  • 解析的配置文件的根为configuration,然后依次解析子标签:包括最重要的mappers标签。这部分的解析和前面介绍的配置文件说明是一一对应的,所有标签都有对应的解析标签的代码

    mybatis原理,配置介绍及源码分析
  • 对mapper文件的解析,内部又具体调用了XMLMapperBuilder类的parse方法。这部分的解析与前面介绍的mapper配置文件说明也是一一对应的

    mybatis原理,配置介绍及源码分析
  • 解析mapper文件时,从根元素mapper开始,包括子节点cache,parameterMap,resultMap,select等。然后将解析的信息都保存到Configuration对象中。

    mybatis原理,配置介绍及源码分析
  • 其中select,insert,delete,update语句的解析方法为

    mybatis原理,配置介绍及源码分析
  • 解析完之后,放入一个map中,每条sql语句对应一个MappedStatement对象。其他属性的解析类似,大多是放到map中。

    mybatis原理,配置介绍及源码分析
    mybatis原理,配置介绍及源码分析
  • 解析完所有的配置文件,得到Configuration对象,将它作为参数传给SqlSessionFactoryBuilder的build方法

    mybatis原理,配置介绍及源码分析
  • SqlSessionFactoryBuilder内部根据Configuration参数,创建DefaultSqlSessionFactory类

    mybatis原理,配置介绍及源码分析
  • DefaultSqlSessionFactory构造函数只是将Configuration保存了下来,当需要获取session时,根据内部的configuration去具体创建

    mybatis原理,配置介绍及源码分析
  • 得到SqlSessionFactory后,根据它去创建SqlSessionTemplate

    mybatis原理,配置介绍及源码分析
  • SqlSessionTemplate内部创建SqlSession的代理类,将没有加事务的SqlSession的操作做强制提交

    mybatis原理,配置介绍及源码分析
    mybatis原理,配置介绍及源码分析

3. 动态代理的实现

3.1 概述

Dao层都是是一些接口 它并没有实现类,为什么接口可以直接使用呢? 那是因为MyBbatis使用了JDK动态代理机制动态生成了代理类,那么代理类又是如何对SqlSession进行封装的呢?

3.2 UML图

mybatis原理,配置介绍及源码分析

3.3 源码跟踪

注册mapper并创建代理类

  • MapperScanConfiguration这个bean,扫描给定包下所有的mapper文件,并注册到MapperRegistry中
    mybatis原理,配置介绍及源码分析
  • MapperRegistry中的addMappers方法将包名下每个mapper类创建一个MapperProxyFactory,放入map中。
    mybatis原理,配置介绍及源码分析
    mybatis原理,配置介绍及源码分析
  • 获取mapper时,从map中找到对应的MapperProxyFactory,并将sqlSession参数传给newInstance,创建出代理类
    mybatis原理,配置介绍及源码分析
  • 创建代理类调用了JDK的动态代理方法,被代理类为DAO接口,代理类为MapperProxy
    mybatis原理,配置介绍及源码分析
  • MapperProxy实现了InvocationHandler,重写invoke方法。该方法主要调用MapperMethod的execute方法
    mybatis原理,配置介绍及源码分析
  • MapperMethod的创建需要三个参数:DAO接口本身,方法类,Configuration对象
    mybatis原理,配置介绍及源码分析
  • MapperMethod内部新建了两个类:SqlCommand,MethodSignature
    mybatis原理,配置介绍及源码分析
  • SqlCommand主要保存了要查询的这个接口方法的方法名称和SQL查询类型,这两个值都需要先查询MappedStatemen
    mybatis原理,配置介绍及源码分析
  • MappedStatement查询就是在前面章节说道了解析文件完成后保存到的Configuration的map中查找
    mybatis原理,配置介绍及源码分析
  • MethodSignature主要保存参数,返回值,返回类型等信息,主要解析Method类
    mybatis原理,配置介绍及源码分析
  • MapperMethod执行execute时,就是根据前面创建的SqlCommand和MethodSignature的一些属性执行不同的操作,这些操作都调用了SqlSession接口。比如:xml中的select语句,SqlCommand中type指定为SELECT,execute根据不同type执行不同方法。xml中返回类型是单条记录,还是多条记录。分别对应MethodSignature的不同属性,然后执行不同的方法。
    mybatis原理,配置介绍及源码分析

获取mapper并执行

  • mapper的注册前面介绍了是通过MapperRegistry的addMappers方法,而获取mapper的方法是getMapper,那么谁来调用这个getMapper方法呢?
  • 当我们再service中使用@Autowired注解获取某个mapper接口时,实际上是调用了spring为我们自动注入的bean,这个操作是由MapperFactoryBean泛型类来完成。同SqlSessionFactoryBean一样,MapperFactoryBean实现了FactoryBean接口,所以getBean获取实例时实际调用他的getObject方法。getObejct内部通过sqlSession调用getMapper方法,避免了原生mybatis中每次手动通过sqlSession调用getMapper方法。
    mybatis原理,配置介绍及源码分析
  • session对象是MapperFactoryBean的父类SqlSessionDaoSupport的属性,内部具体实现类是SqlSessionTemplate
    mybatis原理,配置介绍及源码分析
  • SqlSessionTemplate的getMapper方法,实际调用的是Configuration的getMapper方法
    mybatis原理,配置介绍及源码分析
  • Configuration中的getMapper方法调用的就是前面一小节介绍的MapperRegistry类中注册进去所有进行了动态代理后,放入一个map的对象
    mybatis原理,配置介绍及源码分析

六. Mybatis Generator

1. 概述

  • mybatis generator是一个mybatis代码自动生成工具。官方文档, 中文文档
  • 生成的内容包括:
    • 实体对象:指定数据库中指定表对应的java实体类
    • mapper xml文件:每张表对应的增删改查SQL语句
    • DAO接口:和SQL语句对应的java查询接口
  • 多次生成时注意的事项:
    • xml文件会自动合并,不会覆盖已有的内容
    • java文件不会合并,它默认会生成一个不同名字的文件。可通过参数配置覆盖原有的文件

2. 如何使用

2.1 命令行运行使用

  • 定义配置文件
  • 运行以下命令
java -jar mybatis-generator-core-x.x.x.jar -configfile /temp/generatorConfig.xml -overwrite
复制代码

2.2 spring或springboot中使用

  • pom中添加依赖
    <build>
        <plugins>
            <plugin>
              <groupId>org.mybatis.generator</groupId>
              <artifactId>mybatis-generator-maven-plugin</artifactId>
              <version>${mybatis-generator.version}</version>
              <configuration>
                <overwrite>true</overwrite>
                <verbose>true</verbose>
              </configuration>
              <dependencies>
                <dependency>
                  <groupId>mysql</groupId>
                  <artifactId>mysql-connector-java</artifactId>
                  <version>${mysql.version}</version>
                </dependency>
              </dependencies>
            </plugin>
        </plugins>
    </build>
    复制代码
  • 运行插件
    mybatis原理,配置介绍及源码分析

3. 配置文件说明

<?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>
      <!--非必填选项,用于添加运行类路径位置到类路径中-->
      <classPathEntry location="/Program Files/IBM/SQLLIB/java/db2java.zip" />
     
      <!--元素用于指定生成一组对象的环境-->
      <context id="DB2Tables" targetRuntime="MyBatis3">
        <!--注释生成器的属性-->
        <commentGenerator>
            <property name="suppressDate" value="true" />
            <!-- 是否去除自动生成的注释 true:是 : false:否 -->
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>
       <!--指定数据库连接信息-->
        <jdbcConnection driverClass="COM.ibm.db2.jdbc.app.DB2Driver"
            connectionURL="jdbc:db2:TEST"
            userId="db2admin"
            password="db2admin">
        </jdbcConnection>
        
        <!--用于定义Java类型解析器的属性-->
        <javaTypeResolver >
          <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!-- 生成实体类的包名和位置-->
        <javaModelGenerator targetPackage="test.model" targetProject="/MBGTestProject/src">
          <property name="enableSubPackages" value="true" />
          <property name="trimStrings" value="true" />
        </javaModelGenerator>
    
        <!-- 生成mapper xml文件的包名和位置-->
        <sqlMapGenerator targetPackage="test.xml"  targetProject="/MBGTestProject/src">
          <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
    
        <!-- 生成DAO的包名和位置-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="test.dao" targetPackage="xx"  targetProject="/MBGTestProject/src">
          <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        
        <!--指定生成哪个表的信息-->
        <table schema="DB2ADMIN" tableName="ALLTYPES" domainObjectName="Customer" >
          <property name="useActualColumnNames" value="true"/>
          <!--指定自动生成的主键-->
          <generatedKey column="ID" sqlStatement="DB2" identity="true" />
          <columnOverride column="DATE_FIELD" property="startDate" />
          <ignoreColumn column="FRED" />
          <!--自定义列信息,覆盖默认信息,包括property,javaType,jdbcType,typeHandler,delimitedColumnName属性-->
          <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" />
        </table>
      </context>
    </generatorConfiguration>
复制代码

七. PageHelper

1. 概述

  • mybatis的分页插件,说明文档,或者github地址 github地址 , 与springboot的集成 springboot-pagehelper

2. 如何使用

  • 添加springboot依赖
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper-spring-boot-starter</artifactId>
        <version>${pageHelper.version}</version>
    </dependency>
    复制代码
  • 在application.properties中添加配置说明
    # 分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置helperDialect属性来指定分页插件使用哪种方言
    pagehelper.helperDialect=mysql
    # 分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页,
    # pageNum>pages(超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。
    pagehelper.reasonable=true
    # 默认值为false,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为true时,使用 RowBounds 分页会进行 count 查询。
    pagehelper.row-bounds-with-count=false
    # 为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值
    # 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值
    # 默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero
    pagehelper.params=
    # 支持通过 Mapper 接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,
    # 自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页
    pagehelper.supportMethodsArguments=false
    # 默认值为 false,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0 
    # 就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是 Page 类型)
    pagehelper.pageSizeZero=false
    # autoRuntimeDialect:默认值为 false。设置为 true 时,允许在运行时根据多数据源自动识别对应方言的分页 
    # pring 中配置了动态数据源,并且连接不同类型的数据库,这时你可以配置为true
    pagehelper.autoRuntimeDialect: false
    # 默认值为 true。当使用运行时动态数据源或没有设置 helperDialect 属性自动获取数据库类型时,会自动获取一个数据库连接,
    # 通过该属性来设置是否关闭获取的这个连接,默认true关闭,设置为 false 后,不会关闭获取的连接
    # 这个参数的设置要根据自己选择的数据源来决定
    pagehelper.close-conn=false
    复制代码
  • 在代码中调用
    //方法一:Mapper接口方式的调用,startPage,推荐这种使用方式。
    PageHelper.startPage(1, 10);
    List<Country> list = countryMapper.selectIf(1);
    
    //方法二:Mapper接口方式的调用,offsetPage, 推荐这种使用方式。
    PageHelper.offsetPage(1, 10);
    List<Country> list = countryMapper.selectIf(1);
    
    //方法三:参数方法调用
    //存在以下 Mapper 接口方法,你不需要在 xml 处理后两个参数
    public interface CountryMapper {
    List<Country> selectByPageNumSize(
            @Param("user") User user,
            @Param("pageNum") int pageNum,
            @Param("pageSize") int pageSize);
    }
    //配置supportMethodsArguments=true
    //在代码中直接调用:
    List<Country> list = countryMapper.selectByPageNumSize(user, 1, 10);
    
    //方法四:java8 lambda调用
    //jdk8 lambda用法
    Page<Country> page = PageHelper.startPage(1, 10).doSelectPage(()-> countryMapper.selectGroupBy());
    pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(() -> countryMapper.selectGroupBy());
    //count查询,返回一个查询语句的count数
    total = PageHelper.count(()->countryMapper.selectLike(country));
    复制代码

3. 使用注意

  • PageHelper.startPage使用静态的ThreadLocal的,分页和线程绑定,使用startPage时,后面必须紧跟着dao查询,分页才能生效
原文  https://juejin.im/post/5bd02b3d6fb9a05cee1e2478
正文到此结束
Loading...