(转)MyBatis & MyBatis Plus

Posted free_wings

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(转)MyBatis & MyBatis Plus相关的知识,希望对你有一定的参考价值。

(二期)3、mybatis与mybatis plus

【课程三】mybatis ...运用.xmind0.1MB

【课程三】mybatis...机制.xmind0.2MB

【课程三】mybatis与jdbc.xmind0.2MB

【课程三】多数据源处理.xmind49.4KB

【课程三】数据库...字段.xmind38.4KB

【课程三预习】myb...plus.xmind73.9KB

 

 

讲课顺序:

  • mybatis基本概念
  • jdbc与mybatis关系
  • mybatis的主要组件
  • mybatis的二级缓存
  • mybatis如何获取数据库中的表、字段
  • mybatis的多数据源处理
  • mybatis的读写分离
  • 一个简易的手写mybatis
  • mybatis plus的简单运用

问题准备:

MyBatis基本概念

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

jdbc与mybatis

需要先注册驱动和数据库信息、操作Connection、通过statement对象执行SQL,将结果返回给resultSet,然后从resultSet中读取数据并转换为pojo对象,最后需要关闭数据库相关资源。而且还需要自己对JDBC过程的异常进行捕捉和处理

 

MyBatis对JDBC的封装很好,几乎可以取代Jdbc。

MyBatis使用SqlSessionFactoryBuilder来连接完成JDBC需要代码完成的数据库获取和连接,减少了代码的重复。JDBC将SQL语句写到代码里,属于硬编码,非常不易维护,MyBatis可以将SQL代码写入xml中,易于修改和维护。JDBC的resultSet需要用户自己去读取并生成对应的POJO,MyBatis的mapper会自动将执行后的结果映射到对应的Java对象中。

三个组件

SqlSessionFactoryBuilder与SqlSessionFactory、SqlSession

 

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。

 

既然有了 SqlSessionFactory ,顾名思义,我们就可以从中获得 SqlSession 的实例了。SqlSession 完全包含了面向数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。

 

作用域:

SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但是最好还是不要让其一直存在以保证所有的 XML 解析资源开放给更重要的事情。

 

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏味道(bad smell)”。因此 SqlSessionFactory 的最佳作用域是应用作用域。有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

 

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。也绝不能将 SqlSession 实例的引用放在任何类型的管理作用域中,比如 Servlet 架构中的 HttpSession。如果你现在正在使用一种 Web 框架,要考虑 SqlSession 放在一个和 HTTP 请求对象相似的作用域中。换句话说,每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。这个关闭操作是很重要的,你应该把这个关闭操作放到 finally 块中以确保每次都能执行关闭。下面的示例就是一个确保 SqlSession 关闭的标准模式:

原理

技术分享图片

mybatis的二级缓存
一级缓存

在应用运行过程中,我们有可能在一次数据库会话中,执行多次查询条件完全相同的SQL,MyBatis提供了一级缓存的方案优化这部分场景,如果是相同的SQL语句,会优先命中一级缓存,避免直接对数据库进行查询,提高性能。具体执行过程如下图所示。

技术分享图片

  • 一级缓存数据库会话内部共享
一级缓存工作流程

一级缓存的工作流程是怎样的呢?我们从源码层面来学习一下。

一级缓存执行的时序图,如下图所示。

 

技术分享图片

二级缓存

在日常工作中,开发人员多数情况下是使用MyBatis的默认缓存配置,但是MyBatis缓存机制有一些不足之处,在使用中容易引起脏数据,形成一些潜在的隐患。

 

在上文中提到的一级缓存中,其最大的共享范围就是一个SqlSession内部,如果多个SqlSession之间需要共享缓存,则需要使用到二级缓存。开启二级缓存后,会使用CachingExecutor装饰Executor,进入一级缓存的查询流程前,先在CachingExecutor进行二级缓存的查询,具体的工作流程如下所示。

技术分享图片

二级缓存开启后,同一个namespace下的所有操作语句,都影响着同一个Cache,即二级缓存被多个SqlSession共享,是一个全局的变量。

当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。

 

  • Mybatis全局配置中启用二级缓存配置
<setting name="cacheEnabled" value="true"/>
  • 在对应的Mapper.xml中配置cache节点
