Hibernate和Mybatis对比
Hibernate和Mybatis都是orm对象关系映射框架,都是用于将数据持久化的框架技术。
以下几点作为分析:
- 映射关系:
hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql。配置对象关系映射关系有两种,一种是基于xml的方式,另一种是基于annotation的注解方式。在hibernate4以后已经将annotation的jar包集成进来了,如果使用hibernate3的版本就需要引入annotation的jar包。
<!-- 基于annotation的配置 -->
<mapping class="com.xiaoluo.bean.User"/>
<!-- 基于hbm.xml配置文件 -->
<mapping resource="com/xiaoluo/bean/User.hbm.xml"/>
而mybatis仅有基本的字段映射,对象数据以及对象实际关系仍然需要通过手写sql来实现和管理。
实现思路有两种:
1. 在使用 SQL 语句的时候,为每个字段定义别名;
2. 使用 MyBatis 映射文件的 resultMap 标签。
- 底层配置:
针对初学者觉得hibernate的配置文件好麻烦,用hibernate还要写代码,还要写配置。Hibernate中配置主要分为两种:一种包含了Hibernate与数据库的基本连接信息,在Hibernate工作的初始阶段,这些信息被先后加载到Configuration和SessionFactory实例;另一种包含了Hibernate的基本映射信息,即系统中每一个类与其对应的数据库表之间的关联信息,在Hibernate工作的初始阶段,这些信息通过hibernate.cfg.xml的mapping节点被加载到Configuration和SessionFactory实例。这两种文件信息包含了Hibernate的所有运行期参数。以下是实现连接的基本方式:
第一种是使用hibernate.properties文件作为配置文件。
//实例化configuration对象
Configuration cfg = new Configuration()
//多次调用addResource()方法,添加映射文件
cfg.addResource("Item.hbm.xml")
cfg.addResource("Bid.hbm.xml");
查看hibernate.properties文件发现,该文件没有提供Hibernate映射文件的方式。因此使用hibernate.properties文件来作为配置文件时,必须使用Configuration的.addResource()方法,使用该方法来添加映射文件
第二种是使用hibernate.cfg.xml文件作为配置文件。如下是样例
<hibernate-mapping>
<class name="com.bzu.hibernate.Student" table="student">
<id name="id" column="id" type="string">
<generator class="uuid"></generator>
</id>
<property name="name" column="name" type="string"></property>
<property name="cardId" column="cardId"type="string"></property>
<property name="age" column="age" type="int"></property>
<set name="courses" table="student_course" cascade="save-update">
<key column="stu_id"></key>
<many-to-many class="com.bzu.hibernate.Course" column="course_id">
</many-to-many>
</set>
</class>
</hibernate-mapping></span>
以上代码可以在配置hibernate开发环境时自动生成的。
mybatis比hibernate轻量了很多,少了很多配置
首先是读取mybatis的配置文件,创建工程类,获得session,调用SqlSession里面的方法进行数据库的相关操作。
factory = new SqlSessionFactoryBuilder().build(reader);
它的外层方法parseConfiguration(),进行具体的解析configuration下的子节点,并给configuration的对应变量赋值。
重点关注其中的:
environmentsElement(root.evalNode("environments")); //相当于jdbc配置数据源,以及事务的配置
mapperElement(root.evalNode("mappers"));//解析sql映射文件
- 数据查询:
在Hibernate里面Session的查询不能够胜任于复杂查询,所以现在的所有查询都通过Query接口完成,在这个接口里面要使用hql语言(及其类似于SQL语句)。比如:String hql="FROM News AS n";
Query query=HibernateSessionFactory.getSession().createQuery(hql);
在使用Hiberante进行数据查询的时候,发现所有的内容都会以POJO类的形式返回,所有的实例化操作部分都由Hibernate自动帮助用户处理了,
对于多表查询时编写HQL语言则会受到限制,营运在复杂场景的业务显得尤为笨重。
MyBatis进行数据库查询一定会用到SqlSessionFactory和SqlSession这两个类的对象,为了以后每次查询方便,就先构造有一个工具类,用来管理这两个对象:SqlSessionFactory的对象是重量级的,而SqlSession是轻量级的
另:mybatis在查询时可以传多个参数,批量删除,新增,修改,相比Hibernate更为灵活。可以根据业务场景多表联合查询,在报表导出比Hibernate尤为突出。
- 对象管理:
Hibernate 是完整的对象/关系映射解决方案,它提供了对象状态管理(state management)的功能,使开发者不再需要理会底层数据库系统的细节。也就是说,相对于常见的 JDBC/SQL 持久层方案中需要管理 SQL 语句,Hibernate采用了更自然的面向对象的视角来持久化 Java 应用中的数据。
换句话说,使用 Hibernate 的开发者应该总是关注对象的状态(state),不必考虑 SQL 语句的执行。这部分细节已经由 Hibernate 掌管妥当,只有开发者在进行系统性能调优的时候才需要进行了解。
而MyBatis在这一块没有文档说明,用户需要对对象自己进行详细的管理。
Hibernate对实体关联对象的抓取有着良好的机制。对于每一个关联关系都可以详细地设置是否延迟加载,并且提供关联抓取、查询抓取、子查询抓取、批量抓取四种模式。 它是详细配置和处理的。
而Mybatis的延迟加载是全局配置的。
- 对象关联机制:
Hibernate对实体关联对象的抓取有着良好的机制。对于关联关系都可以详细地设置是否延迟加载,并且提供关联抓取、查询抓取、子查询抓取、批量抓取四种模式,它是详细配置和处理的。
<!--关联配置 -->
<many-to-one name="grade" class = "entity.Grade" column="gid"></many-to-one>
Mybatis的延迟加载是全局配置的,也可以全局自定义配置:如ClazzMapper.xml
<mapper namespace="org.zang.mapper.ClazzMapper">
<!-- 映射Clazz对象的resultMap -->
<resultMap type="org.zang.domain.Clazz" id="clazzResultMap">
<id property="id" column="id"/>
<result property="code" column="code"/>
<result property="name" column="name"/>
<!-- 一对多关联映射:collection fetchType="lazy"表示懒加载 -->
<collection property="students" javaType="ArrayList" column="id" ofType="org.zang.domain.Student"
select="org.zang.mapper.StudentMapper.selectStudentByClazzId" fetchType="lazy">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
</collection>
</resultMap>
<!-- 根据id查询班级信息,返回resultMap -->
<select id="selectClazzById" parameterType="int" resultMap="clazzResultMap">
SELECT * FROM tb_clazz WHERE id = #{id}
</select>
</mapper>
- 缓存机制
hibernate的缓存机制,包括一级缓存(session级别)、二级缓存(sessionFactory级别)以及查询缓存其中持久化对象有三种状态,分别是:
transient(瞬时态):尚未与Session关联对象,失去引用的话,就会被JVM回收。一般就是直接New创建的对象。
persistent(持久态):已经与当前session产生关联,并且相关联的session没有关闭,并且事务尚未提交。
detached(脱管态):存在持久化OID,但没有与当前session关联,脱管状态改变hibernate不能检测到。
<span style="font-family:SimSun;font-size:18px;">// 获得Session
Session session = HibernateUtils.openSession();
// 开启事务
Transaction transaction = session.beginTransaction();
Book book = new Book(); // 瞬时态(没有OID,未与Session关联)
book.setName("hibernate精通");
book.setPrice(56d);
session.save(book);// 持久态(具有OID,与Session关联)
// 提交事务,关闭Session
transaction.commit();
session.close();
System.out.println(book.getId()); // 脱管态(具有 OID,与Session断开关联)
</span>
hibernate向一级缓存放入数据时,同时保存快照数据,当修改一级缓存的时候,在flush操作时,对比缓存和快照,如果不一致,自动更新
由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此Hibernate二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。
<!-- 开启二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!-- 为hibernate指定二级缓存的实现类 -->
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
hibernate的查询缓存是主要是针对普通属性结果集的缓存, 而对于实体对象的结果集只缓存id。
mybatis提供了缓存机制减轻数据库压力,提高数据库性能
mybatis的缓存分为两级:一级缓存、二级缓存
一级缓存是SqlSession级别的缓存,缓存的数据只在SqlSession内有效
1.第一次执行select完毕会将查到的数据写入SqlSession内的HashMap中缓存起来
2.第二次执行select会从缓存中查数据,如果select相同切传参数一样,那么就能从缓存中返回数据,不用去数据库了,从而提高了效率
二级缓存是mapper级别的缓存,同一个namespace公用这一个缓存,所以对SqlSession是共享的;二级缓存默认是没有开启的。需要在setting全局参数中配置开启二级缓存,也可以针对某个表自定义开启,相比Hibernate更为灵活。
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>当前mapper下所有语句开启二级缓存
- 系统的调优解决方法:
Hibernate的调优方法可以采用:
1、制定合理的缓存策略;
2、尽量使用延迟加载特性;
3、采用合理的 Session 管理机制;
4、使用批量抓取,设定合理的批处理参数(batch_size)
5、进行合理的 O/R 映射设计
Mybatis的调优方法可以采用:
1、MyBatis 可以进行详细的 SQL 优化设计
2、MyBatis 在 Session 方面和 Hibernate 的 Session 生命周期是一致的, 同样需要合理的 Session 管理机制。 MyBatis 同样具有二级缓存机制。
8.SQL的优化
Hibernate的SQL调优方法可以采用:
1、使用的是封装好, 通用的 SQL 来应付所有场景;
2、查询时,会查询所有字段,会有不必要的性能消耗;
3、可以自己写SQL,但违背了框架的初衷。
Mybatis的SQL调优方法可以采用:
1、是针对响应的场景设计的 SQL,更灵活、 可控性更好、 更优化
2、SQL是手动编写的,按需查询
此处推荐mybatis做持久化操作.
- 可移植性
Hibernate: 1、与具体数据库的关联只需在 XML 文件中配置即可
2、所有的 HQL 语句与具体使用的数据库无关, 移植性很好
Mybatis: 1、所有的 SQL 语句都是依赖所用的数据库的
2、所以不同数据库类型的支持不好
- 动态SQL
Hibernate: 不支持
Mybatis:支持
- 业务场景
Hibernate: 针对业务场景复杂多变的情况,其灵活易开发优于Hibernate,实现业务要求的优化空间大
Mybatis: 复杂的业务场景开发效率低
- 开发成本
Hibernate: 托管spring,配置内容较少,容易上手,后期易于维护。
Mybatis: 全自动配置,底层配置复杂,多场景查询不灵活,开发时间成本较高。不熟悉Hibernate机制的开发人员开发难度加大
- 建议选择情况
Hibernate: 1、适用于中小企业需求变化不多的项目,对复杂多变的业务要求不高
2、其它条件满足,看团队大多数人员的倾向使用
3、对于不是熟悉Hibernate的开发者来说不易上手,后期开发吃力
Mybatis: 1、数据量大(千万级),高并发
2、表关联复杂度(>20)
3、项目要求对于数据库可控性好, 可深度调优
4、后期易于维护