区别:
1.Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。MyBatis 在查询关联对象或关联集合对象时,需要手动编写 sql 来完成,不过 mybatis 可以通过 XML 或注解方式灵活配置要运行的 sql 语句,并将java 对象和 sql 语句映射生成最终执行的 sql,最后将 sql 执行的结果再映射生成 java 对象,算是半自动ORM映射工具。
2.Mybatis 学习门槛低,简单易学,程序员直接编写原生态 sql,可严格控制 sql 执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是 mybatis 无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套 sql 映射文件,工作量大。
3.Hibernate 对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用 hibernate 开发可以节省很多代码,提高效率。因此他的数据库移植性很好,而Mybatis更换数据库,很多sql语句要大量修改。但是Hibernate 的缺点是学习门槛高,要精通门槛更高,而且怎么设计 O/R 映射,
原文链接:https://blog.youkuaiyun.com/banzhuanhu/article/details/110201816
一级缓存(内置缓存,都是默认开启)
1:一级缓存是默认开启的;
2:底层其实是基于hashmap的本地内存缓存;
3:作用域是session(其实就相当于在一个方法里,更准确说应该是一次与数据库的会话,一个方法如果提交了2次事务,就出现2个session了?);
4:当session关闭或者刷新的时候缓存清空;
5:不同sqlsession或者是hibernatesession之间缓存互不影响,是线程独享的;
导致的问题
数据一致性问题:
比如:我有一个更新操作对同一条数据,
如果是sqlsessionA进行了更新操作,则sqlsessionA对应的一级缓存被清空;(疑问?应该是sqlsessionA先进行查询操作,且一级缓存没清空 ,然后sqlsessionB更新操作后,导致的sqlsessionA再次查询数据不一致才对把???后面再测试)
如果是sqlsessionB进行了更新操作,则此更新操作对该sqlsessionA不可见;
那么其实这个时候sqlsessionA再查的数据就是过期失效数据了;
就出现了数据不一致现象;
建议:
1:单个sqlsession的生命周期不能过长;
2:如果是对同一个语句更新尽量使用同一个sql,也就是同一个sqlsession;
3:建议关闭一级缓存,
Hibernate一级缓存是HibernateSession,session,,字面意思即会话。这里表示的是应用程序和数据库的一次交互(会话)。
所以,当一次交互过程中,涉及到对同对象查询时(比如一段代码里,有好几个地方都会查询某条姓名为“张三”的数据),除了第一次查询需要执行select的sql
语句去查询数据库,后面不用再去执行sql语句了,直接从缓存中拿数据。
代码验证:
- // 证明一级缓存的存在
- @Test
- public void test2() {
- Session session = HibernateUtils.getSession(); // 得到session对象
- session.beginTransaction();
- // 获取goods1对象时,由于一级缓存中没有数据,所以会发送SQL语句,查询数据库中的内容
- Goods goods1 = (Goods) session.get(Goods.class, 1);
- System.out.println(goods1);
- // 获取goods2对象时,不会发出SQL语句,会从Session缓存中获取数据
- Goods goods2 = (Goods) session.get(Goods.class, 1);//根据id从缓存获取对象
- System.out.println(goods2);
- session.getTransaction().commit();
- session.close();
- }
Session 缓存什么时候被清理?
1,commit() 方法被调用时。因为提交则表示,本次同数据库的会话已经完成,不会再用到。
2,查询时会清理缓存,保证查询结果能反映对象的最新状态。
3,显示的调用session 的 flush方法区清除缓存。
session 清理缓存的特例:
当对象使用 native 生成器 时 会立刻清理缓存向数据库中插入记录。
Mybatis 一级缓存 SqlSessio 同理
demo如下
@Test
public void test1(){
InputStream is = TestUser.class.getClassLoader().getResourceAsStream("application.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
System.out.println("===========================================");
User user1 = sqlSession.selectOne("getUserById",1001);
System.out.println(user1);
System.out.println("===========================================");
User user2 = sqlSession.selectOne("getUserById",1001);
System.out.println(user2);
System.out.println("===========================================");
sqlSession.close();
}
从打印的sql来看,在同一个SqlSession中,查询2次相同的数据时(实际上是通过mapper.xml找到的同一条sql语句),只会在第一次查询时,打印出一次sql,后面就从缓存直接拿了。这就是一级缓存的作用 。
可以通过mapper.xml中标签属性屏蔽一级缓存:flushCache="true" (默认是false,意为不清除缓存,也就是开启一级缓存的意思)具体如下:
对比:Hibernate一级缓存,判断是否相同数据是根据缓存里 的对象id,如果是hibernate
通过hql语句或者sql语句去查询,则一级缓存没有起作用,还是每次都会执行查询。、
而Mybatis一级缓存,,是通过sql来判断是否为相同数据,也就是如果2次的sql语句一致,第二次就直接从缓存里拿。(当然前提也是在一次事务会话,事务提交后缓存也就清楚了,当然也可以手动清除缓存,和hibernate几乎一样的道理)
具体可以参考
https://blog.youkuaiyun.com/chengqiuming/article/details/100179998
二级缓存(外置缓存,都是默认关闭)
默认情况下默认也是采用 PerpetualCache,HashMap存储,SessionFactory 不会启用这个缓存插件,外置缓存中的数据是数据库数据的复制(可以缓存整个数据库?),外置缓存的物理介质可以是内存或硬盘。
二级缓存被多个SqlSession或HibernateSession共享,是一个全局的变量,线程共享,存在于SessionFactory的生命周期,是由SessionFactory管理的?
二级缓存坑的地方:
Mybatis:
你在OrderMapper.XML 和 UserMapp.XML的文件 都操作了User表的话,
当你使用OrderMapper.XML的SQL更新User表的时候,其他的SeqSession在OrderMapper.XML可以查到User表最新的数据,但是在UserMapp.XML查不到最新的数据
原因就是 二级缓存是基于某个XXXMapper.xml,每个Mapper直接独立,所以 不同Mapper操作同一张表的时候 (哪怕执行的是同一条sql,也要区分多个缓存对象?一级缓存也会吗??), 使用二级缓存会造成脏读
这也就是没什么人开启二级缓存的主要原因
原文链接:https://blog.youkuaiyun.com/weixin_35910783/article/details/113679318
当然二级缓存也不建议使用,mysql都默认关闭了,更何况我们呢。
缓存建议使用redis,mamcache等
参考:原文链接:https://blog.youkuaiyun.com/u010953880/article/details/104412646