Hibernate核心开发接口介绍

Hibernate 核心接口 三种对象状态 四种操作方法

1 Configuration

一个Configuration的实例允许应用指定在创建一个SessionFactory时使用的属性和映射文件,通常一个应用将创建一个单独的Configuration,构建一个SessionFactory的单一实例然后实例化会话线程用于服务客户请求。Configuration仅仅是作为一个初始化时的对象,一个Configeration 实例代表Hibernate 所有Java类到Sql数据库映射的集合。

Configuration主要用于产生SessionFactory,进行配置信息的管理,可以在configure方法中指定hibernate文件。

在Hibernate 4之前的版本中,Configuration是通过下述方式产生SessionFactory的:

SessionFactory sf=new AnnotationConfiguration().configure().buildSessionFactory();

Hibernate 4以后,Configuration的buildSessionFactory方法被标记为过时,官方建议使用buildSessionFactory(ServiceRegistry sr)这个方法来获取SessionFactory。

Configuration configuration = new Configuration().configure();
ServiceRegistry sr=new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
SessionFactory sessionFactory = configuration.buildSessionFactory(sr);

  1. AnnotationConfiguration
  2. 进行配置信息管理
  3. 用来产生SessionFactory
  4. 可以在configure方法在指定hibernate配置文件
  5. 只需要关注一个方法:buildSessionFactory

2 SessionFactory

SessionFactory的主要作用是产生和管理Session,通常情况下每一个应用只需要一个SessionFactory,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。

一个SessionFactory的内部状态是不可变的,一旦创建了这个内部状态的内部设置便不再与Configuration对象关联,这种状态包括所有关于对象/关系映射数据。

SessionFactory在Hibernate中起到一个缓冲区的作用,它缓冲了Hibernate自动生成的SQL语句和一些其他的映射数据。

SessionFactory可以通过两种方法getCurrentSession()和openSession()产生Session,两种方法的区别有:

1、openSession每次打开都是新的Session,并且需要人为的调用close方法关闭Session。

2、getCurrentSession是从当前上下文中获取Session并且会绑定到当前线程,第一次调用会自动创建一个Session实例,如果未手动关闭多次获取的是同一个Session,事物提交或者回滚时会自动关闭Session。

3、使用getCurrentSession时,需要在配置文件中添加如下:

(1)如果使用的是本地事务(JDBC事务)

<property name="current_session_context_class">thread</property>

(2)如果使用的是全局事务(JTA事务)

<property name="current_session_context_class">jta</property>

备注:

全局事务:资源管理器管理和协调的事务,可以跨越多个数据库和进程。资源管理器一般使用XA 二阶段提交协议与“企业信息系统”(EIS) 或数据库进行交互。   

本地事务:在单个 EIS或数据库的本地并且限制在单个进程内的事务。本地事务不涉及多个数据来源。

使用getCurrentSession()方法时,如果未配置上述属性,则会报错:

Hibernate核心开发接口介绍

3 Session

Session用于管理一个数据库的任务单元(增、删、改、查),它是Java应用和Hibernate之间主要运行接口,是抽象持久性服务概念的主要API。

Session的生命周期是以一个逻辑事物的开始和结束为边界,Session的主要功能是提供创建、读取和删除映射的实体类的操作,实体可能存在于三种状态:

1、瞬时状态(transient)

即为普通的Java对象,此状态下,不与Session实例关联,在数据库中没有和瞬时对象关联的数据

2、持久状态(persistent)

处于此状态的实例在数据库中对应的记录,并拥有一个持久化标识。持久状态的对象总是与Session和Transaction相关联,在一个Session中,对持久对象的改变不会马上对数据库进行变更,而是发生在Transaction终止,执行commit之后。

3、游离状态(detached)

与持久状态的对象关联的Session被关闭后,该对象就变成游离状态,此状态下对游离对象的引用依然有效,也可以继续被修改。

这三种状态之间可以相互转换,如下图示:

Hibernate核心开发接口介绍

