【hibernate笔记】


HibernateTemplate和HibernateDaoSupport

参考博客:http://blog.csdn.net/qq799499343/article/details/7836473
http://blog.csdn.net/yuebinghaoyuan/article/details/7430086

HibernateTemplate

使用Hibernte操作数据库时,我们需要开启session、transaction等。一般的步骤就是先获取SessionFactory,再通过openSession()或者getCurrentSession()来获得session。
接着开启transaction,然后对数据库进行CRUD操作,在操作结束后,提交transaction,关闭session。还有,关于异常的处理,这就涉及到事务的回滚。我们发现,这样逻辑的代码我们需要反复使用,每次session的历程都是这样的。显然,当业务较多时,我们要反复的获取和关闭session,开启和提交事务。

Spring对Hibernate提供了HibernateTemple类。这个模版类对session进行封装。
并且Spring会默认为自动提交事务。

给HibernateTemplate注入SessionFactory。
public class EmployeeDaoImpl implements EmployeeDao {  
    private HibernateTemplate hibernateTemplate;  
    
    @Resource  
    public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {  
        this.hibernateTemplate = hibernateTemplate;  
    }  
    @Override  
    public void save(Employee employee) {  
        hibernateTemplate().save(employee);  
    }
}
上面的代码采用的是annotation方式,当然我们也可以使用xml方式,一样很简单。

HibernateDaoSupport

HibernateDaoSupport是Spring为Hibernate的DAO提供的帮助类。
从上面的代码我们得知,当使用DAO时就需要注入HibernateTemplate,并提供setHibernateTemplate()方法。当有多个DAO时,每个DAO都要这样干。大量的HibernateTemplate和setHibernateTemplate()方法会造成代码冗余和重复。
那么如何避免冗余呢?我们很容易想到可以抽出一个类,该类中注入了HibernateTemplate,我们的DAO直接继承这个类就可以了。而这个类Spring已经提供了,它就是HibernateDaoSupport。


Hibernate持久化对象状态和相互间的转化



Hibernate持久化对象存在三种状态

  • 瞬时态 transient  
    尚未与Hibernate Session关联对象,被认为处于瞬时状态,失去引用将被JVM回收
    无持久化标识OID,未与Session关联
  • 持久态 persistent 
    数据库中有数据与之对应并与当前session有关联,并且相关联的session没有关闭数据库并且事务未提交 
    存在持久化标识OID,与Session关联
  • 脱管态 detached 
    数据库中有数据与之对应,但当前没有session与之关联,脱管状态改变hibernate不能检测到
    存在持久化标识OID,未与Session关联
持久化对象状态转换


Hibernate的检索策略

类级别的检索策略
类级别的检索策略包括立即检索和延迟检索,默认为延迟检索。
如果程序加载一个持久化类对象的目的是为了访问它的属性,可以使用立即检索。
如果程序加一个一个持久化对象的目的仅仅是为了获得它的引用,可以使用延迟检索。
立即检索

延迟检索

一对多和多对多关联的检索策略
立即检索
延迟检索
增强延迟检索
批量延迟检索和批量立即检索
用带子查询的select语句整批量初始化orders集合
迫切做外连接检索

多对一和一对一关联的检索策略
立即检索
延迟检索
增强延迟检索
批量延迟检索和批量立即检索
用带子查询的select语句整批量初始化orders集合
迫切做外连接检索

类级别的检索策略:load、get、list

关联 

类级别的检索策略
类级别的检索策略包括立即检索和延迟检索,默认为延迟检索。
如果<class>元素的lazy属性为true,表示采用延迟检索。如果lazy属性为false,则表示立即检索。lazy属性的默认值为true。

<class name="cn.it.domain.Customer" table="customers" lazy="true">
如果程序加载持久化对象的目的是为了访问它的属性,可以采用立即检索。如果仅仅是为了获得它的引用,可以采用延迟检索。

Customer c=(Customer)session.load(Customer.class, 1);//默认延迟加载,返回代理类对象。id为1,其余值为null
c.getId();        //不会执行select语句。直接从代理对象中获取id值
c.getAge();     //执行select语句,检索数据,完成代理类实例的初始化
①假设以上采用默认的延迟加载。当执行load方法时,不会执行select语句,仅返回Customer代理类实例。该代理类是由Hibernate在运行时采用cglib工具动态生成的,它继承了Customer类的所有属性和方法,但它的实现对于应用程序是透明的。
Hibernate创建该代理类实例时,仅初始化它的OID属性,其它属性都为null。因此,这个代理类占用的内存很少。
②当访问代理类实例的getId()时,不会初始化代理类实例。因为在创建代理类实例时OID已经存在了,直接获取就行了,没必要到数据库中获取。
③访问getXXX方法时,hibernate会初始化代理类实例。在初始化过程中,会发送select语句,加载Customer对象的所有数据。

