设计思想Q?br /> 使用WebLogic的数据库q接池,而不是Hibernate自带的连接池?br /> Hibernate的SessionFactory配置到Weblogic JNDI目录树下?br /> 在SessionBean中直接调用Hibernate的实体访问数据库
准备条gQ?br />1、安装以下Y?都可以免费下载?
1.1 Mysql 4.0.21 c:\mysql
创徏数据库study,创徏数据表cat
1.2 mysql-connector-java-3.0.15-ga.zip mysql驱动E序
1.3 Weblogic platform 8.1 c:\bea
Weblogic配置完成Q域mydomain和服务器myserverQ数据池studyjndi,数据源名Umysqldatasource
1.4 Hibernate 2.1.2
参考其它文编写一个hibernate的实例cat,~写Cat.hbm.xml和hibernate.cfg.xml文gQ了解hibernate的基本配|?br /> 注意数据库的差异?/p>
2.创徏目录l构
C:\Test\lib hibernate解压后lib目录下的全部文g拯到此
C:\Test\src\com\chenm 源代码存攑֜(*.java)
C:\Test\classes hibernate的配|文?hibernate.properties,log4j.properties,cache.ccf)
C:\Test\classes\com\chenm ~译好的代码(*.class) + Cat.hbm.xml + hibernate.cfg.xml
步骤1:配置hibernate的环境目录到Weblogic的CLASSPATH中?br /> 修改Weblogic启动脚本C:\bea\user_projects\domains\mydomain\startweblogic.cmdQ在@REM Call WebLogic Server前加?br /> @rem set hibernate classpath
set HIBERNATE_LIB=C:\Test\lib
set HIBERNATE_CLASSES=C:\Test\classes
SET CLASSPATH=%HIBERNATE_LIB%\cglib-2.0-rc2.jar;%HIBERNATE_LIB%\commons-collections-2.1.jar;%HIBERNATE_LIB%\commons-lang-1.0.1.jar;%HIBERNATE_LIB%\commons-logging-1.0.3.jar;%HIBERNATE_LIB%\dom4j-1.4.jar;%HIBERNATE_LIB%\hibernate2.jar;%HIBERNATE_LIB%\jcs-1.0-dev.jar;%HIBERNATE_LIB%\log4j-1.2.8.jar;%HIBERNATE_LIB%\odmg-3.0.jar;%HIBERNATE_CLASSES%;%CLASSPATH%
步骤2:修改hibernat.properties文g
2.1 修改以下内容
注释掉mysql~省数据库连?br /> ## HypersonicSQL
#hibernate.dialect net.sf.hibernate.dialect.HSQLDialect
#hibernate.connection.driver_class org.hsqldb.jdbcDriver
#hibernate.connection.username sa
#hibernate.connection.password
#hibernate.connection.url jdbc:hsqldb:hsql://localhost
#hibernate.connection.url jdbc:hsqldb:test
#hibernate.connection.url jdbc:hsqldb:.
使用mysql数据?br /> ## MySQL
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect
#hibernate.connection.driver_class org.gjt.mm.mysql.Driver
hibernate.connection.driver_class com.mysql.jdbc.Driver
hibernate.connection.url jdbc:mysql://localhost:3306/study
hibernate.connection.username test
hibernate.connection.password weblogic
调整数据库查询和插入的性能参数
修改hibernate.jdbc.fetch_size 50
修改hibernate.jdbc.batch_size 25
调整Transaction API
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory
?br /> hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory
使用JCS~存
hibernate.transaction.manager_lookup_class net.sf.hibernate.transaction.WeblogicTransactionManagerLookup
2.2 在文件尾增加以下内容
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.datasource studyjndi // 此处为weblogic的数据连接池JNDI名称
hibernate.connection.provider_class net.sf.hibernate.connection.DatasourceConnectionProvider
hibernate.session_factory_name hibernate.session_factory // l定到weblogic JNDI目录树中的名U?/p>
步骤3. 实现SessionFactory的预创徏Q用Weblogic的T3StartUpDef接口创徏一个StartUpc,配置成Weblogic
启动时自动运行?br />3.1 创徏文gHibernateStartUp.java,q编译成C:\Test\classes\com\chenm\HibernateStartUp.class文gQ?br />package com.chenm;
import java.util.Hashtable;
import weblogic.common.T3StartupDef;
import weblogic.common.T3ServicesDef;
import net.sf.hibernate.cfg.Configuration;
import net.sf.hibernate.SessionFactory;
public class HibernateStartUp implements T3StartupDef {
public void setServices(T3ServicesDef services) {}
public String startup(String name,Hashtable args) throws Exception {
Configuration conf = new Configuration().addClass(Cat.class);
SessionFactory sf = conf.buildSessionFactory();
return "Hibernate Startup completed successfully";
}
}
3.2 配置StartUpc?br /> 启动Weblogic控制収ͼ打开左边mydomain\部v\启动和关闭节?选择双"配置新的 Startup Class..."
填写名称HibernateStartup, cdcom.chenm.HibernateStartUp,然后点击"创徏", 如果没有出错信息q成功?br />
认成功Q关闭Weblogicq启,观察DOSH口的信息,可以看到在Weblogic启动后显C很多行INFOQ如果没?br /> 错误Q证明配|成功。再打开weblogic控制?选择mydomain\服务器\myserver,点右键,选择察看JNDI树,如果
看到Hibernate的JNDI对象Q在双可以看见以下信息Q?/p>
l定名称: session_factory
对象c? net.sf.hibernate.impl.SessionFactoryImpl
对象散列代码: 45706641
对象转换成字W串: net.sf.hibernate.impl.SessionFactoryImpl@2b96d91
Config OK!
4. ~写SessionBean操作Hibernate实体
在SessionBean中定义RemoteҎ
public void InsertCat(String cat_id,String name, char sex, float weight) {
/**@todo Complete this method*/
try {
Context ctx = getInitialContext();
SessionFactory sf = (SessionFactory)ctx.lookup("hibernate/session_factory");
Session s = sf.openSession() ;
Transaction t = s.beginTransaction() ;
Cat myCat = new Cat();
myCat.setId(cat_id);
myCat.setName(name);
myCat.setSex(sex);
myCat.setWeight(weight);s.save(myCat);
s.save(myCat);
t.commit() ;
s.close();
}
catch( Exception ex ) {
}
}
private Context getInitialContext() throws Exception {
String url = "t3://chenming:7001"; // chenming服务器名U?br /> String user = null;
String password = null;
Properties properties = null;
try {
properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
properties.put(Context.PROVIDER_URL, url);
if (user != null) {
properties.put(Context.SECURITY_PRINCIPAL, user);
properties.put(Context.SECURITY_CREDENTIALS, password == null ? "" : password);
}
return new InitialContext(properties);
}
catch(Exception e) {
throw e;
}
}
~写试q运行,在cat表中插入一条纪?br /> Context context = getInitialContext();
//look up jndi name
Object ref = context.lookup("CatSession");
//look up jndi name and cast to Home interface
catSessionHome = (CatSessionHome) PortableRemoteObject.narrow(ref, CatSessionHome.class);
catSession = catSessionHome.create();
catSession.InsertCat("007","Chenm.cat",'1',100);
~存的介质一般是内存Q所以读写速度很快。但如果~存中存攄数据量非常大Ӟ也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质,q要考虑到管理缓存的q发讉K和缓存数据的生命周期?/p>
Hibernate的缓存包括Session的缓存和SessionFactory的缓存,其中SessionFactory的缓存又可以分ؓ两类Q内|缓存和外置~存。Session的缓存是内置的,不能被卸载,也被UCؓHibernate的第一U缓存。SessionFactory的内|缓存和Session的缓存在实现方式上比较相|前者是SessionFactory对象的一些集合属性包含的数据Q后者是指Session的一些集合属性包含的数据。SessionFactory的内|缓存中存放了映元数据和预定义SQL语句Q映元数据是映文件中数据的拷贝,而预定义SQL语句是在Hibernate初始化阶D|据映元数据推导出来QSessionFactory的内|缓存是只读的,应用E序不能修改~存中的映射元数据和预定义SQL语句Q因此SessionFactory不需要进行内|缓存与映射文g的同步。SessionFactory的外|缓存是一个可配置的插件。在默认情况下,SessionFactory不会启用q个插g。外|缓存的数据是数据库数据的拷贝,外置~存的介质可以是内存或者硬盘。SessionFactory的外|缓存也被称为Hibernate的第二~存?/p>
Hibernate的这两~存都位于持久化层,存放的都是数据库数据的拷贝,那么它们之间的区别是什么呢Qؓ了理解二者的区别Q需要深入理解持久化层的~存的两个特性:~存的范围和~存的ƈ发访问策略?/p>
持久化层的缓存的范围
~存的范围决定了~存的生命周期以及可以被谁访问。缓存的范围分ؓ三类?/p>
1 事务范围Q缓存只能被当前事务讉K。缓存的生命周期依赖于事务的生命周期Q当事务l束Ӟ~存也就l束生命周期。在此范围下Q缓存的介质是内存。事务可以是数据库事务或者应用事务,每个事务都有独自的缓存,~存内的数据通常采用怺兌的的对象形式?/p>
2 q程范围Q缓存被q程内的所有事务共享。这些事务有可能是ƈ发访问缓存,因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进E的生命周期Q进E结束时Q缓存也q束了生命周期。进E范围的~存可能会存攑֤量的数据Q所以存攄介质可以是内存或盘。缓存内的数据既可以是相互关联的对象形式也可以是对象的松散数据Ş式。松散的对象数据形式有点cM于对象的序列化数据,但是对象分解为松散的法比对象序列化的算法要求更快?/p>
3 集群范围Q在集群环境中,~存被一个机器或者多个机器的q程׃n。缓存中的数据被复制到集环境中的每个进E节点,q程间通过q程通信来保证缓存中的数据的一致性,~存中的数据通常采用对象的松散数据Ş式?/p>
对大多数应用来说Q应该慎重地考虑是否需要用集范围的~存Q因问的速度不一定会比直接访问数据库数据的速度快多?/p>
持久化层可以提供多种范围的缓存。如果在事务范围的缓存中没有查到相应的数据,q可以到q程范围或集范围的~存内查询,如果q是没有查到Q那么只有到数据库中查询。事务范围的~存是持久化层的W一U缓存,通常它是必需的;q程范围或集范围的~存是持久化层的W二U缓存,通常是可选的?/p>
持久化层的缓存的q发讉K{略
当多个ƈ发的事务同时讉K持久化层的缓存的相同数据Ӟ会引起ƈ发问题,必须采用必要的事务隔L施?/p>
在进E范围或集群范围的缓存,即第二~存Q会出现q发问题。因此可以设定以下四U类型的q发讉K{略Q每一U策略对应一U事务隔ȝ别?/p>
事务型:仅仅在受理环境中适用。它提供了Repeatable Read事务隔离U别。对于经常被M很少修改的数据,可以采用q种隔离cdQ因为它可以防止脏读和不可重复读q类的ƈ发问题?/p>
d型:提供了Read Committed事务隔离U别。仅仅在非集的环境中适用。对于经常被M很少修改的数据,可以采用q种隔离cdQ因为它可以防止脏读q类的ƈ发问题?/p>
非严D写型Q不保证~存与数据库中数据的一致性。如果存在两个事务同时访问缓存中相同数据的可能,必须数据配置一个很短的数据q期旉Q从而尽量避免脏诅R对于极被修改Qƈ且允许偶脏ȝ数据Q可以采用这Uƈ发访问策略? 只读型:对于从来不会修改的数据,如参考数据,可以使用q种q发讉K{略?/p>
事务型ƈ发访问策略是事务隔离U别最高,只读型的隔离U别最低。事务隔ȝ别越高,q发性能p低?/p>
什么样的数据适合存放到第二~存中?
1、很被修改的数?
2、不是很重要的数据,允许出现偶尔q发的数?/p>
3、不会被q发讉K的数?/p>
4、参考数?/p>
不适合存放到第二~存的数据?
1、经常被修改的数?/p>
2、胦务数据,l对不允许出现ƈ?/p>
3、与其他应用׃n的数据?/p>
Hibernate的二U缓?/p>
如前所qͼHibernate提供了两U缓存,W一U是Session的缓存。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的~存是事务范围的~存。第一U缓存是必需的,不允许而且事实上也无法比卸除。在W一U缓存中Q持久化cȝ每个实例都具有唯一的OID?/p>
W二U缓存是一个可插拔的的~存插gQ它是由SessionFactory负责理。由于SessionFactory对象的生命周期和应用E序的整个过E对应,因此W二U缓存是q程范围或者集范围的~存。这个缓存中存放的对象的松散数据。第二对象有可能出现ƈ发问题,因此需要采用适当的ƈ发访问策略,该策略ؓ被缓存的数据提供了事务隔ȝ别。缓存适配器用于把具体的缓存实现Y件与Hibernate集成。第二~存是可选的Q可以在每个cL每个集合的粒度上配置W二U缓存?/p>
Hibernate的二U缓存策略的一般过E如下:
1) 条g查询的时候,L发出一条select * from table_name where ? Q选择所有字D)q样的SQL语句查询数据库,一ơ获得所有的数据对象?
2) 把获得的所有数据对象根据ID攑օ到第二~存中?
3) 当HibernateҎID讉K数据对象的时候,首先从Session一U缓存中查;查不刎ͼ如果配置了二U缓存,那么从二U缓存中查;查不刎ͼ再查询数据库Q把l果按照ID攑օ到缓存?
4) 删除、更新、增加数据的时候,同时更新~存?/p>
Hibernate的二U缓存策略,是针对于ID查询的缓存策略,对于条g查询则毫无作用。ؓ此,Hibernate提供了针Ҏ件查询的Query~存?/p>
Hibernate的Query~存{略的过E如下:
1) Hibernate首先Ҏq些信息l成一个Query KeyQQuery Key包括条g查询的请求一般信息:SQL, SQL需要的参数Q记录范_起始位置rowStartQ最大记录个数maxRows)Q等?
2) HibernateҎq个Query Key到Query~存中查扑֯应的l果列表。如果存在,那么q回q个l果列表Q如果不存在Q查询数据库Q获取结果列表,把整个结果列表根据Query Key攑օ到Query~存中?
3) Query Key中的SQL涉及C些表名,如果q些表的M数据发生修改、删除、增加等操作Q这些相关的Query Key都要从缓存中清空?/p>