hibernate 对象OID

它是hibernate用于区分两个对象是否是同一个对象的标识。

我们都知道,虚拟机内存区分两个对象看的是内存的地址是否一致。数据库区分两个对象,靠的是表的主键。hibernate负责把内存中的对象持久化到数据库表中,靠的就是对象标识符来区分两个对象是否是同一个。实体类中映射主键的字段就是OID  在映射文件中对应数据库主键的属性

 

 

自然主键:把具有业务含义的字段作为主键,称之为自然主键。

代理主键:把不具备业务含义的字段作为主键,称之为代理主键。该字段一般取名为“ID”,通常为整数类型,因为整数类型比字符串类型要节省更多的数据库空间。在上面例子中,显然更合理的方式是使用代理主键

 

 

1.1.1 hibernate中的一级缓存:

Hibernate的一级缓存就是指Session缓存,Session缓存是一块内存空间,用来存放相互管理的java对象,在使用Hibernate查询对象的时候,首先使用对象属性的OID值Hibernate一级缓存中进行查找如果找到匹配OID值的对象就直接将该对象从一级缓存中取出使用,再查询数据库如果没有找到相同OID值的对象则会去数据库中查找相应数据。当从数据库中查询到所需数据时,该数据信息也会放置到一级缓存中。Hibernate的一级缓存的作用就是减少对数据库的访问次数。

 

 

 

Hibernate的一级缓存有如下特点:
当应用程序调用Session接口的save()、update()、saveOrUpdate时,如果Session缓存中没有相应的对象,Hibernate就会自动的把从数据库中查询到的相应对象信息加入到一级缓存中去。
当调用Session接口的load()、get()方法,以及Query接口的list()、iterator()方法时,会判断缓存中是否存在该对象,有则返回,不会查询数据库,如果缓存中没有要查询对象,再去数据库中查询对应对象,并添加到一级缓存中。
当调用Session的close()方法时,Session缓存会被清空。

 

 

1.1.1 快照机制:

Hibernate 向一级缓存放入数据时,同时复制一份数据放入到Hibernate快照中,当使用commit()方法提交事务时,同时会清理Session的一级缓存这时会使用OID判断一级缓存中的对象和快照中的对象是否一致,如果两个对象中的属性发生变化,则执行update语句,将缓存的内容同步到数据库,并更新快照;如果一致,则不执行update语句。Hibernate快照的作用就是确保一级缓存

中的数据和数据库中的数据一致。

 

 

1、 瞬时态(transient

 

瞬时态也称为临时态或者自由态,瞬时态的实例是由new命令创建、开辟内存空间的对象,不存在持久化标识OID(相当于主键值),尚未与Hibernate Session关联,在数据库中也没有记录,失去引用后将被JVM回收。瞬时状态的对象在内存中是孤立存在的,与数据库中的数据无任何关联,仅是

一个信息携带的载体。

 

2、 持久态(persistent

 

 持久态的对象存在持久化标识OID 加入到Session缓存中,并且相关联的Session没有关闭,在数据库中有对应的记录,每条记录只对应唯一的持久化对象,需要注意的是,持久态对象是在事务还未提交前变成持久态的。

 

3、 脱管态(detached

 

脱管态也称离线态或者游离态,当某个持久化状态的实例与Session的关联被关闭时就变成了脱管态。脱管态对象存在持久化标识OID,并且仍然与数据库中的数据存在关联,只是失去了与当前Session的关联,脱管状态对象发生改变时Hibernate不能检测到。

 

 

、区分状态只有两个标识

 

一是否有OID

 

二是否和Session建立的关系

 

临时状态:

 

没有OID,和Session没有关系。

 

持久化状态:

 

OID,和Session有关系。

 

脱管状态:

 

OID,和Session没有关系。

 

 

 

 

其实最主要的是如何保证在Service中开启的事务时使用的Session对象和DAO中多个操作使用的是同一个Session对象。
其实有两种办法可以实现:
可以在业务层获取到Session,并将Session作为参数传递给DAO。
可以使用ThreadLocal将业务层获取的Session绑定到当前线程中,然后在DAO中获取Session的时候,都从当前线程中获取。

 

 

 

1.1.1.1 统计查询

/**

 * HQL使用聚合函数:

 * 统计查询

 * 聚合函数:

 *  count sum max min avg

 *

 * sql语句使用聚合函数时,在不使用group by子句的情况下,返回的结果,永远只有一行一列的情况。

 *

 * SQL语句时:

 * select count(*) from table 它是统计所有字段,效率没有只统计主键字段高

 * select count(主键) from table 它和第一个的结果是一样的,但是效率更高

 * select count(非主键) from table 只统计不为null的字段

 */

@Test

public void test1(){

Session s = HibernateUtil.getCurrentSession();

Transaction tx = s.beginTransaction();

Query query = s.createQuery("select count(lkmId) from LinkMan");//它最终仍然换转成SQL语句

// List list = query.list();

// for(Object o : list){;

// System.out.println(o);

// }

 

Long total = (Long)query.uniqueResult();//返回的是一个唯一的结果集。 只有确定结果集唯一时,才能使用

System.out.println(total);

tx.commit();

}

 

 

1.1.1.1 分页查询

/**

 * mysql的分页关键字

 * limit

 * limit的参数含义

 * 第一个:查询的开始记录索引

 * 第二个:每次查询的条数

 * hibernate中针对分页提供了两个方法

 * setFirstResult(int firstResult);设置开始记录索引

 * setMaxResults(int maxResults);设置每次查询的记录条数

 */

@Test

public void test4(){

Session s = HibernateUtil.getCurrentSession();

Transaction tx = s.beginTransaction();

//1.获取Query对象

Query query = s.createQuery("from Customer");

//2.设置分页的方法

query.setFirstResult(2);

query.setMaxResults(2);

//3.执行对象的方法,获取结果集

List list = query.list();

for(Object o : list){

System.out.println(o);

}

tx.commit();

}

 

 

HibernateCriterion对象的创建通常是通过Restrictions 工厂类完成的,它提供了条件查询方法。

通常,使用Criteria对象查询数据的主要步骤,具体如下:

1)获得HibernateSession对象。

2)通过Session获得Criteria对象。

3)使用Restrictions的静态方法创建Criterion条件对象。Restrictions类中提供了一系列用于设定查询条件的静态方法,这些静态方法都返回Criterion实例,每个Criterion实例代表一个查询条件。