注意:无论 <class> 元素的 lazy 属性是 true 还是 false, Session 的 get()方法及 Query 的 list()方法在类级别总是使用立即检索策略

hibernate检索方式(HQL和QBC和QBE)

HQL和QBC和QBE
QBC:Query By Critical
QBE:Query By Example

hibernate的QBE和QBC

Session对象提供了两个方法可以获得Query对象
Query createQuery(String queryString)  接受HQL
SQLQuery createSQLQuery(String queryString)  接受SQL

HQL:Hibernate Query Language
Query query = session.createQuery("from Customer"); //这里Customer是类名

SQL:Structured Query Language
Query query = session.createSQLQuery("select * from customer"); //这里参数就是普通SQL语句 


HQL查询结果会自动封装为Java对象
Query query=session.createQuery("from Customer");
List<Customer> list=query.list();


hibernate检索方式
1)导航对象图检索方式: 根据已经加载的对象导航到其他对象----Customer c = session.get(Customer.class,1);c.getOrders();
2)OID 检索方式:  按照对象的 OID 来检索对象-----get/load
3)HQL 检索方式: 使用面向对象的 HQL 查询语言----Query query = session.createQuery(hql);
4)QBC 检索方式: 使用 QBC(Query By Criteria) API 来检索对象. 这种 API 封装了基于字符串形式的查询语句, 提供了更加面向对象的查询接口.

5)本地 SQL 检索方式: 使用本地数据库的 SQL 查询语句----SQLQuery query = session.createSQLQuery(sql);


hibernate主键生成策略


  • increment:自增,由hibernate框架发出SELECT MAX(id) FROM XX获取当前id的最大值,加1,有线程安全问题,适用于所有数据库

  • identity:主键自增,基于数据库底层的自增机制,没有线程安全问题,不支持所有的数据库,MySQL DB2可以使用,Oracle不能使用
  • sequence:序列,基于数据库底层的序列机制实现自增,没有线程安全问题。
    不支持所有的数据库,Oracle DB2可以使用,MySQL不能使用

  • native:本地策略,由hibernate框架自动选择使用identity或者sequence
    由于 native 能根据底层数据库系统的类型, 自动选择合适的标识符生成器, 因此很适合于跨数据库平台开发.
    OID 必须为 long, int 或 short 类型, 如果把 OID 定义为 byte 类型, 在运行时会抛出异常
  • uuid:随机的32位字符串
    (这种策略并不流行,因为字符串类型的主键比整数类型的主键占用更多的数据库空间)

  • assigned:委派,有应用程序指定主键的值


Hibernate的N+1问题  

【问题】什么时候会遇到N+1的问题?

【备注】 Hibernate默认抓取策略是fetch="select",不是fetch="join",这都是为了延迟加载而准备的。

【出现情况】
         1)一对多(one-to-many) ,在1的这方,通过1条sql查找得到了1个对象,由于关联的存在 ,那么又需要将这个对象关联的集合取出,所以合集数量是n还要发出n条sql,于是本来的1条sql查询变成了    1 +n条 。
         2)多对一<many-to-one>  ,在多的这方,通过1条sql查询得到了n个对象,由于关联的存在,也会将这n个对象对应的1 方的对象取出, 于是本来的1条sql查询变成了1 +n条 。
         3)iterator 查询时,一定先去缓存中找(1条sql查集合,只查出ID),在没命中时,会再按ID到库中逐一查找, 产生1+n条SQL。

【解决办法】
          1)lazy=true, hibernate3开始已经默认是lazy=true了;lazy=true时不会立刻查询关联对象,只有当需要关联对象(访问其属性,非id字段)时才会发生查询动作。
          2)使用二级缓存, 二级缓存的应用将不怕1+N 问题,因为即使第一次查询很慢(未命中),以后查询直接缓存命中也是很快的。刚好又利用了1+N 。
          3 ) 当然你也可以设定fetch="join",一次关联表全查出来,但失去了延迟加载的特性。

转载于:https://my.oschina.net/javandroid/blog/878197

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值