135 Hibernate一级缓存.docx

上传人:b****8 文档编号:10038380 上传时间:2023-02-08 格式:DOCX 页数:8 大小:17.75KB
下载 相关 举报
135 Hibernate一级缓存.docx_第1页
第1页 / 共8页
135 Hibernate一级缓存.docx_第2页
第2页 / 共8页
135 Hibernate一级缓存.docx_第3页
第3页 / 共8页
135 Hibernate一级缓存.docx_第4页
第4页 / 共8页
135 Hibernate一级缓存.docx_第5页
第5页 / 共8页
点击查看更多>>
下载资源
资源描述

135 Hibernate一级缓存.docx

《135 Hibernate一级缓存.docx》由会员分享,可在线阅读,更多相关《135 Hibernate一级缓存.docx(8页珍藏版)》请在冰豆网上搜索。

135 Hibernate一级缓存.docx

135Hibernate一级缓存

13.5 Hibernate一级缓存

缓存(Cache)是计算机领域非常通用的概念。

它介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能。

缓存中的数据是数据存储源中数据的副本,应用程序在运行时直接读写缓存中的数据,只在某些特定时刻按照缓存中的数据来同步更新数据存储源。

技术要点

正确使用缓存,可以大幅度提高系统的性能,但是错误使用缓存,反而会造成意想不到的结果,所以,理解Hibernate的缓存机制非常重要。

Hibernate的缓存按照作用范围可以分为一级缓存和二级缓存,本节介绍一级缓存。

Hibernate的一级缓存是由Session提供的,因此它只存在于Session的生命周期中,当程序调用save()、update()、saveorupdate()等方法,及调用查询接口list、filter、iterate时,如session缓存中还不存在相应的对象,Hibernate会把该对象加入到一级缓存中,当Session关闭时,该Session所管理的一级缓存也会立即被清除。

注意:

Hibernate的一级缓存是Session所内置的,不能被卸载,也不能进行任何配置。

一级缓存采用的是keyvalue的Map方式来实现的,在缓存实体对象时,对象的主关键字ID是Map的key,实体对象就是对应的值。

所以说,一级缓存是以实体对象为单位进行存储的,在访问时使用的是主关键字ID,虽然,Hibernate对一级缓存使用的是自动维护的功能,没有提供任何配置功能,但是可以通过Session中所提供的方法来对一级缓存的管理进行手工干预。

本节代码演示Hibernate如下知识点:

使用Hibernate一级缓存。

了解Session使用缓存的常见方法。

理解Session的load方法和get方法的区别。

使用Log4j日志查看SQL执行情况。

实现代码

为了查看Hibernate如何访问数据库表,需要使用Log4j日志,读者可以将Hibernate安装包中project\etc目录下的log4j.properties属性文件复制到项目路径中,默认的log4j.properties文件会造成大量的调试信息,这里对该属性文件进行了修改,只显示SQL访问信息,便于查看。

log4j.properties文件内容代码如下:

###定义标准输出###

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.Target=System.out

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE}%5p%c{1}:

%L%m%n

###定义日志文件hibernate.log###

#log4j.appender.file=org.apache.log4j.FileAppender

#log4j.appender.file.File=hibernate.log

#log4j.appender.file.layout=org.apache.log4j.PatternLayout

#log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE}%5p%c{1}:

%L%m%n

###设置日志优先级###

#log4j.rootLogger=warn,stdout

log4j.rootLogger=debug,stdout

#log4j.logger.org.hibernate=info

log4j.logger.org.hibernate=warn

###logHQLqueryparseractivity

#log4j.logger.org.hibernate.hql.ast.AST=debug

###logjusttheSQL显示SQL信息

log4j.logger.org.hibernate.SQL=debug

###logJDBCbindparameters###

#log4j.logger.org.hibernate.type=info

log4j.logger.org.hibernate.type=warn

###logschemaexport/update###

log4j.logger.org.hibernate.tool.hbm2ddl=warn

###logHQLparsetrees

log4j.logger.org.hibernate.hql=debug

###logcacheactivity###显示Hibernate缓存信息

log4j.logger.org.hibernate.cache=debug

###logtransactionactivity

log4j.logger.org.hibernate.transaction=warn

###logJDBCresourceacquisition

log4j.logger.org.hibernate.jdbc=warn

注意:

Log4j的类库必须在CLASSPATH路径或者是项目的lib路径下,才能正常运行,默认的Hibernate类库已经包含了Log4j类库。

增加1个Hibernate一级缓存的测试类:

SessionCache.java,内容如下:

packagehelloworld.session.test;

importorg.hibernate.Session;

importorg.hibernate.SessionFactory;

importorg.hibernate.cfg.Configuration;