<mapper namespace="userMapper">
    <cache />
    <result ... />
    <select ... />
</mapper>
  • 在对应的select查询节点中添加useCache=true
<select id="findUserById" parameterType="int" resultMap="user" useCache="true">
    select * from users where id=#{id};
</select>

 

 

集成ehcache做二级缓存步骤:

第一步:导入pom

<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.1.0</version>
</dependency>  

 

第二步:配置ehcache

1、ehcache.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd">
    <diskStore path="java.io.tmpdir/Tmp_EhCache" />
    <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false"
                  timeToIdleSeconds="0" timeToLiveSeconds="3600" memoryStoreEvictionPolicy="LRU" />
    <cache name="content"
           maxEntriesLocalHeap="200"
           timeToLiveSeconds="3600">
    </cache>
</ehcache>  

2、application.properties中打开ehcache支持

spring.cache.ehcache.config=classpath:ehcache.xml

 

第三步:mybatis的xml中使用ehcache

<cache type="org.mybatis.caches.ehcache.EhcacheCache" >
     <!--当缓存闲置n秒后销毁 -->
     <property name="timeToIdleSeconds" value="3600"/>
     <!--当缓存存活n秒后销毁-->
     <property name="timeToLiveSeconds" value="3600"/>
     <property name="maxEntriesLocalHeap" value="1000"/>
     <property name="maxEntriesLocalDisk" value="10000000"/>
     <property name="memoryStoreEvictionPolicy" value="LRU"/>
</cache>
mybatis如何获取数据库中的字段
原理

information_schema数据库是mysql自带的,它提供了访问数据库元数据的方式。什么是元数据呢?元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等。有些时候用于表述该信息的其他术语包括“数据词典”和“系统目录”。

 

在MySQL中,把 information_schema 看作是一个数据库,确切说是信息数据库。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表栏的数据类型与访问权 限等。在INFORMATION_SCHEMA中,有数个只读表。它们实际上是视图,而不是基本表,因此,你将无法看到与之相关的任何文件。

 

information_schema表说明

SCHEMATA表:提供了当前mysql实例中所有数据库的信息。是show databases的结果取之此表。

TABLES表:提供了关于数据库中的表的信息(包括视图)。详细表述了某个表属于哪个schema,表类型,表引擎,创建时间等信息。是show tables from schemaname的结果取之此表。

COLUMNS表:提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。是show columns from schemaname.tablename的结果取之此表。

STATISTICS表:提供了关于表索引的信息。是show index from schemaname.tablename的结果取之此表。

USER_PRIVILEGES(用户权限)表:给出了关于全程权限的信息。该信息源自mysql.user授权表。是非标准表。

SCHEMA_PRIVILEGES(方案权限)表:给出了关于方案(数据库)权限的信息。该信息来自mysql.db授权表。是非标准表。

TABLE_PRIVILEGES(表权限)表:给出了关于表权限的信息。该信息源自mysql.tables_priv授权表。是非标准表。

COLUMN_PRIVILEGES(列权限)表:给出了关于列权限的信息。该信息源自mysql.columns_priv授权表。是非标准表。

CHARACTER_SETS(字符集)表:提供了mysql实例可用字符集的信息。是SHOW CHARACTER SET结果集取之此表。

COLLATIONS表:提供了关于各字符集的对照信息。

COLLATION_CHARACTER_SET_APPLICABILITY表:指明了可用于校对的字符集。这些列等效于SHOW COLLATION的前两个显示字段。

TABLE_CONSTRAINTS表:描述了存在约束的表。以及表的约束类型。

KEY_COLUMN_USAGE表:描述了具有约束的键列。

ROUTINES表:提供了关于存储子程序(存储程序和函数)的信息。此时,ROUTINES表不包含自定义函数(UDF)。名为“mysql.proc name”的列指明了对应于INFORMATION_SCHEMA.ROUTINES表的mysql.proc表列。

VIEWS表:给出了关于数据库中的视图的信息。需要有show views权限,否则无法查看视图信息。

TRIGGERS表:提供了关于触发程序的信息。必须有super权限才能查看该表

 

技术分享图片

 