4)向Criteria对象中添加Criterion 查询条件。Criteriaadd()方法用于加入查询条件。

5)执行Criteritalist() uniqueResult() 获得结果。

细节:

HQL能查的,QBC都能查,反之亦然。

了解了Criteria对象的使用步骤后,接下来,通过具体示例来演示Criteria对象的查询操作。

 

 

 

 

1.1.1.1 离线查询

 

/**

 

 * 离线条件查询

 

 * 离线:

 

 * 它是和在线对应的。

 

 * Criteria对象是一个在线对象,它是由一个可用的(活动的)Session对象获取的出来的。

 

 * session失效时,就无法再获取该对象了。

 

 *  有一个对象,它也可以用于设置条件,但是获取的时候并不需要Session对象。

 

 *  该对象就叫做离线对象:

 

 *   DetachedCriteria对象

 

 *  使用该对象进行的查询就叫做:离线查询

 

 *  

 

 *  如何获取该对象

 

 * DetachedCriteria dCriteria = DetachedCriteria.forClass(要查询的实体类字节码);

 

 *

 

 */

 

@Test

 

public void test3(){

 

//模拟一次web操作: 浏览器发送请求——调用servlet——调用service——调用dao——拿到结果到jsp上展示

 

List list = servletFindAllCustomer();

 

for(Object o : list){

 

System.out.println(o);

 

}

 

}

 

 

 

//模拟servlet

 

public List<Customer> servletFindAllCustomer(){

 

//离线对象

 

DetachedCriteria dCriteria = DetachedCriteria.forClass(Customer.class);

 

//设置条件:和Criteria是一样的

 

dCriteria.add(Restrictions.like("custName","%%"));

 

return serviceFindAllCustomer(dCriteria);

 

}

 

 

 

public List<Customer> serviceFindAllCustomer(DetachedCriteria dCriteria) {

 

 return daoFindAllCustomer(dCriteria);

 

}

 

 

 

public List<Customer> daoFindAllCustomer(DetachedCriteria dCriteria) {

 

Session s = HibernateUtil.getCurrentSession();

 

Transaction tx = s.beginTransaction();

 

//把离线对象使用可用Session激活

 

Criteria c = dCriteria.getExecutableCriteria(s);

 

List<Customer> list = c.list();

 

tx.commit();

 

return list;

 

}

 

 

 

 

1.1.1.1 统计查询

/**

  * QBC使用聚合函数

  * 统计查询

  * 涉及的对象:

  * Criteria

  * 涉及的方法:

  * setProjection(Projection p);

  * 参数的含义

  *  Projection:要添加的查询投影

  */

@Test

public void test2(){

Session s = HibernateUtil.getCurrentSession();

Transaction tx = s.beginTransaction();

//1.获取对象

Criteria c = s.createCriteria(Customer.class);//from Customer | select * from cst_customer

//2.想办法把select * 变成 select count(*)

// c.setProjection(Projections.rowCount());//select count(*)

c.setProjection(Projections.count("custId"));//select count(cust_id)

//3.获取结果集

// List list = c.list();

// for(Object o : list){

// System.out.println(o);

// }

Long total = (Long)c.uniqueResult();

System.out.println(total);

tx.commit();

}

posted @ 2018-05-12 22:54  阿善9  阅读(1879)  评论(0编辑  收藏  举报