publicclassSessionCache{

publicstaticvoidmain(String[]args){

//Configuration管理Hibernate配置

Configurationconfig=newConfiguration().configure();

//根据Configuration建立SessionFactory

//SessionFactory用来建立Session

SessionFactorysessionFactory=config.buildSessionFactory();

//建立session,相当于建立JDBC的Connection

Sessionsession=sessionFactory.openSession();

//同一个session中建立2个实体对象

Boxbox1=(Box)session.get(Box.class,newInteger

(1));

//box2使用了session缓存,并重新没有访问数据库

Boxbox2=(Box)session.get(Box.class,newInteger

(1));

session.close();//session关闭,session缓存随即清除

System.out.println("第一个session关闭");

session=sessionFactory.openSession();//重新建立session

System.out.println("创建第二个session");

box1=(Box)session.get(Box.class,newInteger

(1));//重新访问数据库

session.clear();//清除session缓存

box2=(Box)session.get(Box.class,newInteger

(1));

session.close();

sessionFactory.close();//关闭sessionFactory

运行该示例,结果如下:

14:

12:

42,734DEBUGSQL:

346selectbox0_.idasid0_0_,box0_.widthaswidth0_0_,box0_.lengthas

length0_0_,box0_.heightasheight0_0_,box0_.nameasname0_0_fromssh.boxbox0_wherebox0_.id=?

第一个session关闭

创建第二个session

14:

12:

42,796DEBUGSQL:

346selectbox0_.idasid0_0_,box0_.widthaswidth0_0_,box0_.lengthas

length0_0_,box0_.heightasheight0_0_,box0_.nameasname0_0_fromssh.boxbox0_wherebox0_.id=?

14:

12:

42,843DEBUGSQL:

346selectbox0_.idasid0_0_,box0_.widthaswidth0_0_,box0_.lengthas

length0_0_,box0_.heightasheight0_0_,box0_.nameasname0_0_fromssh.boxbox0_wherebox0_.id=?

上面测试代码获得对象使用了session的get方法,下面将get方法替换为load方法,测试类为SessionCacheLoad.java,内容如下:

packagehelloworld.session.test;

importorg.hibernate.Session;

importorg.hibernate.SessionFactory;

importorg.hibernate.cfg.Configuration;

publicclassSessionCacheLoad{

publicstaticvoidmain(String[]args){

//Configuration管理Hibernate配置

Configurationconfig=newConfiguration().configure();

//根据Configuration建立SessionFactory

//SessionFactory用来建立Session

SessionFactorysessionFactory=config.buildSessionFactory();

//建立session,相当于建立JDBC的Connection

Sessionsession=sessionFactory.openSession();

//同一个session中建立2个实体对象

Boxbox1=(Box)session.get(Box.class,newInteger

(1));

System.out.println("第一个box");

//box2使用了session缓存,并重新没有访问数据库

Boxbox2=(Box)session.get(Box.class,newInteger

(1));

System.out.println("第二个box");

session.close();//session关闭,session缓存随即清除

session=sessionFactory.openSession();

System.out.println("创建第二个session");

box1=(Box)session.load(Box.class,newInteger

(1));//重新访问数据库

System.out.println("第一个box");

box1.getName();

box2=(Box)session.load(Box.class,newInteger

(1));

System.out.println("第二个box");

box2.getName();

session.close();

sessionFactory.close();//关闭sessionFactory

运行该测试程序,结果如下:

14:

25:

04,750DEBUGSQL:

346selectbox0_.idasid0_0_,box0_.widthaswidth0_0_,box0_.lengthas

length0_0_,box0_.heightasheight0_0_,box0_.nameasname0_0_fromssh.boxbox0_wherebox0_.id=?

第一个box

第二个box

创建第二个session

第一个box

14:

25:

04,906DEBUGSQL:

346selectbox0_.idasid0_0_,box0_.widthaswidth0_0_,box0_.lengthaslength0_0_,box0_.heightasheight0_0_,box0_.nameasname0_0_fromssh.boxbox0_wherebox0_.id=?

第二个box

源程序解读

(1)为了查看Hibernate对数据库的访问情况,使用了Log4j日志,log4j.properties属性文件中,设置log4j.logger.org.hibernate.SQL=debug,即可输出SQL语句信息,本例中,同时会输出hql和cache信息,但是本例并没有配置Hibernate的二级缓存,所以不会有cache信息输出。

(2)第一个测试程序中的第一个session中,有2个ID都是1的box对象,从控制台的日志可以看到,这个session只访问一次数据库。

第一个box对象的数据是从数据库中查询而来的,然后该对象就保存在session的缓存中,当第二个box对象调用get方法时,首先检查session缓存中是否有ID为1的对象,如果有,就从缓存中获得数据,并不会再次访问数据库。

(3)第二个session中,不同的是加入了clear方法,即将session缓存数据清空,这样在创建第二个box对象时,由于缓存中找不到该对象,则会再次使用SQL通过JDBC查询数据库获得数据。

(4)第二个测试程序帮助我们来区分load和get方法之间的区别。

(5)使用get方法获得持久化对象时,首先查找session缓存(Hibernate一级缓存)是否有该对象,如果有,则获得该对象;如果没有,就会访问数据库,如果数据库中找不到数据,则返回null。

(6)load方法也是获得数据,但是不同的地方是load方法已经假定数据库中一定存在该数据的,如果在数据库中找不到该数据,则会抛出一个org.hibernate.ObjectNotFoundException异常。

(7)load方法获得对象的过程:

load方法首先在session缓存中查找对象,如果找不到则查找sessionfactory缓存(Hibernate二级缓存),如果再找不到则访问数据库。

(8)值得注意的是,load方法是假定数据库中一定有该数据的,所以使用代理来延迟加载对象,只有在程序中使用到了该对象的属性(非主键属性)时,Hibernate才会进入load方法的获得对象过程。

所以说,如果数据库中不存在该记录,异常是在程序访问该对象属性时抛出的,而不是在创建这个对象时就抛出。

(9)第二个程序中的第二个session中可以看到,只有在访问box对象的name属性时才执行数据库查询的,而不是在创建box1时执行。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 农林牧渔 > 林学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1