一、乐观锁和悲观锁

悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
 
乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
 
两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。
 
悲观锁:
String hqlStr = "from TUser as user where user.name='Erica'";
Query query = session.createQuery(hqlStr);
query.setLockMode("user",LockMode.UPGRADE); //加锁
List userList = query.list();//执行查询,获取数据
Hibernate的加锁模式有:
Ø LockMode.NONE : 无锁机制。
Ø LockMode.WRITE :Hibernate在 Insert 和 Update 记录的时候会自动获取。
Ø LockMode.READ : Hibernate在读取记录的时候会自动获取。
       ---以上这三种锁机制一般由 Hibernate 内部使用,如 Hibernate 为了保证 Update 过程中对象不会被外界修改,会在 save 方法实现中自动为目标对象加上 WRITE 锁。
Ø LockMode.UPGRADE :利用数据库的 for update 子句加锁。
Ø LockMode. UPGRADE_NOWAIT :Oracle 的特定实现,利用 Oracle 的for update nowait 子句实现加锁。
              -- 上面这两种锁机制是我们在应用层较为常用的,加锁一般通过以下方法实现:
Criteria.setLockMode
Query.setLockMode
Session.lock 

二、多态

第一种方案:一个子类对应一张表。
实现方式:在父类的配置文件中配置子类的实现方式,当然,也可以在子类中单独配置:
         <!-- 可单独写在Student.hbm.xml里 -->
<union-subclassname="com.jomoo.entity.Student"table="student"extends="com.jomoo.entity.People">
<propertyname="studentNumber"column="studentNumber"type="string"></property>
</union-subclass>
<!-- 可单独写在Teacher.hbm.xml里 -->
<union-subclass name="com.jomoo.entity.Teacher" table="teacher" extends="com.jomoo.entity.People">
<property name="salary" column="salary" type="string"></property>
</union-subclass>
 
第二种方案:使用一张表表示所有继承体系下的类的属性的并集。
这种策略是使用<subclass>标签来实现的。因为类继承体系下会有许多个子类,要把多个类的信息存放在一张表中,必须有某种机制来区分哪些记录是属于哪个类的。Hibernate中的这种机制就是,在表中添加一个字段,用这个字段的值来进行区分。在表中添加这个标示列使用<discriminator>标签来实现。
 
第三种方案:每个子类使用一张表只存储它特有的属性,然后与父类所对应的表以一对一主键关联的方式关联起来。
每个子类使用一张表只存储它特有的属性,然后与父类所对应的表以一对一主键关联的方式关联起来。这种策略是使用<joined-subclass>标签来定义子类的。父类、子类都对应一张数据库表。在父类对应的数据库表中,它存储了所有记录的公共信息,实际上该父类对应的表会包含所有的记录,包括父类和子类的记录;在子类对应的数据库表中,这个表只定义了子类中所特有的属性映射的字段。子类对应的数据表与父类对应的数据表,通过一对一主键关联的方式关联起来。

三、缓存

缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。
 
缓存的介质一般是内存,所以读写速度很快。但如果缓存中存放的数据量非常大时,也会用硬盘作为缓存介质。
 
Hibernate 的缓存包括 Session 的缓存和 SessionFactory 的缓存,其中 SessionFactory 的缓存又可以分为两类:内置缓存和外置缓存。Session 的缓存是内置的,不能被卸载,也被称为 Hibernate 的第一级缓存。SessionFactory 的内置缓存和 Session 的缓存在实现方式上比较相似,前者是 SessionFactory 对象的一些集合属性包含的数据,后者是指 Session 的一些集合属性包含的数据。SessionFactory 的内置缓存中存放了映射元数据和预定义SQL语句,映射元数据是映射文件中数据的拷贝,而预定义SQL语句是在 Hibernate 初始化阶段根据映射元数据推导出来,SessionFactory 的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义SQL语句,因此 SessionFactory 不需要进行内置缓存与映射文件的同步。SessionFactory 的外置缓存是一个可配置的插件。在默认情况下,SessionFactory 不会启用这个插件。外置缓存的数据是数据库数据的拷贝,外置缓存的介质可以是内存或者硬盘。SessionFactory 的外置缓存也被称为Hibernate的第二级缓存。
 
一级缓存和二级缓存的区别:
Hibernate的一级缓存依赖于 session 的生命周期,无法卸载,只会被单个 session 所持有,一旦 session 的生命周期结束,一级缓存也就消失了,因此,一级缓存不会发生并发。
 
Hibernate的二级缓存是一个可配置的插件,为所有 session 所共同访问,因此他不适用于高并发的数据。由于二级缓存要保证数据的一致性,即数据源和缓存中数据的一致性,当频繁修改数据时,就需要不断访问数据库以保证一致性。这样缓存变得没有意义了。

