Hibernate总结
Hibernate总结
一、ORM(Object Relation Mapping):对象关系映射,是一种程序技术
一、Hibernate是一种对象关系映射框架
JNDI:
3.3 分水岭 :3.3之前需要单独引入Annotationjar。
JPA 是在HIbernate作者参与的情况下完成的一个规范。
JPA是一个标准,可以看成是一个接口,旗下统领着N多个具体框架。
hibernate的基本特征是完全面向对象的程序设计语言到关系数据库的 映射,
在Hibernate中使用持久化对象PO(Persistent Object)完成持久化操作,对PO的操作必须在Session管理下才能同步到数据库,
但是这里的Session并非指HttpSession,可以 理解为基于JDBC的Connnection,
Session是Hibernate运作的中心,对象的生命周期、事务的管理、数据库的存取都与 Session息息相关,
首先,我们需要知道,SessionFactory负责创建Session,SessionFactory是线程安全的,多个并 发线程可以同时访问一个SessionFactory 并从中获取Session实例。
而Session并非线程安全,也就是说,如果多个线程同时使用一个Session实例进行数据存取,则将会导致 Session 数据存取逻辑混乱.
因此创建的Session实例必须在本地存取空上运行,使之总与当前的线程相关。 这里就需要用到ThreadLocal,在很多种Session 管理方案中都用到了它.
ThreadLocal 是Java中 一种较为特殊的线程绑定机制,通过ThreadLocal存取的数据,总是与当前线程相关,也就是说,JVM 为每个运行的线程,绑定了私有的本地实例存取空间,
从而为多线程环境常出现的并发访问问题提供了一种隔离机制,ThreadLocal并不是线程本地化的 实现,而是线程局部变量。
也就是说每个使用该变量的线程都必须为该变量提供一个副本,每个线程改变该变量的值仅仅是改变该副本的值,而不会影响其他线程的 该变量的值,ThreadLocal是隔离多个线程的数据共享,
不存在多个线程之间共享资源,因此不再需要对线程同步。
二、关于Hibernate中session的线程安全问题
session在多线程下不安全,当两个应用程序拿到同一个session对象时,就会出现脏读和死锁问题
解答:Hibernate中用openSession()打开的session是线程不安全的
Hibernate中用getCurrentSession()打开的是一个线程安全的,是获取与当前线程绑定的一个session
Hibernate中两个缓存,
sessionFactory是重量级的,线程安全,也叫一级缓存
session是轻量级的,线程不安全,也叫二级缓存
Session的使用原则就是一个线程一个session,session一次一个事务
解决session线程不安全的二种解决方案:
1.通过Threadlocal类可以把session绑定在当前线程上,
2.也可以直接通过hbm配置文件设定current_session_context_class-thread
然后通过SessionFactory.getCurrentSession()获得
以上两种解决方案有一点不同,就是用第二种方式时,当我们的事物提交后,session会自动关闭,而用第一种方式需要我们手动关session
SessionFactory:线程安全,保存了当前的数据库配置信息和所有映射关系以及预定义的SQL语句。在SessionFactory中内置了连接池。其有两个常用方法:
openSession() --从连接池中随机获取一个连接
getCurrentSession() --将Session和ThreadLocal绑定,确保在一次请求中,
只有一个Session对象。
通常一个应用只会初始化一个SessionFactory(代表一个连接池)
1、getCurrentSession()与openSession()的区别?
* 采用getCurrentSession()创建的session会绑定到当前线程中,而采用openSession()创建的session则不会
* 采用getCurrentSession()创建的session在commit或rollback时会自动关闭,而采用openSession()创建的session必须手动关闭
2、使用getCurrentSession()需要在hibernate.cfg.xml文件中加入如下配置:
* 如果使用的是本地事务(jdbc事务)
<property name="hibernate.current_session_context_class">thread</property>
* 如果使用的是全局事务(jta事务)
<property name="hibernate.current_session_context_class">jta</property>
Creates Sessions. Usually an application has a single SessionFactory. Threads servicing client requests obtain Sessions from the factory.
Implementors must be threadsafe.
SessionFactorys are immutable. The behaviour of a SessionFactory is controlled by properties supplied at configuration time. These properties are defined on Environment.
对比ThreadLocal和synchronized同步机制
相同点:
1、ThreadLocal和线程同步机制都能解决多线程中相同变量的访问冲突问题。
不同点:
1、适用的情况不同
在同步机制中,使用同步保证同一时间只有一个线程访问,不能同时访问共享资源,否则就是出现错误。ThreadLocal则隔离了相关的资源,并在同一个线程中可以共享这个资源。彼此独立,修改不会影 响到对方。
2、最终实现的效果不同
对于多线程资源共享问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
4.Transaction 代表事务
commit(); 提交事务,rollback(); 回滚事务
如果没有开启事务,那么每个Session的操作,都相当于一个独立的事务
关于load和get方法区别的说明:
Session.load/get方法均可以根据指定的实体类和id从数据库读取记录,并返回与之对应的实体对象。
其区别在于:
如果未能发现符合条件的记录,get方法返回null,而load方法会抛出一个ObjectNotFoundException。
Load方法可返回实体的代理类实例,而get方法永远直接返回实体类。
/** *//**
* get()方法的执行顺序如下:
* a):首先通过id在session缓存中查找对象,如果存在此id的对象,直接将其返回
* b):在二级缓存中查找,找到后将 其返回。
* c):如果在session缓存和二级缓存中都找不到此对象,则从数据库中加载有此ID的对象
* 因此get()方法并不总是导致SQL语句,只有缓存中无此数据时,才向数据库发送SQL!
*/
/** *//**
* 与get()的区别:
* 1:在立即加载对象(当hibernate在从数据库中取得数据组装好一个对象后
* 会立即再从数据库取得数据此对象所关联的对象)时,如果对象存在,
* load()和get()方法没有区别,都可以取得已初始化的对象;但如果当对
* 象不存在且是立即加载时,使用get()方法则返回null,而使用load()则
* 抛出一个异常。因此使用load()方法时,要确认查询的主键ID一定是存在
* 的,从这一点讲它没有get方便!
* 2:在延迟加载对象(Hibernate从数据库中取得数据组装好一个对象后,
* 不会立即再从数据库取得数据组装此对象所关联的对象,而是等到需要时,
* 都会从数据库取得数据组装此对象关联的对象)时,get()方法仍然使用
* 立即加载的方式发送SQL语句,并得到已初始化的对象,而load()方法则
* 根本不发送SQL语句,它返回一个代理对象,直到这个对象被访问时才被
* 初始化。
*/
1. Hibernate 的检索方式有哪些?
① 导航对象图检索
② OID检索
③ HQL检索
④ QBC检索
⑤ 本地SQL检索