查找当前数据库的表信息:

第一种方法:

select * from information_schema.TABLES where TABLE_SCHEMA=(select database())

第二种方法:

#获取表信息
show table status 

 

查找当前表的所有字段信息:

第一种方法:

select * from information_schema.COLUMNS where TABLE_SCHEMA = (select database()) and TABLE_NAME=#{tableName}

第二种方法:

show full fields from `student`;
mybatis的多数据源处理
单独使用mybatis的多数据源处理

配置多个environment,生产sessionFactory的时候指定environment即可实现多数据源。

<environments default="development">
    <environment id="development">
        <!--使用默认的JDBC事务管理-->
        <transactionManager type="JDBC"/>
        <!--使用连接池-->
        <dataSource type="POOLED">
            <!--这里会替换为local-mysql.properties中的对应字段的值-->
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
        </dataSource>
    </environment>

    <environment id="development2">
        <!--使用默认的JDBC事务管理-->
        <transactionManager type="JDBC"/>
        <!--使用连接池-->
        <dataSource type="POOLED">
            <!--这里会替换为local-mysql.properties中的对应字段的值-->
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url2}"/>
            <property name="username" value="${username2}"/>
            <property name="password" value="${password2}"/>
        </dataSource>
    </environment>
</environments>
集成spring的多数据源处理

1、通过扫描包区分

git demo: https://gitee.com/lv-success/git-second/tree/master/course-3-mybatis/springBootMybatisMulidatasource

 

2、通过动态数据源区分

一般使用注解的形式,这里先留着,后面的renren-fast项目

mybatis的读写分离

原理:

和多数据源处理差不多,mybatis做读写分离也有多种方法。通过拦截发起请求的方法或执行的sql来自动判断需要的数据源!

 

1、拦截发起操作的方法名

需要自己约定增删改查的前缀,然后根据前缀选择数据源!

git demo:https://gitee.com/lv-success/git-second/tree/master/course-3-mybatis/bounterMybatis

 

2、拦截发起操作的sql

git demo:https://github.com/shawntime/shawn-rwdb

一个简易的手写mybatis
逻辑整理

技术分享图片

  • 1.读取xml文件,建立连接

从图中可以看出,MyConfiguration负责与人交互。待读取xml后,将属性和连接数据库的操作封装在MyConfiguration对象中供后面的组件调用。本文将使用dom4j来读取xml文件,它具有性能优异和非常方便使用的特点。

 

  • 2.创建SqlSession,搭建Configuration和Executor之间的桥梁

我们经常在使用框架时看到Session,Session到底是什么呢?一个Session仅拥有一个对应的数据库连接。类似于一个前段请求Request,它可以直接调用exec(SQL)来执行SQL语句。从流程图中的箭头可以看出,MySqlSession的成员变量中必须得有MyExecutor和MyConfiguration去集中做调配,箭头就像是一种关联关系。我们自己的MySqlSession将有一个getMapper方法,然后使用动态代理生成对象后,就可以做数据库的操作了。

 

  • 3.创建Executor,封装JDBC操作数据库

Executor是一个执行器,负责SQL语句的生成和查询缓存(缓存还没完成)的维护,也就是jdbc的代码将在这里完成,不过本文只实现了单表,有兴趣的同学可以尝试完成多表。

 

  • 4.创建MapperProxy,使用动态代理生成Mapper对象

我们只是希望对指定的接口生成一个对象,使得执行它的时候能运行一句sql罢了,而接口无法直接调用方法,所以这里使用动态代理生成对象,在执行时还是回到MySqlSession中调用查询,最终由MyExecutor做JDBC查询。这样设计是为了单一职责,可扩展性更强。

 

mybatis plus的简单运用

官方地址:

https://gitee.com/lv-success/git-second/tree/master/course-3-mybatis/mybatisPlusDemo

 

以上是关于(转)MyBatis & MyBatis Plus的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis之Oracle增删查改示例--转

(转)Mybatis高级映射动态SQL及获得自增主键

转MyBatis学习总结——MyBatis快速入门

转MyBatis学习总结——Mybatis缓存

转MyBatis学习总结——优化MyBatis配置文件中的配置

转Mybatis框架结构与基本原理