Mybatis
1. Mybatis架构或工作流程
- mybatis配置
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环 境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需 要在SqlMapConfig.xml中加载。
2) 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
3) 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
4) mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
5) Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
6) Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
7) Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。
2. Mapper.xml中statement中属性含义
-
id:sql语句唯一标识
-
parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼 接在sql中。
- resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。
- resultMap:resultType可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功。如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系resultMap实质上还需要将查询结果映射到pojo对象中。
resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象 中包括pojo和list实现一对一查询和一对多查询。 -
#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
-
${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进 行jdbc类型转换,${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。
3. SqlSessionFactory
SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory。
4. SqlSession
SqlSession是一个面向用户的接口, sqlSession中定义了数据库操作方法。
每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。
private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();
5. Mybatis中自主主键如何获取
#{}:如果传入的是pojo类型,那么#{}中的变量名称必须是pojo中对应的属性.属 性.属性… 如果要返回数据库自增主键:可以使用select LAST_INSERT_ID()
执行 select LAST_INSERT_ID()数据库函数,返回自增的主键 keyProperty:将返回 的主键放入传入参数的Id中保存.
order:当前函数相对于insert语句的执行顺序,在insert前执行是before,在insert后 执行是AFTER resultType:id的类型,也就是keyproperties中属性的类型
6. Mybatis中uuid主键如何获取
需要增加通过select uuid()得到uuid值
要将User中的id改成String类型,并且将User表中的id字段改为varchar(36)
7. Mapper接口开发方法
通常Mybatis开发Dao方法有两种。即原始Dao开发方法和Mapper接口开发方法。
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper接口开发需要遵循以下规范:
- Mapper.xml文件中的namespace与mapper接口的类路径相同。
- Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
- Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
- Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
8. selectOne和selectList
动态代理对象调用sqlSession.selectOne()
和sqlSession.selectList()
是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。
9. 动态sql
通过mybatis提供的各种标签方法实现动态拼接sql。
foreach标签:循环传入的集合参数
collection:传入的集合的变量名称
item:每次循环将循环出的数据放入这个变量中
open:循环开始拼接的字符串
close:循环结束拼接的字符串
separator:循环中拼接的分隔符
where标签作用:会自动向sql语句中添加where关键字,会去掉第一个条件的and关键字。
include标签:调用sql条件
10. Mybatis缓存机制
将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关 系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系 统的性能问题。
mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。
mybaits提供一级缓存,和二级缓存。
一级缓存
是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在 对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据。不同的sqlSession 之间的缓存数据区域(HashMap)是互相不影响的。
一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql 语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓 存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession结束后 该sqlSession中的一级缓存也就不存在了。Mybatis默认开启一级缓存。
如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中 的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。二级缓存
是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句, 多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以 共用二级缓存,二级缓存是跨SqlSession的。
二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不 同的sqlSession两次执行相同namespace下的sql语句且向sql中传递参数也相同 即最终执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内 存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。Mybatis 默认没有开启二级缓存需要在setting全局参数中配置开启二级缓存。
如果缓存中有数据就不用从数据库中获取,大大提高系统性能。
二级缓存的应用场景
对查询频率高,变化频率低的数据建议使用二级缓存。
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用 mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较 高的统计分析sql、电话账单查询sql等。
实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓 存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60 分钟、24小时等,根据需求而定。
Mybatis缓存的局限性
mybatis二级缓存对细粒度的数据级别
的缓存实现不好,比如如下需求:对商品信 息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品 信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商 品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper 为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此 类问题需要在业务层根据需求对数据有针对性缓存。
11. Mybatis实现分布式缓存
ehcache是一个分布式缓存框架。
EhCache 是一个纯Java的进程内缓存框架,是一种广泛使用的开源Java分布式缓 存,具有快速、精干等特点,是Hibernate中默认的CacheProvider。
我们系统为了提高系统并发,性能、一般对系统进行分布式部署(集群部署方式)
不使用分布缓存,缓存的数据在各各服务单独存储,不方便系统开发。所以要使用 分布式缓存对缓存数据进行集中管理。
mybatis无法实现分布式缓存,需要和其它分布式缓存框架进行整合。
12. Mybatis逆向工程
使用官方网站的mapper自动生成工具mybatis-generator-core-1.3.2
来生成po类和 mapper映射文件。
作用:mybatis官方提供逆向工程,可以使用它通过数据库中的表来自动生成Mapper 接口和映射文件(单表增删改查)和Po类.
13. Mybatis解决jdbc编程的问题
- 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
解决:在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。 - Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。 - 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
解决:Mybatis自动将java对象映射至sql语句,通过statement中的 parameterType定义输入参数的类型。 - 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
14. Hibernate与Mybatis对比
首先简单介绍下两者的概念Hibernate
:Hibernate 是当前最流行的ORM框架,对数据库结构提供了较为完整 的封装。Mybatis
:Mybatis同样也是非常流行的ORM框架,主要着力点在于POJO 与SQL 之间的映射关系。
其次具体从几个方面说一下两者的区别:
1.两者最大的区别
针对简单逻辑,Hibernate和MyBatis都有相应的代码生成工具,可以生成简单基 本的DAO层方法。
针对高级查询,Mybatis需要手动编写SQL语句,以及ResultMap。而Hibernate有 良好的映射机制,开发者无需关心SQL生成与结果映射,可更专注于业务流程。
2.开发难度对比
Hibernate的开发难度要大于Mybatis。主要由于Hibernate比较复杂、庞大,学习 周期较长。
而Mybatis则相对简单一些,并且Mybatis主要依赖于sql的书写,让开发者感觉 更熟悉。
3.sql书写比较
Mybatis的SQL是手动编写的,所以可以按需求指定查询的字段。不过没有自己的 日志统计,所以要借助log4j来记录日志。
Hibernate也可以自己写SQL来指定需要查询的字段,但这样就破坏了Hibernate开 发的简洁性。不过Hibernate具有自己的日志统计。
4.数据库扩展性比较
Mybatis由于所有SQL都是依赖数据库书写的,所以扩展性,迁移性比较差。
Hibernate与数据库具体的关联都在XML中,所以HQL对具体是用什么数据库并不 是很关心。
5.缓存机制比较
相同点:Hibernate和Mybatis的二级缓存除了采用系统默认的缓存机制外,都可 以通过实现自己的缓存或为其他第三方缓存方案,创建适配器来覆盖缓存行为。
不同点:Hibernate的二级缓存配置在SessionFactory生成的配置文件中进行详细配 置,然后再在具体的表-对象映射中配置是那种缓存。
MyBatis的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对 不同的表可以自定义不同的缓存机制。并且Mybatis可以在命名空间*享相同的 缓存配置和实例,通过Cache-ref来实现。
两者比较:因为Hibernate对查询对象有着良好的管理机制,用户无需关心SQL。 所以在使用二级缓存时如果出现脏数据,系统会报出错误并提示。
而MyBatis在这一方面,使用二级缓存时需要特别小心。如果不能完全确定数据更 新操作的波及范围,避免Cache的盲目使用。否则,脏数据的出现会给系统的正常 运行带来很大的隐患。
6.总结
Hibernate与MyBatis都可以是通过SessionFactoryBuider由XML配置文件生成 SessionFactory,然后由SessionFactory 生成Session,最后由Session来开启执行事 务和SQL语句。
而MyBatis的优势是MyBatis可以进行更为细致的SQL优化,可以减少查询字段,并且容易掌握。
Hibernate的优势是DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。 数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。 有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。