hibernate总结二
Hibernate总结二:
Criteria查询:
接口,它是特定的持久化类的查询,面向对象,是传统sql的对象化表示,让开发人员可以用对象的方式来对数据库进行操作,他仅仅针对单个类查询。
Session是用来制造criteria实例的工厂
Criteria criteria = session.createCriteria(MyTest.class);
怎么构建一个criteria查询:
第一步:创建criteria对象
第二步:设置条件,criterion对象来封装,用Restictions获取条件
第三步:添加条件 add
第四步:执行查询
实战演练:
package com.lovo.criteria;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import com.lovo.po.Pet;
import com.lovo.po.User;
import junit.framework.TestCase;
/**
* criteria查询
* @author xieyongbing
*
*/
public class Test extends TestCase {
private SessionFactory sessionfactory;
private Configuration cfg;
public void setUp() throws Exception {
cfg = new Configuration().configure();
this.sessionfactory = cfg.buildSessionFactory();
}
public void tearDown() throws Exception {
this.sessionfactory.close();
}
public void testCriteria(){
Session session = this.sessionfactory.openSession();
//Criteria criteria = session.createCriteria(User.class); //创建criteria对象
// //添加查询 add,criterion来充当条件
//Criterion criterion = Restrictions.eq("id", 1); //创建查询条件,一般来说,我们用Restictions获取条件
//// List list = criteria.list(); //什么条件也不给,将返回所有的对象
//criteria.add(criterion); //添加条件
//List list = criteria.list(); //执行查询
// System.out.println(list.size());
// session.close();
/**
* 用一个方法链格式来写
* Restrictions.eq("id", 1) 这其中的id是你实体类的属性,后面是你的值
*/
// Session session = this.sessionfactory.openSession();
//List list = session.createCriteria(User.class)
// .add(Restrictions.eq("id", 1))
// .list();
//System.out.println(list.size());
// session.close();
/**
* 两个条件查询
* 简单查询
* Restrictions.or()
*/
// Session session = this.sessionfactory.openSession();
//List list = session.createCriteria(User.class)
// .add(Restrictions.or(Restrictions.eq("password", "1234"),Restrictions.eq("name", "谢永兵")))
// .list();
//System.out.println(list.size());
// session.close();
/**
* 离散查询,即离线查询 DetachedCriteria
* 好处:先构建一个离散查询对象,它没有和session关联,需要时关联。在web层构造查询条件。构建一个
* 离散的查询对象,传回持久层,与session关联。会带来web层与持久层耦合了
*(Restrictions.between("age", 12, 5) 12 和 5 的参数是从客户端传来的
*/
Integer low = 1;
Integer hi = 2;
//创建一个离散的criteria对象
DetachedCriteria dc = DetachedCriteria.forClass(User.class);
//添加条件
dc.add(Restrictions.between("id", low, hi));
//构建一个criteria对象,和session关联
// 一般来说我们应该,将下面的分离在另外一个方法中,这里我就不演示了
Criteria criteria = dc.getExecutableCriteria(session);
List list = criteria.list();
System.out.println(list.size());
}
}
Hibernate 缓存处理:
什么是缓存:
就是数据库的数据在内存中的临时容器
位于数据库与数据库访问层中间,实际上就是为了性能的提高,查询速度的增快
缓存的分类:
一级缓存: 即在但前事物范围内的数据库缓存,它是基于session的生命周期实现的
二级缓存:即在某个应用中或应用中某个独立数据库访问子集中的共享缓存,此缓存可由多
个事物共享,hibernate中由sessfactory实现。 就是相当作用域当中的
servletcontext 上下文
分布式缓存: 即在多个应用实例,多个jvm间共享的缓存
一级缓存实例:
/**
* 一级缓存实例
*
*/
Session session = this.sessionfactory.openSession();
User u1 = (User)session.get(User.class, 2);
System.out.println(u1.getName());
User u2 = (User)session.get(User.class, 2);
System.out.println(u2.getName());
//session.clear();内存清除session
session.close();
控制台打印的查询语句:
什么时候使用二级缓存:
第一:数据不会被第三方修改
第二:数据大小在可以接受的范围之内
第三:数据更新频率比较低
第四:同一数据可能会被频繁引用
第五:非关键数据需要共享的数据
查询缓存:
查询缓存,就是在内存建立空间用来保存上次查询结果,下次再进行同样的查询时,就不用再从数据库查找结果,大大的提高速度。
不过内存和数据库的数据没有完全同步,所以不适用于多个程序共同访问同一数据表的的情况;这样的话,数据表的数据已经被其他程序修改,有可能内存里存在的数据是旧数据,这就是所谓的脏数据。
而且Hibernate和数据库的查询缓存,在对一个数据表记录进行修改时,会把有关这个表的全部查询缓存清空,以保证减少脏读问题。
所以查询缓存只适用于非多服务器同时访问的数据库,而且读取大大多于修改操作的数据表上
配置一:
hibernate.cfg.xml文件中增加
<!--开启二级缓存-->
<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.cache.use_query_cache">true</property>
配置二:
工程项目src文件下新建一个ehcache.xml文件,其内容为
<!--开启二级缓存-->
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<diskStore path="java.io.tmpdir" />
<defaultCache maxElementsInMemory="10000" eternal="false" overflowToDisk="true" timeToIdleSeconds="300" timeToLiveSeconds="180" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" />
</ehcache>
配置三:
为了缓存某类的对象,其hbm文件中需添加<cache usage="read-only"/>属性例如:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping>
<class name="com.vogue.bbsphoto.entity.Forum"
table="cdb_forums">
<cache usage="read-only"/>
<id name="ID" column="fid" unsaved-value="null">
<generator />
</id>
<property name="name" column="name" type="string" />
<property name="type" column="type" type="string" />
</class>
</hibernate-mapping>
配置四:
为了使用查询缓存,Query必须设置cacheable为true,query.setCacheable(true);
例如dao父类中用于hql查询的方法修改后为:
/**
* 执行hql语句的查询
* @param sql
* @return
*/
public List executeQuery(String hql){
List list = new ArrayList();
Session session = HibernateSessionFactory.currentSession();
Transaction tx = null;
Query query = session.createQuery(hql);
query.setCacheable(true);
try {
tx = session.beginTransaction();
list = query.list();
tx.commit();
} catch (Exception ex) {
ex.printStackTrace();
HibernateSessionFactory.rollbackTransaction(tx);
} finally {
HibernateSessionFactory.closeSession();
}
return list;
}
实验结果:
一验证对象缓存
执行如下测试方法
public void testLoadForum(){
//第一次加载
long l1 = System.currentTimeMillis();
Forum res = (Forum)fDAO.get(Forum.class,new Long(3));
System.out.println(System.currentTimeMillis() - l1);
System.out.println(res.getName());
//第二次加载
long l2 = System.currentTimeMillis();
res = (Forum)fDAO.get(Forum.class,new Long(3));
System.out.println(System.currentTimeMillis() - l2);
System.out.println(res.getName());
}输出结果:可以看到先后两次加载id为3的(Forum)对象,但是只执行了一条sql
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
Hibernate: select forum0_.fid as fid0_, forum0_.name as name2_0_, forum0_.type as type2_0_ from cdb_forums forum0_ where forum0_.fid=?
1703
功能版区
0
功能版区
二验证查询结果缓存
执行如下测试方法
public void testGetAllForum() {
//第一次查询所有论坛记录
long l1 = System.currentTimeMillis();
List res = fDAO.getAllForum();
System.out.println(System.currentTimeMillis() - l1);
System.out.println(res.size());
//第二次查询所有论坛记录
long l2 = System.currentTimeMillis();
res = fDAO.getAllForum();
System.out.println(System.currentTimeMillis() - l2);
System.out.println(res.size());
}输出结果:先后两次查询所有论坛记录但,仍然只执行了一条sql
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
Hibernate: select forum0_.fid as fid, forum0_.name as name2_, forum0_.type as type2_ from cdb_forums forum0_ where (1=1 )and(forum0_.type='forum' ) order by forum0_.fid
1765
14
0
14
补充一下:当要缓存的对象处于级联关系中时。如果和他存在级联关系的对象都有属性 <cache usage="read-only"/>那么,在第一次get后该对象所处的对象图中的所有对象都会保存到hibernate的二级缓存中,在第二次get该对象时,直接从二级缓存中找到所有级联的对象;如果其中某个级联对象没有<cache usage="read-only"/>属性,则不会被保存到二级缓存中,以后每次get时仍然会执行sql去数据库中找该级联对象。
二级缓存:
1启用Hibernate二级缓存
Hibernate二级缓存分为两部分,class缓存和查询缓存,其获取对象的方式有所不同,但两者也有联系,查询缓存必须以class缓存为基础才能起作用,否则只会使效率更低。
我们这里使用的二级缓存是通过ehcache第三方插件实现的。
1.1配置Hibernate.cfg.xml
启用class缓存:
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
启用查询缓存:
<property name="hibernate.cache.use_query_cache">true</property>
1.2配置Spring框架中的hibernate
启用class缓存:
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
启用查询缓存:
<prop key="hibernate.cache.use_query_cache">true</prop>
1.3配置ehcache
Ehcache配置文件为ehcache.xml,默认配置为:
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
overflowToDisk="true"
/>
</ehcache>
其中各项内容的含义为:
1 diskStore:代表当二级缓存对象数据在内存中溢出,如果需要写入文件系统时的文件目录。
2 defaultCache:默认的calss缓存配置,如果某个对象没有其专有的配置时,ehcache一律启用默认配置。
3 maxElementInMemory:对象在内存中可存放的最大数量。
4 eternal:表示对象永不过期,如果选true则5,6两项无效。
5 timeToIdleSeconds:对象的空闲状态过期时间,单位为秒,0为可以无限制空闲。
6 timeToLiveSeconds:对象存在的最长时间,单位为秒(注意,如果该项比5项要小,则第5项无意义),0为永不过期。
7 overflowToDisk:当对象在内存中的数量超过maxElementInMemory值时,如果该项为true,则ehcahe会把对象数据写入diskStore项指定的目录。
如果需要对某个具体对象进行单独配置时,可以加上一组cache配置,例如:
<cache name="com.juyee.mp.bean.SysCodelist"
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="1800"
timeToLiveSeconds="0"
overflowToDisk="true"
/>
另外还有两个特殊的cache配置:
<cache name="org.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000"
eternal="true"
timeToIdleSeconds="1800"
timeToLiveSeconds="0"
overflowToDisk="true"/>
<cache name="org.hibernate.cache.StandardQueryCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="0"
overflowToDisk="true"/>
这两个cache配置对应查询缓存,具体作用如下(摘用别人的描述):
“当hibernate更新数据库的时候,它怎么知道更新哪些查询缓存呢? hibernate在一个地方维护每个表的最后更新时间,其实也就是放在上面UpdateTimestampsCache所指定的缓存配置里面。
当通过hibernate更新的时候,hibernate会知道这次更新影响了哪些表。然后它更新这些表的最后更新时间。每个缓存都有一个生成时间和这个缓存所查询的表,当hibernate查询一个缓存是否存在的时候,如果缓存存在,它还要取出缓存的生成时间和这个缓存所查询的表,然后去查找这些表的最后更新时间,如果有一个表在生成时间后更新过了,那么这个缓存是无效的。
可以看出,只要更新过一个表,那么凡是涉及到这个表的查询缓存就失效了,因此查询缓存的命中率可能会比较低。”
当然,如果没有这两个配置,则ehcache将为查询缓存启用默认配置。
2如何使用class缓存
2.1对象缓存
Class缓存的作用主要是在内存中保存某个具体对象,当用户第一次通过get、iterator方式取出对象时,系统会先从class缓存中去找,如果没有再通过sql语句去数据库中查找相关记录,并将查询到的对象放入内存中。
实例:对某个对象使用二级缓存,只需要在该对象的hbm文件中配置即可
<cache usage="read-write"/>
我们注意到其中usage这个选项,它有多个选择,对应不同的含义,经常有这两种种:
1 read-only:只对缓存中的对象进行读操作。
2 read-write:当对象被update时,缓存中和数据库中一同被修改(缓存不支持事务回滚)。
2.2关联缓存
目前我们仅仅实现了对一个对象的缓存,那如何对该对象的关联对象集合进行缓存呢?
实例:对某个对象的关联对象集合的二级缓存,需要在该对象的hbm文件中set配置进行修改
<set name="children" lazy="true" order-by="treeid asc">
<cache usage="read-write"/>
<key column="PARENTID"/>
<one-to-many not-null="true" length="50"/>
<property name="summary" not-null="true" length="200" lazy="true"/>
<property name="text" not-null="true" length="2000" lazy="true"/>
</class>
属性的延迟加载需要使用运行时的字节设备来处理,如果你的持久化类还没有被这个设备处理。hibernate 会忽略这个设置,我们要导入一个包: cglib
要想使用此字节设备处理持久化类,使用如下的Ant 任务。
<target name="instrument" depends="compile">
<taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
<classpath path="${jar.path}"/>
<classpath path="${classes.dir}"/>
<classpath refid="lib.class.path"/>
</taskdef>
<instrument verbose="true">
<fileset dir="${testclasses.dir}/org/hibernate/auction/model">
<include name="*.class"/>
</fileset>
</instrument>
</target>
当我在使用ant时候,我们的java实体bean讲发生改变,如果我们在修改的时候不运行ant,,,java实体bean不会发生改变
一、saveorUpdate与unsaved-value
到底是sava还是update
Hibernate需要判断被操作的对象究竟是一个已经持久化过的持久对象还是临时对象。
1).主键Hibernate的id generator产生
<id name="id" type="java.lang.Long">
<column name="ID" precision="22" scale="0" />
<generator />
</id>
Project project = new Project();
project.setId(XXX);
this.projectDao.saveOrUpdate(project);
1、默认unsaved-value="null"
主键是对象类型,hebernate判断project的主键是否位null,来判断project是否已被持久化
是的话,对project对象发送save(project),
若自己设置了主键则直接生成update的sql,发送update(project),即便数据库里没有那条记录。
主键是基本类型如int/long/double/
自己设置unsaved-null="0"。
所以这样的话save和update操作肯定不会报错。
2、unsaved-value="none",
由于不论主键属性为任何值,都不可能为none,因此Hibernate总是对project对象发送update(project)
3、unsaved-value="any"
由于不论主键属性为任何值,都肯定为any,因此Hibernate总是对project对象发送save(project),hibernate生成主键。
Hibernate文档中写到
saveOrUpdate()完成了如下工作:
如果对象已经在这个session中持久化过了,什么都不用做
如果对象没有标识值,调用save()来保存它
如果对象的标识值与unsaved-value中的条件匹配,调用save()来保存它
如果对象使用了版本(version或timestamp),那么除非设置unsaved-value="undefined",版本检查会发生在标识符检查之前.
如果这个session中有另外一个对象具有同样的标识符,抛出一个异常
2).主键由自己来赋值
<id name="id" type="java.lang.Long">
<column name="ID" precision="22" scale="0" />
<generator />
</id>
Project project = new Project();
project.setId(XXX);
this.projectDao.saveOrUpdate(project);
1、默认unsaved-value="null"
这时有所不同,hibernate会根据主键产生一个select,来判断此对象是否已被持久化
已被持久化则update,未被持久化则save。
2、unsaved-value="none",update对象,同上
3、unsaved-value="any" ,save对象,
如果自己自己设置的ID在数据库中已存在,则报错。
二、save与update操作
显式的使用session.save()或者session.update()操作一个对象的时候,实际上是用不到unsaved-value的
在同一Session,save没什么可说得
update对象时, 最直接的更改一个对象的方法就是load()它,保持Session打开,然后直接修改即可:
Session s =…
Project p = (Project) sess.load(Project.class, id) );
p.setName(“test”);
s.flush();
不用调用s.update(p);hibernate能察觉到它的变化,会自动更新。当然显示调用的话也不会错
Hibernate文档中写到
update()方法在下列情形下使用:
程序在前面的session中装载了对象
对象被传递到UI(界面)层
对该对象进行了一些修改
对象被传递回业务层
应用程序在第二个session中调用update()保存修改
三、delete操作
删除时直接自己构造一个project即可删除
this.projectDao.delete(preojct);
以前删除我是这样写的
public void deleteProject(String id) {
Project project = (Project) this.projectDao.get(Project.class, id);
if (project != null) {
this.projectDao.delete(project);
}
即这样也是可以的
Project project = new Project();
project.setId(id);
this.projectDao.delete(project).
如果有级联关系,需要把级联的子类也构造出来add进去,同样可以删除。
Hibernate 事物处理机制:
Hibernate是对JDBC的轻量级对象封装,Hibernate本身是不具备Transaction处理功能的,Hibernate的 Transaction实际上是底层的JDBC Transaction的封装,或者是JTA Transaction的封装,下面我们详细的分析:
Hibernate可以配置为JDBCTransaction或者是JTATransaction,这取决于你在hibernate.properties中的配置:
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory
如果你什么都不配置,默认情况下使用JDBCTransaction,如果你配置为:
hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
将使用JTATransaction
不管你准备让Hibernate使用JDBCTransaction,还是JTATransaction,我的忠告就是什么都不配,将让它保持默认状态,如下:
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory
在下面的分析中我会给出原因。
一、JDBC Transaction
看看使用JDBC Transaction的时候我们的代码例子:
Session session = sf.openSession();
Transaction tx = session.beginTransactioin();
...
session.flush();
tx.commit();
session.close();
这是默认的情况,当你在代码中使用Hibernate的Transaction的时候实际上就是JDBCTransaction。那么JDBCTransaction究竟是什么东西呢?来看看源代码就清楚了:
Hibernate2.0.3源代码中的类
net.sf.hibernate.transaction.JDBCTransaction:
public void begin() throws HibernateException {
...
if (toggleAutoCommit) session.connection().setAutoCommit(false);
...
}
这是启动Transaction的方法,看到 connection().setAutoCommit(false) 了吗?是不是很熟悉?
再来看
public void commit() throws HibernateException {
...
try {
if ( session.getFlushMode()!=FlushMode.NEVER ) session.flush();
try {
session.connection().commit();
committed = true;
}
...
toggleAutoCommit();
}
这 是提交方法,看到connection().commit() 了吗?下面就不用我多说了,这个类代码非常简单易懂,通过阅读使我们明白Hibernate的Transaction都在干了些什么?我现在把用 Hibernate写的例子翻译成JDBC,大家就一目了然了:
Connection conn = ...; <--- session = sf.openSession();
conn.setAutoCommit(false); <--- tx = session.beginTransactioin();
... <--- ...
conn.commit(); <--- tx.commit(); (对应左边的两句)
conn.setAutoCommit(true);
conn.close(); <--- session.close();
看 明白了吧,Hibernate的JDBCTransaction根本就是conn.commit而已,根本毫无神秘可言,只不过在Hibernate 中,Session打开的时候,就会自动conn.setAutoCommit(false),不像一般的JDBC,默认都是true,所以你最后不写 commit也没有关系,由于Hibernate已经把AutoCommit给关掉了,所以用Hibernate的时候,你在程序中不写 Transaction的话,数据库根本就没有反应。
二、JTATransaction
如果你在EJB中使用Hibernate,或者准备用JTA来管理跨Session的长事务,那么就需要使用JTATransaction,先看一个例子:
javax.transaction.UserTransaction tx = new InitialContext().lookup("javax.transaction.UserTransaction");
Session s1 = sf.openSession();
...
s1.flush();
s1.close();
...
Session s2 = sf.openSession();
...
s2.flush();
s2.close();
tx.commit();
这 是标准的使用JTA的代码片断,Transaction是跨Session的,它的生命周期比Session要长。如果你在EJB中使用 Hibernate,那么是最简单不过的了,你什么Transaction代码统统都不要写了,直接在EJB的部署描述符上配置某某方法是否使用事务就可 以了。
现在我们来分析一下JTATransaction的源代码, net.sf.hibernate.transaction.JTATransaction:
public void begin(InitialContext context, ...
...
ut = (UserTransaction) context.lookup(utName);
...
看清楚了吗? 和我上面写的代码 tx = new Initial Context?().lookup("javax.transaction.UserTransaction"); 是不是完全一样?
public void commit() ...
...
if (newTransaction) ut.commit();
...
JTATransaction的控制稍微复杂,不过仍然可以很清楚的看出来Hibernate是如何封装JTA的Transaction代码的。
但 是你现在是否看到了什么问题? 仔细想一下,Hibernate Transaction是从Session中获得的,tx = session.beginTransaction(),最后要先提交tx,然后再session.close,这完全符合JDBC的 Transaction的操作顺序,但是这个顺序是和JTA的Transactioin操作顺序彻底矛盾的!!! JTA是先启动Transaction,然后启动Session,关闭Session,最后提交Transaction,因此当你使用JTA的 Transaction的时候,那么就千万不要使用Hibernate的Transaction,而是应该像我上面的JTA的代码片断那样使用才行。
总结:
1、在JDBC上使用Hibernate
必须写上Hibernate Transaction代码,否则数据库没有反应。此时Hibernate的Transaction就是Connection.commit而已
2、在JTA上使用Hibernate
写JTA的Transaction代码,不要写Hibernate的Transaction代码,否则程序会报错
3、在EJB上使用Hibernate
什么Transactioin代码都不要写,在EJB的部署描述符里面配置
|---CMT(Container Managed Transaction)
|
|---BMT(Bean Managed Transaction)
|
|----JDBC Transaction
|
|----JTA Transaction
--------------------------------------------
提问:
javax.transaction.UserTransaction tx = new InitialContext().lookup("javax.transaction.UserTransaction");
Session s1 = sf.openSession();
...
s1.flush();
s1.close();
...
Session s2 = sf.openSession();
...
s2.flush();
s2.close();
tx.commit();
s1不关闭,使用s2进行操作的代码中使用s1可不可以(我觉得这样更加节约资源,不需要反复的连接、关闭)
但sf.opengSession()时,并没有setAutoCommit(false),我想问的是,如果不编写任何事务代码,如:
Session s = sf.openSession();
......
s.close();
数据库会不会有反应(此时应该是默认AutoCommit为true)。
不会有反应。在sf.openSession() 创建Session实例的时候,就已经调用了conn.setAutoCommit(false)了。
另外,我想问一下:
1. s.flush()是不是必须的
2. s.close()是不是一定要关闭
--------------------------------------------
回答:
s.flush不是必须的,s.close()会调用一次s.flush()
s.close()正常情况下应该关闭,除非你是用ThreadLocal管理Session。
s1不关闭,使用s2进行操作的代码中使用s1可不可以(我觉得这样更加节约资源,不需要反复的连接、关闭)
在这个例子中看不出来JTA的作用。
假设
Class A {
find() {
Session s1 = sf.openSession();
...
s1.flush();
s1.close();
}
}
Class B {
find() {
Session s2 = sf.openSession();
...
s2.flush();
s2.close();
}
}
Main {
tx = ...;
A.find();
B.find();
tx.commit();
}
Hibernate连接池:
用Hibernate自带的连接池性能不高,而且还存在BUG,因此官方推荐使用c3p0或Proxool连接池。
1.Hibernate默认连接池
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration
PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory >
<!—JDBC驱动程序-->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 连接数据库的URL-->
<property name="connection.url">
jdbc:mysql://localhost:3306/schoolproject
</property>
<property name="connection.useUnicode">true</property>
<property name="connection.characterEncoding">UTF-8</property>
<!--连接的登录名-->
<property name="connection.username">root</property>
<!—登录密码-->
<property name="connection.password"></property>
<!--是否将运行期生成的SQL输出到日志以供调试-->
<property name="show_sql">true</property>
<!--指定连接的语言-->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!--映射Student这个资源-->
<mapping resource="com/wqbi/model/pojo/student.hbm.xml" />
</session-factory>
</hibernate-configuration>
2.C3P0连接配置
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration
PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory >
<!—JDBC驱动程序-->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 连接数据库的URL-->
<property name="connection.url">
jdbc:mysql://localhost:3306/schoolproject
</property>
<property name="connection.useUnicode">true</property>
<property name="connection.characterEncoding">UTF-8</property>
<!--连接的登录名-->
<property name="connection.username">root</property>
<!--登录密码-->
<property name="connection.password"></property>
<!-- C3P0连接池设定-->
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider
</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.timeout">120</property>
<property name="hibernate.c3p0.max_statements">100</property>
<property name="hibernate.c3p0.idle_test_period">120</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<!--是否将运行期生成的SQL输出到日志以供调试-->
<property name="show_sql">true</property>
<!--指定连接的语言-->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!--映射Student这个资源-->
<mapping resource="com/wqbi/model/pojo/student.hbm.xml" />
</session-factory>
</hibernate-configuration>
3.proxool连接池
(1) 先写proxool的配置文件,文件名:proxool.xml(一般放在与hibernate.cfg.xml文件在同一个目录中)本例配置的是MYSQL数据库,数据库的名字为schoolproject
<?xml version="1.0" encoding="UTF-8"?>
<!-- the proxool configuration can be embedded within your own application's.
Anything outside the "proxool" tag is ignored. -->
<something-else-entirely>
<proxool>
<!--连接池的别名-->
<alias>DBPool</alias>
<!--proxool只能管理由自己产生的连接-->
<driver-url>
jdbc:mysql://localhost:3306/schoolproject?useUnicode=true&characterEncoding=UTF8
</driver-url>
<!—JDBC驱动程序-->
<driver-class>com.mysql.jdbc.Driver</driver-class>
<driver-properties>
<property name="user" value="root"/>
<property name="password" value=""/>
</driver-properties>
<!-- proxool自动侦察各个连接状态的时间间隔(毫秒),侦察到空闲的连接就马上回
收,超时的销毁-->
<house-keeping-sleep-time>90000</house-keeping-sleep-time>
<!-- 指因未有空闲连接可以分配而在队列中等候的最大请求数,超过这个请求数的
用户连接就不会被接受-->
<maximum-new-connections>20</maximum-new-connections>
<!-- 最少保持的空闲连接数-->
<prototype-count>5</prototype-count>
<!-- 允许最大连接数,超过了这个连接,再有请求时,就排在队列中等候,最大的
等待请求数由maximum-new-connections决定-->
<maximum-connection-count>100</maximum-connection-count>
<!-- 最小连接数-->
<minimum-connection-count>10</minimum-connection-count>
</proxool>
</something-else-entirely>
(2)配置hibernate.cfg.xml文件
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration
PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory >
<property name="hibernate.connection.provider_class">
org.hibernate.connection.ProxoolConnectionProvider
</property>
<property name="hibernate.proxool.pool_alias">DBPool</property>
<property name="hibernate.proxool.xml">proxoolconf.xml</property>
<!--是否将运行期生成的SQL输出到日志以供调试-->
<property name="show_sql">true</property>
<!--指定连接的语言-->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!--映射Student这个资源-->
<mapping resource="com/wqbi/model/pojo/student.hbm.xml" />
</session-factory>
</hibernate-configuration>
(1) hibernate.connection.provider_class定义Hibernate的连接加载类,这里Proxool连接池是用这个,不同的连接池有不同的加载类,可以查阅Hibernate文档获取相关信息
(2) hibernate.proxool.pool_alias这里就是用我们上面提到的连接池的别名
(3) hibernate.proxool.xml是向Hibernate声明连接池的配置文件位置,可以用相对或绝对路径,用相对路径时要注意一定在要Path范围内!不然会抛出异常。
(4) dialect是声明SQL语句的方言
(5) show_sql定义是否显示Hibernate生成的SQL语言,一般在调试阶段设为true,完成后再改成false,这样有利于调试。
(6) <mapping >资源文件映射
4.JNDI连接池,数据源已经由应用服务配置好(如Web服务器),Hibernate需要做的只是通过JNDI名查找到此数据源。应用服务器将连接池对外显示为JNDI绑定数据源,它是javax.jdbc.Datasource类的一个实例。只要配置一个Hibernate文件,如:
hibernate.connection.datasource=java:/comp/env/jdbc/schoolproject //JNDI名
hibernate.transaction.factory_class = org.hibernate.transaction.JTATransactionFactory
hibernate.transaction.manager_loopup_class =
org.hibernate.transaction.JBossTransactionManagerLookup
hibernate.dialect=org.hibernate.dialect.MySQLDialect