Mybatis学习总结

来源:互联网 发布:超时空拦截知乎 编辑:程序博客网 时间:2024/06/09 20:30

一、Mybatis介绍

Mybatis是一个支持普通SQL查询、存储过程和高级映射的持久层框架。Mybatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。Mybatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的 Java对象)映射成为数据库中的记录。


Mybatis中的核心概念:

1)SqlSession:代表和数据库的一次会话,向用户提供了操作数据库的方法;

2)MappedStatement:代表要发往数据库执行的指令,可以理解为是Sql的抽象表示;

3)Executor:具体用来和数据库交互的执行器,接受MappedStatement作为参数;

4)映射接口:在接口中会将要执行的sql语句用一个方法来表示,具体的sql写在映射文件中;

5)映射文件:可以理解为是Mybatis编写sql的地方,通常来说每一张单表都会对应着一个映射文件,在该文件中会定义sql语句入参和出参的形式。

二、Mybatis数据持久化(以查询为例)

1.准备开发环境

①创建测试项目,如下图所示:


②添加相应的jar包,如下图所示:


③在MySQL数据库中创建数据库和表

create database mybatis;

use mybatis;

create table users(id int primary key,name varchar(10),age int);

insert into users(id,name,age) values(1,'lv',20);

insert into users(id,name,age) values(2,'ting',21);

2.使用mybatis查询表中的数据

①在com.example.xml包下创建一个NewFile.xml

NewFile.xml文件中内容如下:


②在com.example.domain包下创建一个User实体类

User类代码如下:


③在com.example.mapping包下定义users表的sql映射文件userMapper.xml

userMapper.xml文件中内容如下:


④在NewFile.xml文件中注册userMapper.xml文件

如下图所示:


⑤在com.example.test包下创建测试代码test.java,执行select语句

如下图所示:


整个项目文件结构如下图所示:


三、mybatis缓存

一级缓存

在系统代码的运行中,我们可能会在一个数据库会话中,执行多次查询条件完全相同的sql,鉴于日常应用的大部分场景都是读多写少,这重复的查询会带来一定的网络开销,同时select查询的量比较大的话,对数据库的性能还是有比较大的影响。

如果是MySQL数据库的话,在服务端和jdbc端都开启预编译的话,可以在本地jvm端缓存statement,可以在MySQL服务端直接执行sql,省去编译sql的步骤,但也无法避免和数据库之间的重复交互。

Mybatis提供了一级缓存的方案来优化在数据库会话间重复查询的问题。实现方式是每一个SqlSession中都持有了自己的缓存,一种是session级别,即在一个Mybatis会话中执行的所有语句,都会共享这一个缓存。一种是statement级别,可以理解为缓存只对当前执行的这一个statement有效。如下图所示:


每一个SqlSession中持有了自己的Executor,每一个Executor中有一个local cache。当用户发起查询时,Mybatis会根据当前执行的MappedStatement生成一个key,去local cache中查询,如果缓存命中的话,返回。反之,则写入local cache中再将结果返回给用户。

一级缓存配置:

在MyBatis的配置文件中,添加语句(<setting name="localCacheScope"  value="SESSION"/>),就可以使用一级缓存。共有两个选项,SESSION和STATEMENT,默认是SESSION。

一级缓存工作流程:

①对于某个select statement,根据该statement生成key;

②判断在local Cache中,该key是否有对应的数据存在;

③如果命中,则跳过查询数据库;

④如果没命中,则去数据库中查看数据,得到查询结果,将key和查询到的结果放入到local cache中,并将查询结果返回;

⑤判断缓存级别是否为statement级别,如果是,清空缓存。

总结:

①Mybatis一级缓存的生命周期和SqlSession一致;

②Mybatis的缓存也是一个粗粒度的缓存,没有更新缓存和缓存过期的概念,同时只是使用了默认的hashmap,也没有做容量上的限定。

③Mybatis的一级缓存最大范围时SqlSession内部,有多个SqlSession或者分布式的环境下,有操作数据库写的话,会引起脏数据,建议不要去使用一级缓存。

注:一级缓存只是在数据库会话内部共享。例如:有两个会话SqlSession1和SqlSession2,在SqlSession1中更改了某一信息,而SqlSession2查询依旧是原先数据信息,因此这里出现脏数据,也证明了一级缓存只是在数据库会话内部共享这一结论。

二级缓存

在一级缓存中,其最大的共享范围是一个SqlSession内部,那么如何让多个SqlSession之间也能够共享缓存呢,答案是二级缓存。当开启二级缓存后,会使用CachingExecutor装饰Executor,在进入后续执行前,现在CachingExecutor进行二级缓存查询,具体工作流程如下:


在二级缓存的使用中,一个namespace下的所有操作语句,都影响着同一个cache,即二级缓存是被多个SqlSession共享着的,是一个全局的变量。当开启缓存后,数据的查询执行的流程就是二级缓存—>一级缓存—>数据库。

二级缓存配置:

①在Mybatis的配置文件中开启二级缓存

<setting name="cacheEnabled"  value="true"/>

②在Mybatis的映射XML中配置cache

<cache/>

cache标签用于声明这个namespace使用的是二级缓存,并且可以自定义配置。

<cache-ref namespace="mapper.UserMapper"/>

cache-ref代表引用别的命名空间的cache配置,两个命名空间的操作使用的是同一个cache.

总结:

①Mybatis的二级缓存相对于一级缓存来说,实现了SqlSession之间缓存数据的共享,同时粒度更加的细,能够到Mapper级别,通过Cache接口实现类不同的组合,对Cache的可控性也更强。

②Mybatis在多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用的条件比较苛刻。

③在分布式环境下,由于默认的Mybatis Cache实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将Mybatis的Cache接口实现,有一定的开发成本,所以可以用radis或者memcache实现业务上的缓存。

注:Mybatis的二级缓存并不适用于映射文件存在多表查询的情况。一般来说,我们会为每一个单表创建一个单独的映射文件,如果存在涉及多个表的查询的话,由于Mybatis的二级缓存是基于namespace的,多表查询语句所在的namespace无法感应到其他namespace中的语句对表查询中涉及的表进行了修改,引发脏数据问题。


原创粉丝点击