博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
mybatis原理,配置介绍及源码分析
阅读量:5878 次
发布时间:2019-06-19

本文共 16518 字,大约阅读时间需要 55 分钟。

前言

mybatis核心组件有哪些?它是工作原理是什么?

mybatis配置文件各个参数是什么含义?

mybatis只添加了接口类,没有实现类,为什么可以直接查询呢?

mybatis的mapper映射文件各个参数又是什么含义?

mybatis-spring提供哪些机制简化了原生mybatis?

mybatis-springboot-starter又是如何简化进一步让mybatis使用如此方便?代码调用流程是怎么样的?

目录

jdbc介绍

mybatis介绍

mybatis-spring

mybatis-spring-boot-starter

mybatis源码分析

mybatis代码生成工具mybatis-generator

mybatis分页插件pagehelper

一. jdbc介绍

1. 概述

  • 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,SerialSqlSession openSession(TransactionIsolationLevel level)//查询类型:simple,batch,reuseSqlSession 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 selectOne(String statement, Object parameter)
List
selectList(String statement, Object parameter)
Map
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 selectOne(String statement)
List
selectList(String statement)
Map
selectMap(String statement, String mapKey)int insert(String statement)int update(String statement)int delete(String statement)//高级版本的增删该查方法,支持自定义返回行数和结果控制
List
selectList (String statement, Object parameter, RowBounds rowBounds)
Map
selectMap(String statement, Object parameter, String mapKey, RowBounds rowbounds)void select (String statement, Object parameter, ResultHandler
handler)void select (String statement, Object parameter, RowBounds rowBounds, ResultHandler
handler)//事务控制相关方法void commit()void commit(boolean force)void rollback()void rollback(boolean force)//清除缓存。mybatis提供了本地缓存和二级缓存void clearCache()//关闭sessionvoid close()//获得configuration实例Configuration getConfiguration()//获得映射器
T getMapper(Class
type)复制代码

mapper

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

4. mybatis配置说明

4.1 主配置文件

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

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

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

    复制代码
  • mappers,定义映射器,告诉mybatis去哪里找映射器

    复制代码
  • typeHandlers,用于将获取的值转化为合适的java类型

    复制代码

    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,定义了如何配置数据库环境信息

    ...
    复制代码
  • settings,很重要的参数

    复制代码
  • objectFactory:创建结果对象的工厂类,可自定义覆盖默认的

    复制代码
  • plugins:插件运行定义拦截器,拦截mybatis执行过程中的某些调用

4.2 Mapper映射文件

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

  • select
    复制代码
  • insert/update/delete:很多属性同insert
    复制代码
  • sql:定义可重用的sql语句
    复制代码
  • resultMap:mybatis只最重要最强大的元素
    复制代码
  • cache:开启缓存,默认情况下是不开启缓存的,除了局部session
    eviction="LRU"
    flushInternval="60000" readOnly="true"
    size="512"/>
    复制代码
  • cache-ref:引用另外一个缓存

5. 动态SQL

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

复制代码

三. 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创建
    复制代码
  • SqlSessionFactoryBean实现了spring的FactoryBean接口
  • 它必须注入dataSource属性

4. 配置事务

复制代码

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类中,无需自己写实现类,内部会自动创建代理
复制代码
  • MapperFactoryBean创建的代理类实现了UserMapper接口,并注入到应用程序中
  • 为了代替手工注册每个映射器,可以使用MapperScannerConfigurer,它会创建路径下所有映射器,被自动创建MapperFactoryBean
复制代码

四. 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/xxmybatis.executor-type=SIMPLE# 指定别名的包,多个用逗号分开mybatis.type-aliases-package=com.example.domain.modelmybatis.type-handlers-package=com.example.typehandlermybatis.configuration.map-underscore-to-camel-case=truemybatis.configuration.default-fetch-size=100mybatis.configuration.default-statement-timeout=30复制代码

五. Mybatis源码分析

1. mybatis相关jar包说明

1.1 mybatis-spring-boot-starter.jar

  • 只有一个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

  • 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和spring的集成包

1.4 mybatis.jar

  • 最原生的mybatis包

2. 配置文件加载

