hibernate3第六章之性能优化相关几个问题_1
来源:互联网 发布:深圳冰川网络 张雄 编辑:程序博客网 时间:2024/06/08 01:17
一、1+N问题,也叫N+1问题
1.问题描述如testQueryByNoLazy方法所示:
import java.util.Date;import java.util.List;import org.hibernate.*;import org.hibernate.cfg.AnnotationConfiguration; import org.hibernate.tool.hbm2ddl.SchemaExport;import org.junit.AfterClass;import org.junit.BeforeClass;import org.junit.Test;public class Modeltest {private static SessionFactory sf=null;@BeforeClasspublic static void beforeClass(){sf=new AnnotationConfiguration().configure().buildSessionFactory();}@Testpublic void testSave(){//先插入c再插入t保证每个t都关联不同的cSession session=sf.getCurrentSession();session.beginTransaction();for(int i=0;i<10;i++){Category c=new Category();c.setName("c"+i);Topic t=new Topic();t.setCategory(c);t.setTitle("t"+i);t.setCreateDate(new Date());session.save(c);session.save(t);}session.getTransaction().commit();}@Testpublic void testQueryByNoLazy(){//默认Topic中是Eager,这样取数据的话会发出11条sql语句(1条取所有t,10条取c)由于是eager的原因Session session=sf.getCurrentSession();session.beginTransaction(); List<Topic> topics=(List<Topic>)session.createQuery("from Topic").list();for(Topic t : topics){System.out.println(t.getTitle()+":"+t.getId());}session.getTransaction().commit();}@Testpublic void testQueryByLazy(){//将默认的fetch设置为Lazy,这样只会发出1条sql语句(只取t),但是如果用到其关联的c的话,用到谁的c会发1条sql语句取c。Session session=sf.getCurrentSession();session.beginTransaction(); List<Topic> topics=(List<Topic>)session.createQuery("from Topic").list();for(Topic t : topics){System.out.println(t.getTitle()+":"+t.getId()+":"+t.getCategory().getName());}session.getTransaction().commit();}@Testpublic void testQueryByCriteria(){//Criteria默认使用left join取数据 不会发那么多sql语句Session session=sf.getCurrentSession();session.beginTransaction(); List<Topic> topics=(List<Topic>)session.createCriteria(Topic.class).list();for(Topic t : topics){System.out.println(t.getTitle()+":"+t.getId()+":"+t.getCategory().getName());}session.getTransaction().commit();}@Testpublic void testQueryByJoinfetch(){//手动设置left join 也不会发出那么多sql语句Session session=sf.getCurrentSession();session.beginTransaction(); List<Topic> topics=(List<Topic>)session.createQuery("from Topic t join fetch t.category c").list();for(Topic t : topics){System.out.println(t.getTitle()+":"+t.getId()+":"+t.getCategory().getName());}session.getTransaction().commit();}@Testpublic void testQueryByBatchSize(){//这个查询和nolazy方法一样 只是在Category类上加了@BatchSize(size=5) 这样的话会发出3条sql语句(1条取t,2条取c:每一条sql语句使用id in()的形式各取出5条c)Session session=sf.getCurrentSession();session.beginTransaction(); List<Topic> topics=(List<Topic>)session.createQuery("from Topic").list();for(Topic t : topics){System.out.println(t.getTitle()+":"+t.getId()+":"+t.getCategory().getName());}session.getTransaction().commit();}@Testpublic void testSchemaExport(){new SchemaExport(new AnnotationConfiguration().configure()).create(false, true);}@AfterClasspublic static void afterClass(){sf.close();}}
import org.hibernate.annotations.BatchSize;@Entity//@BatchSize(size=5)public class Category {private int id;private String name;@Id@GeneratedValuepublic int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;} }
import java.util.ArrayList;import java.util.Date;import java.util.List; import javax.persistence.*; @Entity public class Topic {private int id;private String title;private Category category;private Date createDate; @Id@GeneratedValuepublic int getId() {return id;}public void setId(int id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}//解决方法:<span style="font-family: Arial, Helvetica, sans-serif;">@ManyToOne(fetch=FetchType.LAZY)</span>@ManyToOnepublic Category getCategory() {return category;}public void setCategory(Category category) {this.category = category;}public Date getCreateDate() {return createDate;}public void setCreateDate(Date createDate) {this.createDate = createDate;}}
二、list和iterate效率
1.list只往缓存里写,不从缓存里读;iterate先去缓存里读,再去数据库读,会先读出数据的ID,用到该数据的其他属性后才发出sql语句查询
2.load也是先查缓存;外链接不能和iterate一起使用,会报错
import java.util.Date;import java.util.Iterator;import java.util.List;import org.hibernate.*;import org.hibernate.cfg.AnnotationConfiguration; import org.hibernate.tool.hbm2ddl.SchemaExport;import org.junit.AfterClass;import org.junit.BeforeClass;import org.junit.Test;public class Modeltest {private static SessionFactory sf=null;@BeforeClasspublic static void beforeClass(){sf=new AnnotationConfiguration().configure().buildSessionFactory();}@Testpublic void testSave(){//先插入c再插入t保证每个t都关联不同的cSession session=sf.getCurrentSession();session.beginTransaction();for(int i=0;i<10;i++){Category c=new Category();c.setName("c"+i);Topic t=new Topic();t.setCategory(c);t.setTitle("t"+i);t.setCreateDate(new Date());session.save(c);session.save(t);}session.getTransaction().commit();}@Testpublic void testQueryByLazy(){//将默认的fetch设置为Lazy,这样只会发出1条sql语句(只取t),但是如果用到其关联的c的话,用到谁的c会发1条sql语句取c。Session session=sf.getCurrentSession();session.beginTransaction(); //List<Topic> topics=(List<Topic>)session.createCriteria(Topic.class).list();List<Topic> topics=(List<Topic>)session.createQuery("from Topic").list();for(Topic t : topics){System.out.println(t.getTitle()+":"+t.getId()+":"+t.getCategory().getName());}session.getTransaction().commit();} @Testpublic void testQueryByIterate(){/*如果用left join+iterate的话会报错:org.hibernate.QueryException: fetch may not be used with scroll() or iterate() [from com.wzy.model.Topic t join fetch t.category c]at org.hibernate.hql.ast.tree.FromElement.setFetch(FromElement.java:429)at org.hibernate.hql.ast.tree.FromElementFactory.createEntityJoin(FromElementFactory.java:263)at org.hibernate.hql.ast.tree.DotNode.dereferenceEntityJoin(DotNode.java:454)at org.hibernate.hql.ast.tree.DotNode.dereferenceEntity(DotNode.java:373)at org.hibernate.hql.ast.tree.DotNode.resolve(DotNode.java:232)at org.hibernate.hql.ast.tree.FromReferenceNode.resolve(FromReferenceNode.java:117)at org.hibernate.hql.ast.HqlSqlWalker.createFromJoinElement(HqlSqlWalker.java:369)at org.hibernate.hql.antlr.HqlSqlBaseWalker.joinElement(HqlSqlBaseWalker.java:3452)at org.hibernate.hql.antlr.HqlSqlBaseWalker.fromElement(HqlSqlBaseWalker.java:3239)at org.hibernate.hql.antlr.HqlSqlBaseWalker.fromElementList(HqlSqlBaseWalker.java:3112)at org.hibernate.hql.antlr.HqlSqlBaseWalker.fromClause(HqlSqlBaseWalker.java:720)at org.hibernate.hql.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:571)at org.hibernate.hql.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:288)at org.hibernate.hql.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:231)at org.hibernate.hql.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:254)at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:185)at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:136)at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:101)at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:80)at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:94)at org.hibernate.impl.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:156)at org.hibernate.impl.SessionImpl.iterate(SessionImpl.java:1215)at org.hibernate.impl.QueryImpl.iterate(QueryImpl.java:69)at com.wzy.model.Modeltest.testQueryByIterate(Modeltest.java:59)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)at java.lang.reflect.Method.invoke(Unknown Source)at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:73)at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:46)at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)at org.junit.runners.ParentRunner.run(ParentRunner.java:220)at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)*///iterate只会取出数据的Id 程序中用到其他属性值的时候会再发出sql语句取数据库中取 ,因为iterate会利用缓存list则不会//下面我取的是多的一方,由于1+N问题,会发出多条sql语句将1的一方也取出来Session session=sf.getCurrentSession();session.beginTransaction(); //Iterator<Topic> topics=(Iterator<Topic>)session.createQuery("from Topic t join fetch t.category c").iterate();Iterator<Topic> topics=(Iterator<Topic>)session.createQuery("from Topic").iterate(); while(topics.hasNext()){Topic t=topics.next();System.out.println(t.getTitle()+":"+t.getId()+":"+t.getCategory().getName());}//下面我取的是一的一方,这样就不考虑1+N问题了/*Iterator<Category> category=(Iterator<Category>)session.createQuery("from Category").iterate();while(category.hasNext()){Category c=category.next();System.out.println(c.getName());}*/session.getTransaction().commit();} @Testpublic void testQueryByList(){//听说如果用left join+iterate的话会报错 list实现iterater的接口Session session=sf.getCurrentSession();session.beginTransaction(); List<Category> categorys=(List<Category>)session.createQuery("from Category").list();for(Category c : categorys){System.out.println(c.getName());}session.getTransaction().commit();} @Testpublic void testQueryByIterate2(){Session session=sf.getCurrentSession();session.beginTransaction(); //取两遍Category sql只发一遍,从缓存中读取Iterator<Category> category=(Iterator<Category>)session.createQuery("from Category").iterate();while(category.hasNext()){Category c=category.next();System.out.println(c.getName());}Iterator<Category> category2=(Iterator<Category>)session.createQuery("from Category").iterate();while(category2.hasNext()){Category c2=category.next();System.out.println(c2.getName());}session.getTransaction().commit();} @Testpublic void testQueryByList2(){//取两遍Category sql发2遍 不读缓存,刷新缓存Session session=sf.getCurrentSession();session.beginTransaction(); List<Category> categorys=(List<Category>)session.createQuery("from Category").list();for(Category c : categorys){System.out.println(c.getName());}List<Category> categorys2=(List<Category>)session.createQuery("from Category").list();for(Category c2 : categorys){System.out.println(c2.getName());}session.getTransaction().commit();} @Testpublic void testSchemaExport(){new SchemaExport(new AnnotationConfiguration().configure()).create(false, true);}@AfterClasspublic static void afterClass(){sf.close();}}
import java.util.ArrayList;import java.util.Date;import java.util.List; import javax.persistence.*; @Entity public class Topic {private int id;private String title;private Category category;private Date createDate;@Id@GeneratedValuepublic int getId() {return id;}public void setId(int id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}@ManyToOne(fetch=FetchType.LAZY)public Category getCategory() {return category;}public void setCategory(Category category) {this.category = category;}public Date getCreateDate() {return createDate;}public void setCreateDate(Date createDate) {this.createDate = createDate;}}
import javax.persistence.*; @Entity public class Category {private int id;private String name;@Id@GeneratedValuepublic int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;} }
三、缓存
1.一级缓存:session级别缓存,跨session读不到,不用更改配置(相当局部变量)
2.二级缓存:sessionFatory级别缓存,同一个sessionFatory里夸session共享数据,夸sessionFatory读不到(相当全局变量),需要在hibernate配置文件里加上打开二级缓存的代码,并在需要缓存的实体entity上加@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)标签:
(1)二级缓存是有很多类型的:
HashTable:只是用来测试的,不能投入使用,只能用在内存里,不用于集群环境,支持三级缓存,代码为org.hibernate.cache.HashtableCacheProvider
EhCache:hibernate3.2默认Cache,内存不够的时候可以存入硬盘,不用于集群环境,支持三级缓存,代码为org.hibernate.cache.EhCacheProvider
OSCache:内存不够的时候可以存入硬盘,不用于集群环境,支持三级缓存,代码为org.hibernate.cache.OSCacheProvider
SwarmCahce:内存不够的时候可以存入硬盘,支持集群环境,不支持三级缓存,代码为org.hibernate.cache.SwarmCacheProvider
JBossCahe1.x::内存不够的时候可以存入硬盘,支持集群环境,支持三级缓存,代码为org.hibernate.cache.TreeCacheProvider
JBossCache2:内存不够的时候可以存入硬盘,支持集群环境,支持三级缓存,代码为org.hibernate.cache.jbc2.JBossCacheRegionProvider
(2)二级缓存配置文件代码(使用EhCache): 先打开二级缓存,再设置缓存类型,再加入缓存配置文件
<property name="cache.use_second_level_cache">true</property> <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>在根目录下加入ehcache.xml
3.查询缓存(三级缓存):打开query缓存,使用.setCacheable(true)
hibernate配置文件要在“二级缓存”代码后加上:<property name="cache.use_query_cache">true</property>
4.@Cache有三个参数usage一般都是READ_WRITE,region指定缓存(在ehcache配置文件中命名的cache):
@Cache( CacheConcurrencyStrategy usage(); (1) String region() default ""; (2) String include() default "all"; (3))
usage: 给定缓存的并发策略(NONE, READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL)
(2)region (可选的):缓存范围(默认为类的全限定类名或是集合的全限定角色名)
(3)include (可选的):值为all时包括了所有的属性(proterty), 为non-lazy时仅含非延迟属性(默认值为all)
import java.util.Date;import java.util.Iterator;import java.util.List;import org.hibernate.*;import org.hibernate.cfg.AnnotationConfiguration; import org.hibernate.tool.hbm2ddl.SchemaExport;import org.junit.AfterClass;import org.junit.BeforeClass;import org.junit.Test;public class Modeltest {private static SessionFactory sf=null;@BeforeClasspublic static void beforeClass(){sf=new AnnotationConfiguration().configure().buildSessionFactory();}@Testpublic void testSave(){//先插入c再插入t保证每个t都关联不同的cSession session=sf.getCurrentSession();session.beginTransaction();for(int i=0;i<10;i++){Category c=new Category();c.setName("c"+i);Topic t=new Topic();t.setCategory(c);t.setTitle("t"+i);t.setCreateDate(new Date());session.save(c);session.save(t);}session.getTransaction().commit();}@Testpublic void testQueryCache(){ //load,iterate会使用2级缓存,list会存入2级缓存,但不会从2级缓存中取值Session session=sf.getCurrentSession();session.beginTransaction(); Category c=(Category)session.load(Category.class, 1); System.out.println(c.getName()); session.getTransaction().commit();Session session2=sf.getCurrentSession();session2.beginTransaction(); Category c2=(Category)session2.load(Category.class, 1); System.out.println(c2.getName()); session2.getTransaction().commit(); } @Testpublic void testQueryCacheByList(){ //load,iterate会使用2级缓存,list会存入2级缓存,但不会从2级缓存中取值Session session=sf.getCurrentSession();session.beginTransaction(); List<Category> categories=(List<Category>)session.createQuery("from Category").setCacheable(true).list(); for(Category c:categories){System.out.println(c.getName());} session.getTransaction().commit();Session session2=sf.getCurrentSession();session2.beginTransaction(); List<Category> categories1=(List<Category>)session2.createQuery("from Category").setCacheable(true).list(); for(Category c:categories1){System.out.println(c.getName());} session2.getTransaction().commit(); } @Testpublic void testSchemaExport(){new SchemaExport(new AnnotationConfiguration().configure()).create(false, true);}@AfterClasspublic static void afterClass(){sf.close();}}
import javax.persistence.*;import org.hibernate.annotations.BatchSize;import org.hibernate.annotations.Cache;import org.hibernate.annotations.CacheConcurrencyStrategy;@Entity@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)public class Category {private int id;private String name;@Id@GeneratedValuepublic int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}}
import java.util.ArrayList;import java.util.Date;import java.util.List; import javax.persistence.*; @Entity public class Topic {private int id;private String title;private Category category;private Date createDate; @Id@GeneratedValuepublic int getId() {return id;}public void setId(int id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}@ManyToOne(fetch=FetchType.LAZY)public Category getCategory() {return category;}public void setCategory(Category category) {this.category = category;}public Date getCreateDate() {return createDate;}public void setCreateDate(Date createDate) {this.createDate = createDate;}}
- hibernate3第六章之性能优化相关几个问题_1
- hibernate3第六章之性能优化相关几个问题_2事务隔离机制
- 《高性能mysql》之查询性能优化(第六章)
- Hibernate 性能优化_1
- MapReduce性能优化_1. 性能测量
- 【性能优化】 之 HINTS 相关作业
- LINUX基础第六章笔记_1
- Spark性能优化第六季
- Spark性能优化第六季
- 精通安卓性能优化-第六章(一)
- 精通安卓性能优化-第六章(二)
- 精通安卓性能优化-第六章(三)
- Apache 性能优化相关
- Java性能优化相关
- hashCode相关性能优化
- Android 性能优化相关
- 性能优化相关
- Android性能优化相关
- 第九章 中位数和顺序统计量
- ns3中采用Linux模式启动dce的问题
- ef根据年月进行分组
- iOS开发--Advanced NSOperations
- android webview 缩放及换行 及其webview 进度条
- hibernate3第六章之性能优化相关几个问题_1
- mysql导入数据
- 映射公网(花生壳、PubYun、No-IP、DynDNS、Ngrok、Tunnel、localtunnel、pagekite)
- C++中派生类的访问控制
- NSLog打印格式控制
- 数据结构学习笔记 C++版 (一)
- RAGE的megatexture介绍
- python_面向对象
- log4j的配置