四、状态

hibernate的三种状态
1、 瞬时态:刚 new 出来的一个对象,只是在内存中占据了一个空间,可被垃圾回收器回收,没有被保存到数据库,也没有与session相关联。
2、 持久态:对象被保存到数据库中,且缓存在 session 对象中,是一个持久的状态。
3、 脱离态:session 关闭了,原来 session 的缓存脱离了 session 的控制,但是又有一个数据库的记录与之相对应。但需要重新对这条记录改变时,脱离状态被重新回到持久状态。

五、其他

1、什么是SessionFactory?什么是Session?http session 和 hibernate session 有什么区别?

    SessionFactory 接口负责初始化 Hibernate。它充当数据存储源的代理,并负责创建 Session 对象。这里用到了工厂模式。需要注意的是 SessionFactory 并不是轻量级的,因为一般情况下,一个项目通常只需要一个 SessionFactory 就够,当需要操作多个数据库时,可以为每个数据库指定一个 SessionFactory 。
   在 hibernate 中的 session 并不是 http 中所说的 session,一般把 HttpSession 对象称为用户会话。
   而 hibernate 中的 Session 呢?是用来表示,应用程序和数据库的一次交互(会话)。在这个Session中,包含了一般的持久化方法(CRUD)。而且,Session 是一个轻量级对象(线程不安全),通常将每个 Session 实例和一个数据库事务绑定,也就是每执行一个数据库事务,都应该先创建一个新的 Session 实例,在使用 Session 后,还需要关闭 Session。

2、n+1问题?

一般而言说 n+1 意思是,无论在一对多还是多对一当查询出 n 条数据之后,每条数据会关联的查询1次他的关联对象,这就叫做 n+1。
下面是几种解决方案:
  • 设置 @ManyToOne 的fetch属性值为 fetchType.LAZY,这种方式解决后,后面的 n 条 sql 语句按需而发。但是有个弊端,就是如果需要级联查询就无法获取级联对象了。
  • 设置 @BatchSize(size=5)(该注解要加在类上面,跟@Entity在同一位置),这样发出的sql语句减少。这个设置在一定程度上提高了效率。
  • join fetch , 如使用"from Student s left join fetch s.group g", 进行表连接查询,此时就发1条SQL语句。
  • 使用QBC查询,默认效果与3相同:
              1、fetch="select" 会另外发出一条语句查询集合。
              2、设置 fetch="join" 采用外连接集合的 lazy 失效。
              3、这只 fetch="subselect" 另外发出一条 select 语句抓取前面查询到的所有的实体对象的关联集合 fetch只对 HQL 查询产生影响其他的则不会。

3、Hibernate中的 get 和 load 加载有什么区别?

当我们使用 session.load() 方法来加载一个对象时,此时并不会发出sql语句,当前得到的这个对象其实是一个代理对象,这个代理对象只保存了实体对象的 id 值,只有当我们要使用这个对象,得到其它属性时,这个时候才会发出 sql 语句,从数据库中去查询我们的对象。
 
相对于load的延迟加载方式,get 就直接的多,当我们使用session.get()方法来得到一个对象时,不管我们 使不使用这个对象,此时都会发出sql语句去从数据库中查询出来。

4、脏读和幻读?

脏读:是指当一个事务正在访问数据,且对数据做了修改,但是还没有提交到数据库。另一个事务查询到这个数据、这个数据就是脏数据,依靠这个数据所做的操作就是不正确的、
幻读:比如第一个事务对数据库的全部行进行了修改,同时第二个事务插入一条数据到数据库中,这时第一个事务就会发现,数据库中有一条记录没有被修改,像发生了幻觉一样、

