首页 > 代码库 > 性能优化(1+N,list与iterator,缓存,事务)
性能优化(1+N,list与iterator,缓存,事务)
1、注意session.clear()的运用,尤其是不断分页循环的时候
A 在一个大集合中进行遍历,取出其中含有敏感字的对象
B 另一种形式的内存泄露.
2、1+N问题
问题描述:如@ManyToOne时,两个类分别是User与Group,取User时,本想发一条SQL语句,结果顺带发了N条语句,将每个User对应的Group也查询了。
解决方法有三种:
(1)设为@ManyToOne(fetch=FetchType.LAZY)
(2)在Group类中的@Entity下面加一条@BatchSize(size=5),则每一条SQL语句可以取出5个Group对象
(3)查询语句写为“from User u left join fetch u.group g”
3、list和iterator的区别
(1)list()返回List,直接取对象;list第二次发出,仍会到数据库中查询数据
(2)iterator先取对象的主键,即ID,等到要用的时候再根据ID取出对象;iterator第二次首先查找session级缓存.
4、缓存
(1)一级缓存(session级别的缓存)
例如,同一个session中,load两次,只向数据库发一条SQL语句。但如果是两个不同session中,分别load一次,则发两条SQL语句。
(2)二级缓存(SessionFactory级别的缓存,可以跨越session级别存在)
两个不同session中,分别load一次,要想只发一条SQL语句,则需要利用二级缓存。
load默认使用二级缓存,iterator默认使用二级缓存
list默认向二级缓存添加数据,但是查询的时候不使用.
如果Query需要使用二级缓存,则打开查询缓存。
适用情况:经常被访问,改动不大,数量有限的情况,如用户权限,组织机构等。
使用方法:Hibernate不提供二级缓存的实现,由其他厂商提供(如EH,OS,Swarm,JBoss)。使用时要配置xml,导入jar包。
在相关类中需要@Entity@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
(3)查询缓存:在二级缓存设置有效时才可以使用,需要在xml中设置。相同的查询语句才能使用查询缓存。
需要调用Query setCachable(true)方法指明使用二级缓存.
5、缓存算法
LRU,LFU, FIFO
Least Recently Used 按时间
Least Frequently Userd 按命中次数
First In First Out
memoryStoreEvictionPlicy=”LRU”(ehcache)
6、事务并发
(1)ACID 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。
(2)事物并发带来的问题:
- 脏读:读了其他未提交事务B的数据,该事务B后来被回滚了
- 不可重复读:同一事务中,读了两遍,前后数据不一致。因为其他事务B更改了数据
- 幻读:同一事务中,读了两遍,前后数据不一致。因为其他事务B插入/删除了数据
(3)数据库事务隔离级别:(javax.sql.Connection)
- READ_UNCOMMITTED:允许读取改变了的还未提交的数据,可能导致脏读、不可重复读和幻读。
- READ COMMITTED(Oracle默认):允许并发事务提交之后读取,可以避免脏读,可能导致重复读和幻读。
- REPEATABLE_READ(MySQL默认):对相同字段的多次读取结果一致,可导致幻读。
- SERIALIZABLE:完全服从ACID的原则,确保不发生脏读、不可重复读和幻读。
Dirty reads non-repeatable reads phantom reads
Serializable 不会 不会 不会
REPEATABLE READ 不会 不会 会
READ COMMITTED 不会 会 会
Read Uncommitted 会 会 会
(4)一般选择READ COMMITTED,在此前提下,解决不可重复读问题(忽略幻读)有两种方式
- 悲观锁:依赖于数据库。session.load(**.class,1,LockMode.UPGRADE);相当于select...from...where...for update
- 乐观锁:与数据库无关,效率高。在类中加入private int version;属性@Version 该属性由Hibernate控制,没更新一次加1,不一致时报错。