Session中有一个缓存,被称为hibernate的第一季缓存,它存放被当前工作单元加载的对象,这块缓存中有一map,在执行save方法后,会生成一个id,这个id会保存在map的key中,与之对应的value值就是该是该对象的引用,执行commit()方法后,数据库就有对应这条数据了,此时该实体处于持久化状态,当执行完Session.close()后,处于托管状态。

区分这三种状态的关键在于:

  1. 有没有ID
  2. ID在数据库中有没有
  3. 在内存中没有

瞬时状态下,为内存中一个对象没有ID,缓存中也没有

持久化状态,内存有,缓存中有,数据库中也存在

托管状态:内存中有,缓存中没有,数据库中存在ID

4 操作方法

Session接口有几个重要的方法:

save():持久化给出的瞬时状态的实体,并分配有一个ID标识符(在事务里执行到save,会向数据库插一条数据,如果事务里异常,会回滚,删除数据库中插入的数据)

delete():从数据库中删除持久化实体

load():返回给定标识符的实体类的持久化实例(假定实例存在),不能使用该方法来确定一个实例是否存在(使用get方法)

get():返回给定标识符的实体类的持久化实例或null(如果实例不存在)

get()和load()方法的区别:

1、当对应记录不存在时,使用load方法会报异常,而get方法会返回null

2、load返回的是代理对象,等到真正用到对象的内容时才发出sql语句,而get直接从数据库加载,不会延迟

update():更新指定标识符的托管状态实例为持久化状态,如果存在具有相同标识符的持久化实例,将会报异常。

saveOrUpdate()这个方法是更新或者插入,有主键就执行更新,如果没有主键就执行插入。

区别:对于一个从游离状态到瞬态的对象(对于一个从数据库中取出来又被删除的对象),这个对象本身是有主键的,但是因为被删除了,所以这个时候因为数据库中已经没有了这条记录了。不过它还有主键存在,所以这个时候不可以使用update()或者是saveOrUpdate(),因为update()方法是认为数据库中肯定有这条记录的,而saveOrUpdate的执行过程就是先查看这个对象是不是有主键,有主键那么就执行update()方法,没有主键就执行save()方法,因此结果跟调用了update()方法的效果是一样的,结果就会出错,因为这个对象已经被删除了,数据库中已经没有这条记录了,只是它还有主键而已(仅仅是存在于内存中),因此这个时候要执行的是save()方法

 

Clear方法 无论是load还是get 都会首先查找缓存(一级缓存),如果没有,才会从数据库查找,调用clear()方法可以强制清除session缓存(把缓冲区内的全部对象清除,但不包括操作中的对象)

Session.Commit() 这个方法它自动调用了close()和flush()方法

调用flush()可以强制从内存到数据库的同步

evict() 会把指定的缓冲对象进行清除

persist() 在事务里执行到persist,不会向数据库插数据,事务commit了才会插入数据

 

5 Transaction

Hibernate的Transaction是底层的JDBC Transaction或者JTA Transaction的封装,具体取决于在hibernate.properties中的配置。

一个典型的事务在创建完Session对象后即使用beginTransaction()启动事务,从此开始知道commit()之间的代码都会处于同一个事务中,这两个函数之间的所有的数据库代码都会在commit()执行时一次性提交,在提交时如果某一句代码执行出现异常,就会回滚这一次事务之间的所有执行代码。

6 Query

通过SessionFactory获得了session对象后,除了可以通过get(类名.class, id)方法得到相应的对象,还可以通过获得Query对象来取得需要的对象:

Query query = session.createQuery("查询语句如from UserBean");
List list = query.list();//得到一个集合
query.uniqueResult();//得到一个单个的对象

分页查询:

query.setFirstResult(位置);//表示从哪个位置开始查询,返回query对象
query.setMaxResult(记录条数);//表示当页共几条记录,返回一个集合
session.createQuery("select count(*) from 类名").uniqueResult();//得到记录总数

查询语句同sql查询语句很相像,只是将表名换作类名,字段名换作属性名,如果查询需要条件可以使用占位符来替换对应的属性名,也可以使用:变量名来作为占位符。