【Hibernate】学习

【Hibernate】学习

数据库的核心是 存储数据,而 数据库框架的作用 就是为了 优化性能 和 简化使用, 通过 缓存设计 和 封装功能,实现目的。

Hibernate : 使用底层的API或Transaction对象完成轻量级框架提供一级缓存和二级缓存

Hibernate用反射机制实现持久化对象操作,实现与IDE(Integrated Development Environment)的耦合度。Hibernate使用数据库和配置信息为应用程序提供持久化服务。从配置文件中读取数据库相关参数,将持久化类和数据表对应使用。用Hibernate API对象持久化,利用映像信息将持久化操作翻译为SQL语句进行查询。

整个过程首先实现应用层和数据层。数据层保存持久化数据,应用层接收输入的数据。然后通过MVC 模式实现业务逻辑与表示层的分开。表示层和用户实现交互,业务逻辑层处理数据持久化操作。将第二阶段业务逻辑层的功能部署拆分后,业务逻辑层完成核心业务逻辑处理,持久层完成对象持久化。降低业务逻辑层复杂度的同时将数据持久化让其他组件完成。

方法选择:

a) 完成同样一件事,Hibernate提供了可供选择的一些方式,使用不同的编码方式对性能有不同的影响。比如:一次返回十万条记录,如果用 (List/Set/Bag/Map等)进行处理,很可能导致内存不够的问题,而如果用基于游标(ScrollableResults)或 Iterator的结果集,则不存在这样的问题。

b) Session的load/get方法,前者会使用二级缓存,而后者则不使用。

c) Query和list/iterator,如果去仔细研究一下它们,你可能会发现很多有意思的情况,二者主要区别(如果使用了Spring,在HibernateTemplate中对应find,iterator方法):

i. list只能利用查询缓存(但在交易系统中查询缓存作用不大),无法利用二级缓存中的单个实体,但list查出的对象会写入二级缓存,但它一般只生成较少的执行SQL语句,很多情况就是一条(无关联)。

ii. iterator则可以利用二级缓存,对于一条查询语句,它会先从数据库中找出所有符合条件的记录的ID,再通过ID去缓存找,对于缓存中没有的记录,再构造语句从数据库中查出,因此很容易知道,如果缓存中没有任何符合条件的记录,使用iterator会产生N+1条SQL语句(N为符合条件的记录数)

iii. 通过iterator,配合缓存管理API,在海量数据查询中可以很好的解决内存问题,如:

while(it.hasNext()){
  YouObject object = (YouObject)it.next();
  session.evict(youObject);
  sessionFactory.evice(YouObject.class, youObject.getId());
}

如果用list方法,很可能就出OutofMemory错误了。

hibernate延迟加载

get不支持延迟加载,load支持延迟加载。

1、hibernate2对 实体对象和集合 实现了延迟加载
2、hibernate3对 提供了属性的延迟加载功能

hibernate延迟加载就是当使用session.load(User.class,1)或者session.createQuery()查询对象或者属性的时候

这个对象或者属性并没有在内存中,只有当程序操作数据的时候,才会存在内存中,这样就实现延迟加载,节省了内存的开销,从而提高了服务器的性能。

Hibernate的缓存机制

一级缓存:session级的缓存也叫事务级的缓存,只缓存实体,生命周期和session一致。不能对其进行管理。不用显式的调用。

二级缓存:sessionFactory缓存,也叫进程级的缓存,使用第3方插件实现的,也只缓存实体,生命周期和sessionFactory一致,可以进行管理。

首先配置第3方插件,我们用的是EHCache,在hibernate.cfg.xml文件中加入

<propertyname="hibernate.cache.user_second_level_cache">true</property>

在映射中也要显式的调用,<cacheusage=”read-only”/>

二级缓存之查询缓存:对普通属性进行缓存。如果关联的表发生了修改,那么查询缓存的生命周期也结束了。

在程序中必须手动启用查询缓存:query.setCacheable(true);

优化Hibernate

1、使用一对多的双向关联,尽量从多的一端维护。
2、不要使用一对一,尽量使用多对一。
3、配置对象缓存,不要使用集合缓存。
4、表字段要少,表关联不要怕多,有二级缓存撑腰。

hibernate 类与类之间关系

关联关系  聚集关系  继承关系

Hibernate继承关系映射策略分为三种:一张表对应一整棵类继承树、一个类对应一张表、每一个具体类对应一张表。

Hibernat  的核心知识: get()  或者  load() 都返回一个对象,这个对象不是 单纯的new出来的,而是跟数据库有关系的,比如 在 get()  一个 id 为26 的product对象,但是修改其 id 为27 ,再执行 update,就会报错,肯定是数据库有某些操作在控制。

1.  Hibernate  在更新数据时:

public static void main(String[] args) {
		SessionFactory sf = getSessionFactory();
		Session s = sf.openSession();
		s.beginTransaction();
		
		Product product = (Product)s.get(Product.class, 26);
		
		product.setId(27);
		product.setName("test111");
		s.update(product);
		
		s.getTransaction().commit();
		s.close();
		sf.close();
}

通过 get 操作查询出 id 为 26 的对象,此时修改 其 name,然后 update 可以成功。

如果修改其 id 为 27 ,再执行 update 就会失败,说明 返回的 对象 跟数据库还是有关系的。

identifier of an instance of hello.pojo.Product was altered from 26 to 27

有点像是  load()  和 get() 的操作,get 返回一个实际的对象, 而 load() 返回一个 代理对象,当使用该对象的其他属性时,才会执行真正的 数据库操作(load 操作之后需要注意,不能在关闭session 之后,再使用其属性,据说为了 省性能,但我不太懂)

2. Hibernate 使用占位符:

3.x   支持的占位符方式  :    指定参数名称的    +  基于0开始 

Query q = s.createQuery("from Product p where p.name like :name");
q.setParameter("name", "%" + name +"%");
		  
Query q = s.createQuery("from Product p where p.name like 0");
q.setString(0, "%" + name +"%"); 

> 4.1   支持 的占位符方式:    指定参数名称的    +   JPA占位符

Query q = s.createQuery("from Product p where p.name like :name");
q.setParameter("name", "%" + name +"%");
		
Query q = s.createQuery("from Product p where p.name like ?0");
q.setParameter(0, "%" + name +"%");

continue…

0 0 vote
Article Rating
Subscribe
提醒
guest
0 评论
Inline Feedbacks
View all comments