2.1 UML图

  • 访问数据库层,最基本的接口是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对象

  • SqlSessionFactoryBean实现了FactoryBean接口,所以getBean获取实例时实际调用他的getObject方法。内部调用了afterPropertiesSet方法。afterPropertiesSet方法被重写,内部调用buildSqlSessionFactory

  • buildSqlSessionFactory内部创建了XMLConfigBuilder,用于解析mybatis的配置文件

  • 真正解析配置文件的地方

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

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

  • 解析mapper文件时,从根元素mapper开始,包括子节点cache,parameterMap,resultMap,select等。然后将解析的信息都保存到Configuration对象中。

  • 其中select,insert,delete,update语句的解析方法为

  • 解析完之后,放入一个map中,每条sql语句对应一个MappedStatement对象。其他属性的解析类似,大多是放到map中。

  • 解析完所有的配置文件,得到Configuration对象,将它作为参数传给SqlSessionFactoryBuilder的build方法

  • SqlSessionFactoryBuilder内部根据Configuration参数,创建DefaultSqlSessionFactory类

  • DefaultSqlSessionFactory构造函数只是将Configuration保存了下来,当需要获取session时,根据内部的configuration去具体创建

  • 得到SqlSessionFactory后,根据它去创建SqlSessionTemplate

  • SqlSessionTemplate内部创建SqlSession的代理类,将没有加事务的SqlSession的操作做强制提交

3. 动态代理的实现

3.1 概述

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

3.2 UML图

3.3 源码跟踪

注册mapper并创建代理类

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

获取mapper并执行

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

六. 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中添加依赖
    org.mybatis.generator
    mybatis-generator-maven-plugin
    ${mybatis-generator.version}
    true
    true
    mysql
    mysql-connector-java
    ${mysql.version}
    复制代码
  • 运行插件

3. 配置文件说明

复制代码

七. PageHelper

1. 概述

  • mybatis的分页插件,,或者github地址, 与springboot的集成

2. 如何使用

  • 添加springboot依赖
    com.github.pagehelper
    pagehelper-spring-boot-starter
    ${pageHelper.version}
    复制代码
  • 在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=pageSizeZeropagehelper.params=# 支持通过 Mapper 接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,# 自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页pagehelper.supportMethodsArguments=false# 默认值为 false,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0 # 就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是 Page 类型)pagehelper.pageSizeZero=false# autoRuntimeDialect:默认值为 false。设置为 true 时,允许在运行时根据多数据源自动识别对应方言的分页 # pring 中配置了动态数据源,并且连接不同类型的数据库,这时你可以配置为truepagehelper.autoRuntimeDialect: false# 默认值为 true。当使用运行时动态数据源或没有设置 helperDialect 属性自动获取数据库类型时,会自动获取一个数据库连接,# 通过该属性来设置是否关闭获取的这个连接,默认true关闭,设置为 false 后,不会关闭获取的连接# 这个参数的设置要根据自己选择的数据源来决定pagehelper.close-conn=false复制代码
  • 在代码中调用
    //方法一:Mapper接口方式的调用,startPage,推荐这种使用方式。PageHelper.startPage(1, 10);List
    list = countryMapper.selectIf(1);//方法二:Mapper接口方式的调用,offsetPage, 推荐这种使用方式。PageHelper.offsetPage(1, 10);List
    list = countryMapper.selectIf(1);//方法三:参数方法调用//存在以下 Mapper 接口方法,你不需要在 xml 处理后两个参数public interface CountryMapper {List
    selectByPageNumSize( @Param("user") User user, @Param("pageNum") int pageNum, @Param("pageSize") int pageSize);}//配置supportMethodsArguments=true//在代码中直接调用:List
    list = countryMapper.selectByPageNumSize(user, 1, 10);//方法四:java8 lambda调用//jdk8 lambda用法Page
    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查询,分页才能生效

转载地址:http://bbcix.baihongyu.com/

你可能感兴趣的文章
电子政务方向:We7.Cloud政府云门户
查看>>
ansible 基本操作(初试)
查看>>
更改tomcat的根目录路径
查看>>
51nod 1292 字符串中的最大值V2(后缀自动机)
查看>>
加快ALTER TABLE 操作速度
查看>>
学习笔记之软考数据库系统工程师教程(第一版)
查看>>
PHP 程序员的技术成长规划
查看>>
memcached 分布式聚类算法
查看>>
jquery css3问卷答题卡翻页动画效果
查看>>
$digest already in progress 解决办法——续
查看>>
虚拟机 centos设置代理上网
查看>>
Struts2中Date日期转换的问题
查看>>
mysql 数据类型
查看>>
Ubuntu 设置当前用户sudo免密码
查看>>
设置tomcat远程debug
查看>>
android 电池(一):锂电池基本原理篇【转】
查看>>
Total Command 常用快捷键
查看>>
ionic 调用手机的打电话功能
查看>>
怎么使用阿里云直播服务应用到现在主流直播平台中
查看>>
Xcode全局替换内容,一键Replace
查看>>