1,降低访问数据库的频率,减少select语句的数目,实现手段有:使用迫切左外连接或迫切内连接;对延迟检索或立即检索设置批量检索数目;使用查询缓存。
2,避免加载多余的应用程序不需要访问的数据,实现手段有:使用延迟加载策略;使用集合过滤。
3,避免报表查询数据占用缓存,实现手段为利用投影查询功能,查询出实体的部分属性。
4,减少select语句中的字段,从而降低访问数据库的数据量,实现手段为利用Query的iterate()方法。
Query的iterate()方法首先检索ID字段,然后根据ID字段到hibernate的第一级缓存以及第二级缓存中查找匹配的 Customer对象,如果存在,就直接把它加入到查询结果集中,否则就执行额外的select语句,根据ID字段到数据库中检索该对象。
Query query = session.createQuery("from Customer where age<30");
Iterator result = query.iterate();
对于经常使用的查询语句,如果启用了查询缓存,当第一次执行查询语句时,hibernate会把查询结果存放在第二级缓存中,以后再次执行该查询语句时,只需从缓存中获得查询结果,从而提高查询性能。如果查询结果中包含实体,第二级缓存只会存放实体的OID,而对于投影查询,第二级缓存会存放所有的数据值。
查询缓存适用于以下场合:在应用程序运行时经常使用的查询语句;很少对与查询语句关联的数据库数据进行插入,删除,更新操作。
对查询语句启用查询缓存的步骤如下:
1,配置第二级缓存。
2,在hibernate的配置文件中设置查询缓存属性:hibernate.cache.use_query_cache=true
3,即使设置了缓存,在执行查询语句时仍然不会启用查询缓存,只有在调用query.setCacheable()后才启用缓存:
Query query = session.createQuery("from Customer c where c.age > :age");
query.setInteger("age", age):
query.setCacheable(true);
如果希望更加精粒度地控制查询缓存,可以设置缓存区域:query.setCacheRegion("customerQueries");
hibernate提供了3种和查询相关的缓存区域:
1,默认的查询缓存区域:net.sf.hibernate.cache.StandardQueryCache。
2,用户自定义的查询缓存区域:如customerQueries。
3,时间戳缓存区域:net.sf.hibernate.cache.UpdateTimestampCache。
默认的查询缓存区域以及用户自定义的查询缓存区域都用于存放查询结果,而时间戳缓存区域存放了对于查询结果相关的表进行插入,更新,删除操作的时间戳。hibernate通过时间戳缓存区域来判断被缓存的查询结果是否过期。当应用进程对数据库的相关数据做了修改,hibernate会自动刷新缓存的查询结果。但是如果其它应用进程对数据库的相关数据做了修改,hibernate无法监测到这一变化,此时必须由应用程序负责监测这一变化(如通过发送和接收事件或消息机制),然后手工刷新查询结果。
Query.setForceCacheRefresh(true)方法允许手工刷新查询结果,它使得hibernate丢弃查询缓存区域中己有的查询结果,重新到数据库中查询数据,再把查询结果存放在查询缓存区域中。
一个session可以和多个事务对应:
Transaction trans1 = session.beginTransaction();
... ...//数据库操作
trans1.commit();//提交第一个事务
session.disconnect();//释放数据库连接
... ...//执行一些耗时的操作,这段操作不属于任何事务
session.reconnect();//重新获取数据库连接
Transaction trans2 = session.beginTransaction();//开始第二个事务
... ...//数据库操作
trans2.commit();//提交第二个事务
注意:如果在执行session的一个事务时出现了异常,就必须立即关闭这个session,不能再利用这个session来执行其它的事务。
许多数据库系统都有自动管理锁的功能,它们能根据事务执行的SQL语句,自动在保证事务间的隔离性与保证事务间的并发性之间做出权衡,然后自动为数据库资源加上适当的锁,在运行期间还会自动升级锁的类型,以优化系统的性能。
对于普通的并发性事务,通过系统的自动锁定管理机制基本可以保证事务之间的隔离性,但如果对数据安全,数据库完整性和一致性有特殊要求,也可以由事务本身来控制对数据资源的锁定和解锁。
数据库系统能够锁定的资源包括:数据库,表,区域,页面,键值(指带有索引的行数据),行(即表中的单行数据)。在数据库系统中,一般都支持锁升级,以提高性能。
按照封锁程序,锁可以分为:共享锁,独占锁,更新锁。
共享锁:用于读数据操作,它是非独占的,允许其它事务同时读取其锁定的资源,但不允许其它事务更新它。
独占锁:也称排它锁,适用于修改数据的场合,它所销定的资源,其它事务不能读取也不能修改。
更新锁:在更新操作的初始化阶段用来锁定可能要被修改的资源,这可以避免使用共享锁造成的死锁现象。
许多的数据库系统能够自动定期搜索和处理死锁问题,当检测到锁定请求环时,系统将结束死锁优先级最低的事务,并且撤销该事务。
应用程序中可以采用下面的一些方法尽量避免死锁:
1,合理安排表访问顺序;
2,使用短事务;
3,如果对数据的一致性要求不高,可以允许脏读,脏读不需要对数据资源加锁,可以避免冲突;
4,如果可能的话,错开多个事务访问相同数据资源的时间,以防止锁冲突。
5,使用尽可能低的事务隔离级别。
为了实现短事务,在应用程序中可以考虑使用以下策略:
1,如果可能的话,尝试把大的事务分解为多个小的事务,然后分别执行,这保证每个小事务都很快完成,不会对数据资源锁定很长时间。
2,应该在处理事务之前就准备好用户必须提供的数据,不应该在执行事务过程中,停下来长时间等待输入数据。
数据库系统提供了四种事务隔离级别供用户选择:
1,Serializable:串行化。
2,Repeatable Read:可重复读。
3,Read Commited:读己提交数据。
4,Read Uncommited:读未提交数据。
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先把数据库系统的隔离级别设为 ReadCommited,它能够避免脏读,而且具有较好的并发性能,尽管它会导致不可重复读,虚读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制
联系客服