Hibernate乐观锁、悲观锁和多态的更多相关文章

  1. 【Hibernate 9】悲观锁和乐观锁

    一.锁的基本简介 1.1,为什么需要锁 首先,锁的概念产生,主要是为了解决并发性的问题.什么是并发性问题呢,比如: Angel现在银行有个账号,里面有存款1000块.现在,Angel的账户,在两个地方 ...

  2. Java并发 行级锁/字段锁/表级锁 乐观锁/悲观锁 共享锁/排他锁 死锁

    原文地址:https://my.oschina.net/oosc/blog/1620279 前言 锁是防止在两个事务操作同一个数据源(表或行)时交互破坏数据的一种机制. 数据库采用封锁技术保证并发操作 ...

  3. 最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁

    在Java并发场景中,会涉及到各种各样的锁如公平锁,乐观锁,悲观锁等等,这篇文章介绍各种锁的分类: 公平锁/非公平锁 可重入锁 独享锁/共享锁 乐观锁/悲观锁 分段锁 自旋锁 01.乐观锁 vs 悲观 ...

  4. 乐观锁悲观锁对应的JAVA代码和数据库

    乐观锁悲观锁是一种思想.可以用在很多方面. 比如数据库方面.悲观锁就是for update乐观锁就是 version字段 JDK方面:悲观锁就是sync乐观锁就是原子类(内部使用CAS实现) 本质来说 ...

  5. AtomicInteger如何保证线程安全以及乐观锁/悲观锁的概念

    众所周知,JDK提供了AtomicInteger保证对数字的操作是线程安全的,线程安全我首先想到了synchronized和Lock,但是这种方式又有一个名字,叫做互斥锁,一次只能有一个持有锁的线程进 ...

  6. Django - ORM - 事务, 乐观锁, 悲观锁

    事务 概念 Transaction 事务:一个最小的不可再分的工作单元:通常一个事务对应一个完整的业务(例如银行账户转账业务,该业务就是一个最小的工作单元) 一个完整的业务需要批量的DML(inser ...

  7. Java中的锁-悲观锁、乐观锁,公平锁、非公平锁,互斥锁、读写锁

    总览图 如果文中内容有错误,欢迎指出,谢谢. 悲观锁.乐观锁 悲观锁.乐观锁使用场景是针对数据库操作来说的,是一种锁机制. 悲观锁(Pessimistic Lock):顾名思义,就是很悲观,每次去拿数 ...

  8. Java Hibernate中的悲观锁和乐观锁的实现

    锁(locking) 业务逻辑的实现过程中,往往需要保证数据访问的排他性.如在金融系统的日终结算 处理中,我们希望针对某个cut-off时间点的数据进行处理,而不希望在结算进行过程中 (可能是几秒种, ...

  9. Hibernate 再接触 悲观锁和乐观锁

    为什么取1248 二进制 CRUD 移位效率高 在并发和效率选择一个平衡点 一般不会考虑幻读 因为我们不会再一个事务里查询两次,(只能设置为seralizable) 悲观锁和乐观锁的前提是read-u ...

  10. 乐观锁&悲观锁

    悲观&乐观,只是对数据加锁的时机与粒度. 悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这 ...

随机推荐

  1. [SinGuLaRiTy] COCI 2011~2012 #2

    [SinGuLaRiTy-1008] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 测试题目 对于所有的题目:Time Limit:1s   ...

  2. 老李分享: 并行计算基础&编程模型与工具 2

    2.并行编程模型和工具 – MPI – MPI(Message Passing Interface)是一种消息传递编程模型,服务于进程通信.它不特指某一个对它的实现,而是一种标准和规范的代表,它是一种 ...

  3. matlab函数:residue和residuez的用法

    一.residue函数 1. 概念:在部分分式展开式和多项式系数之间转换.(Convert between partial fraction expansion and polynomialcoeff ...

  4. matlab 2016a破解中文版安装教程

    之前电脑重装过,所以要重新安装一个matlab,在大三的时候学过matlab,信息老师给的安装包,但是不知道放哪里去了,记忆力不好,找了些网上的教程和下载地址,真的是坑,一些都是不行的,在这里记录下m ...

  5. 《Python自然语言处理》第一章-练习17

    问题描述: 使用text9.index()查找词sunset的索引值.你需要将这个词作为一个参数插入到圆括号之间.通过尝试和出错的过程中,找到完整的句子中包含这个词的切片. 解题思路: 用两个集合,一 ...

  6. URL解析器urllib2

    urllib2是Python的一个库(不用下载,安装,只需要使用时导入import urllib2)它提供了一系列用于操作URL的功能. urlopen urllib2.urlopen可以接受Requ ...

  7. Linux-配置vim开发环境

    vim是一个类似于vi的著名的功能强大.高度可定制的文本编辑器,在vi的基础上改进和增加了很多特性.vim是纯粹的自由软件. 为了满足使用者的要求,将vim界面配置为自己想要的界面类型也变得流行起来. ...

  8. 安卓Native和H5页面进行交互

    安卓Native和H5页面进行交互 1.H5页面调用安卓Native界面 1)通过给webView添加JsInterface,安卓提供接口,让H5来进行调用    a)安卓写一个类,里面的方法需要用通 ...

  9. java线程控制方法

    一.中断线程 1.Thread.sleep()让线程进入睡眠状态,放弃CPU的占用暂停若干毫秒使用方法: public class runable implements Runnable { @Ove ...

  10. html渲染过程

    用户输入url地址,浏览器依据域名寻觅IP地址浏览器向服务器发送http恳求,假如服务器段回来以301之类的重定向,浏览器依据相应头中的location再次发送恳求服务器端承受恳求,处理恳求生成htm ...