??xml version="1.0" encoding="utf-8" standalone="yes"?>
You tried to delete an object that was allready deleted from the database.
This can happen when cascading deletes where performed somewhere and you did not reattach your object. For deleting you do not nee to reattach your object but this could prevent this problem.
19:47:56,078 ERROR AbstractBatcher:61 - Exception executing batch:
org.hibernate.StaleStateException: Batch update returned unexpected row count from update: 0 actual row count: 0 expected: 1
at org.hibernate.jdbc.BatchingBatcher.checkRowCount(BatchingBatcher.java:93)
at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:79)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:58)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:195)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:230)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:145)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:296)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1009)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:356)
一 hibernate配置
1.下蝲所需?br>下蝲hibernate2.13, hibernate-extension2.13,Middlegen(已装了jdk和ant)
2.创徏数据?例子:student;course,stu_cou)
Student(id,name)
Course(id,name)
Stu_cou(stu_id,cou_id)(分别是student表和course表的外健)
3.使用MiddleGen(见附?
?hibernate映射关系(many-to-many)
1. 分析inverse参数(student.hbm.xml course.hbm.xml)
inverse该参数用来负责映之间的关系,讄为false的一方可以对他们的关p进行维?br>讄inverse = false的实?表示在映中是它是主动关p?由它来维户关pM的数?br>讄inverse = true 的实?表示在映中是它是被动关p?它不l护关系中的数据
1) inverse=false的情?br>a) d记录的情?br>student.hbm.xml是主动方,由它来决定stu_cou表中的记?故inverse=false
当向stu_cou中写入记录时?
/*
* 试目的:在stu_cou中添加一l对应关p?student,course)
* 试l果:当执行完该段代码?br>* 如stu_cou中没?student,course)?自动加入(student,course)
* 如stu_cou中存?student,course)?什么都不作,不会存在d冲突
Student student=(Student)session.load(Student.class,student2.getId())
Course course=(Course)session.load(Course.class,course2.getId());
student.getCourses().add(course);
session.save(student);
执行完后,hibenrate成功昄
Hibernate: select course0_.id as id0_, course0_.name as name0_ from course course0_ where course0_.id=?
Hibernate: select student0_.id as id0_, student0_.name as name0_ from student student0_ where student0_.id=?
Hibernate: select courses0_.cid as cid__, courses0_.sid as sid__ from stu_cou courses0_ where courses0_.sid=?
Hibernate: insert into stu_cou (sid, cid) values (?, ?)
b) 删除记录的情?br>Student student=(Student)session.load(Student.class,student2.getId())
Course course=(Course)session.load(Course.class,course2.getId());
student.getCourses().让remove(course);
session.save(student);
代码执行完后,可以成功执行,hibernate昄:
Hibernate: select course0_.id as id0_, course0_.name as name0_ from course course0_ where course0_.id=?
Hibernate: select student0_.id as id0_, student0_.name as name0_ from student student0_ where student0_.id=?
Hibernate: select courses0_.cid as cid__, courses0_.sid as sid__ from stu_cou courses0_ where courses0_.sid=?
Hibernate: delete from stu_cou where sid=?
2) inverse=true的情?br>student.hbm.xml是被动方,讄它的inverse=true
a) d记录情况
* 试目的:在stu_cou中添加一l对应关p?student,course)
* 试l果:当执行完该段代码?br>* 如stu_cou中没?student,course)?自动加入(student,course)
* 如stu_cou中存?student,course)?什么都不作,不会存在d冲突
Student tudent=(Student)session.load(Student.class,student2.getId());
Course course=(Course)session.load(Course.class,course2.getId());
student.getCourses().add(course);
session.save(student);
代码执行完后,hibernate昄,没有插入记录
Hibernate: select course0_.id as id0_, course0_.name as name0_ from course course0_ where course0_.id=?
Hibernate: select student0_.id as id0_, student0_.name as name0_ from student student0_ where student0_.id=?
Hibernate: select courses0_.cid as cid__, courses0_.sid as sid__ from stu_cou courses0_ where courses0_.sid=?
b) 删除记录情况
当向stu_cou中删除记录时?
Student student=(Student)session.load(Student.class,student2.getId())
Course course= (Course)session.load(Course.class,course2.getId());
student.getCourses().remove(course);
session.save(student);
执行?hibernate昄如下,证明没有删除记录
Hibernate: select course0_.id as id0_, course0_.name as name0_ from course course0_ where course0_.id=?
Hibernate: select student0_.id as id0_, student0_.name as name0_ from student student0_ where student0_.id=?
Hibernate: select courses0_.cid as cid__, courses0_.sid as sid__ from stu_cou courses0_ where courses0_.sid=?
Hibernate: select course0_.id as id0_, course0_.name as name0_ from course course0_ where course0_.id=?
Hibernate: select course0_.id as id0_, course0_.name as name0_ from course course0_ where course0_.id=?
2. 分析cascade参数(student.hbm.xml course.hbm.xml)
只有讄了inverse=false才可以操Ustu_cou的数?br>当inverse=true的时?下列情况1中b)提示错误
原因: stu_cou中存在外健约?你无法直接删除student表中的数?br>1) cascade=save-update的情?br>a)d记录情况
Set set=new HashSet();
set.add(course1);
set.add(course2);
set.add(course3);
student3.setCourses(set);
session.save(student3);
执行后hibernate提示:
Hibernate: insert into student (name) values (?)
Hibernate: insert into course (name) values (?)
Hibernate: insert into course (name) values (?)
Hibernate: insert into course (name) values (?)
Hibernate: insert into stu_cou (sid, cid) values (?, ?)
可见,插入了student,course,和stu_cou三个?/p>
b)删除记录情况
Student student=(Student)session.load(Student.class,new Integer(22));
session.delete(student);
成功执行?hibernate提示:
Hibernate: select student0_.id as id0_, student0_.name as name0_ from student student0_ where student0_.id=?
Hibernate: delete from stu_cou where sid=?
Hibernate: delete from student where
2) cascade=all的情?br>a) d记录情况
Set set=new HashSet();
set.add(course1);
set.add(course2);
set.add(course3);
student3.setCourses(set);
session.save(student3);
执行后hibernate提示:成功dU联关系
Hibernate: insert into student (name) values (?)
Hibernate: insert into course (name) values (?)
Hibernate: insert into course (name) values (?)
Hibernate: insert into course (name) values (?)
Hibernate: insert into stu_cou (sid, cid) values (?, ?)
b) 删除记录情况
Student student=(Student)session.load(Student.class,new Integer(22));
session.delete(student);
试l果(所有和student(22)相关的记录均被删?
删除student表中的student(22)记录
删除stu_cou表中的student(22)的记?br>删除course表中的student(22)对应的course的记?/p>
2) cascade=none情况
a) d记录情况
Set set=new HashSet();
set.add(course1);
set.add(course2);
set.add(course3);
student3.setCourses(set);
session.save(student3);
p|,因ؓ没有U联关系,所以course记录d不进?造成外健p|
b) 删除记录情况
Student student=(Student)session.load(Student.class,new Integer(22));
session.delete(student);
正常,删除了student表中的记录student(22),同时删除了stu_cou中对应的student(22)的记?/p>
附录
1QMiddleGen的?br>1环境变量讄
%Hibernate_Home%/lib/*.jar?MiddleGen%/lib?br>%Hibernate_Home%/hibernate2.jar?MiddleGen%/lib?br>%Hibernate-Extension_Home%/tools/lib/*.jar?MiddleGen%/lib?br>%Hibernate-Extension_Home%/tools/hibernate-tools.jar?MiddleGen%/lib?/p>
2 MiddleGen的配|?br>配置目标数据库参?br>q入MiddleGen 目录下的\config\database 子目录,Ҏ我们实际采用的数据库打开对应的配|文件。如q里我用的是mysql数据库,对应的就是mysql.xml文g?br><property
name="database.script.file" value="${src.dir}/sql/${name}-mysql.sql"/>
<property
name="database.driver.file" value="${lib.dir}/mysql.jar"/>
<property
name="database.driver.classpath" value="${database.driver.file}"/>
<property
name="database.driver" value="org.gjt.mm.mysql.Driver"/>
<property
name="database.url" value="jdbc:mysql://localhost/sample"/>
<property
name="database.userid" value="user"/>
<property
name="database.password" value="mypass"/>
<property
name="database.schema" value=""/>
<property
name="database.catalog" value=""/>
<property
name="jboss.datasource.mapping" value="mySQL"/>
其中下划U标准的部分是我们进行配|的内容Q分别是数据url以及数据库用
户名和密码?/p>
1) 修改Build.xml
修改MiddleGen 根目录下的build.xml 文gQ此文g是Middlegen-Hibernate 的Ant构徏配置。Middlegen-Hibernate根据build.xml文g中的具体参数生成数据库表映射文g。可配置的项目包括:
a) 目标数据库配|文件地址
查找关键?”!ENTITY”Q得刎ͼ
<!DOCTYPE project [
<!ENTITY database SYSTEM
"file:./config/database/hsqldb.xml">
]>
默认情况下,MiddleGen 采用的是hsqldb.xmlQ?br>其修改为我们所用的数据库配|文Ӟmysql.xmlQ:
<!DOCTYPE project [
<!ENTITY database SYSTEM
"file:./config/database/mysql.xml">
]>
b) Application name
查找Q?br><property value="airline"/>
“aireline”是MiddleGen原始配置中默认的 Application NameQ将其修改ؓ我们
所希望的名Uͼ?#8220;HibernateSample”Q?br><property value="HibernateSample"/>
c) 输出目录
查找关键?#8220;name="build.gen-src.dir"”Q得刎ͼ
<property
value="${build.dir}/gen-src"/>
修改value="${build.dir}/gen-src"使其指向我们所期望的输出目录,
q里我们修改为:<property
value="C:\sample"/>
d) 对应代码的Package name
查找关键?#8220;destination”Q得刎ͼ
<hibernate
destination="${build.gen-src.dir}"
package="${name}.hibernate"
genXDocletTags="false"
genIntergratedCompositeKeys="false"
javaTypeMapper=
"middlegen.plugins.hibernate.HibernateJavaTypeMapper"
/>
可以看到Qhibernate 节点package 属性的默认讄实际上是由前面的
Application Name Q?{name}Q和“.hibernate”l合而成Q根据我们的需要,
q里q有一个属性genXDocletTagsQ如果设|ؓtrueQ则生成的代码将包含
xdoclet tagQ这Z后在开发过E中借助xdocletq行映射调整提供了帮助。注意,如果使用的数据库为SQLServerQ需要将build.xml部分删除(参见?^的文?Q否则Middlegen会报出找不到表的错误?br>x为止QMiddleGen 已经配置完毕Q在MiddleGen 根目录下q行antQ就出?br>MiddleGen的界面:
2 *.xml?java
在得?xml?使用ant hbm2java 卛_得到相应的java文g
ȝ:
我第一ơ运行成?但是后来则出现如下类似错?查发现在MiddleGen的lib目录下存在多个类似的jar?br>(velocity.jar,velocity1-0.8.jar),删除旧的jar包后,问题解决
[middlegen] java.lang.IncompatibleClassChangeError
[middlegen] at [middlegen] at org.apache.velocity.Template.process(Template.java:136)
2Q?评论)关于Many-to-Many需要注意的问题
比如group/user,user/role,group/role,都是多对多的关系?br>所以有必要搞搞清楚。以group/userZ
(1)group.getUsers() & user.getGroups()双向映射。在q里Q考虑到user.setGroups()是不会放出来的。所以在user端加入inverse=trueQ就是说Q让Group端来l护两者的关系表?br>(2)于是Q添加的时候,要把user加入到group的user set中,保存Q才有意义!
(3)如果要删除group_user的关p,而不是group/user本nQ那么,需要在group端设定casade=save-update。否则,group.getUsers().remove(user)不会起作用!
(4)׃有了FK保护Q你是无法单独删除User的。同Ӟ׃你指定了inverse=true,所以无法光光的讄user.getGroups().clearp够搞定一切。你必须首先在每个Group.getUsers中删除这个userQ才能最后删除。所以,UserManagerImpl代码可能看v来像q样Q?br>public void delUser(User user) {
if (user == null) {
logger.info("Got a null user object!");
return;
}
Session session = null;
Transaction trans = null;
boolean bSuccess = false;
try {
String username = new String(user.getName());
session = PLUtils.getSession();
trans = session.beginTransaction();
session.update(user);
Set groups = ((UserEntity)user).getGroups();
for(Iterator i = groups.iterator();i.hasNext();){
GroupEntity g = (GroupEntity)i.next();
session.update(g);
g.getUsers().remove(user);
session.update(g);
}
// ((UserEntity)user).getGroups().clear();
session.delete(user);
bSuccess = true;
logger.debug("User " + username + " deleted ok!");
}
catch (ObjectNotFoundException onfe) {
logger.info("user not found!", onfe);
}
catch (Exception e) {
logger.error("failed!", e);
}
finally {
try {
if (bSuccess)
trans.commit();
else
trans.rollback();
session.close();
}
catch (Exception ex) {
}
}
}
最q在目中?Spring ?Hibernate q行开发,有感?Criteria 比较好用Q在查询Ҏ设计上可以灵zȝҎ Criteria 的特Ҏ方便地进行查询条件的l装。所以现在对 Hibernate ?Criteria 深入研究一下。?Hibernate Reference 》及|上其它一些资料对 Criteria 已经做了很多介绍?/p>
最q在目中?/span> Spring ?/span> Hibernate q行开发,有感?/span> Criteria 比较好用Q在查询Ҏ设计上可以灵zȝҎ Criteria 的特Ҏ方便地进行查询条件的l装。所以现在对 Hibernate ?/span> Criteria 深入研究一下。?/span> Hibernate Reference 》及|上其它一些资料对 Criteria 已经做了很多介绍。本文主要是?/span> Criteria 的结构入手来q行分析?/span>
如图 1 ?/span> Hibernate 设计?/span> CriteriaSpecification 作ؓ Criteria 的顶U接口,其下面提供了 Criteria ?/span> DetachedCriteria ?/span>
Criteria ?/span> DetachedCriteria 的主要区别在于创建的形式不一P Criteria 是在U的Q所以它是由 Hibernate Session q行创徏的;?/span> DetachedCriteria 是离U的Q创建时无需 Session Q?/span> DetachedCriteria 提供?/span> 4 个静态方?/span> forClass(Class) ?/span> forEntityName(Name) q行 DetachedCriteria 实例的创建?/span> Spring 的框架提供了
getHibernateTemplate().findByCriteria(detachedCriteria) Ҏ可以很方便地Ҏ
DetachedCriteria 来返回查询结果?/span>
如图 1 Q?/span> Criteria ?/span> DetachedCriteria 均可使用 Criterion ?/span> Projection 讄查询条g。可以设|?/span> FetchMode( 联合查询抓取的模?/span> ) Q设|排序方式。对?/span> Criteria q可以设|?/span> FlushModel Q冲?/span> Session 的方式)?/span> LockMode Q数据库锁模式)?/span>
下面对 Criterion ?/span> Projection q行详细说明?/span>
?/span> 1
Criterion ?/span> Criteria 的查询条件?/span>
Criteria 提供?/span> add(Criterion criterion) Ҏ来添加查询条件。图 2 ?/span> Criterion 的结构图?/span> Criterion 接口的主要实现包括: Example ?/span> Junction ?/span> SimpleExpression 。?/span> Junction 的实际用是它的两个子类 conjunction ?/span> disjunction Q分别是使用 AND ?/span> OR 操作W进行来联结查询条g集合?/span>
Criterion 的实例可以通过 Restrictions 工具cL创徏Q?/span> Restrictions 提供了大量的静态方法,?/span> eq Q等于)?/span> ge Q大于等于)?/span> between {来Ҏ的创?/span> Criterion 查询条g
Q?/span> SimpleExpression 实例Q。除此之外, Restrictions q提供了Ҏ来创?/span> conjunction ?/span> disjunction 实例Q通过往该实例的 add(Criteria) Ҏ来增加查询条件Ş成一个查询条仉合?/span>
至于 Example 的创建有所不同Q?/span> Example 本n提供了一个静态方?/span> create(Object entity) Q即Ҏ一个对象(实际使用中一般是映射到数据库的对象)来创建。然后可以设|一些过滤条Ӟ
Example exampleUser =Example.create(u)
.ignoreCase() // 忽略大小?/span>
.enableLike(MatchMode.ANYWHERE);
// ?/span> String cd的属性,无论在那里值在那里都匹配。相当于 %value%
?/span>
2
Project 主要是让 Criteria 能够q行报表查询Qƈ可以实现分组?/span> Project 主要?/span> SimpleProjection ?/span> ProjectionList ?/span> Property 三个实现。其?/span> SimpleProjection ?/span> ProjectionList 的实例化是由内徏?/span> Projections 来完成,如提供的 avg ?/span> count ?/span> max ?/span> min ?/span> sum 可以让开发者很ҎҎ个字D进行统计查询?/span>
Property 是对某个字段q行查询条g的设|,如通过
Porperty.forName(“color?.in(new String[]{“black?”red?”write”}); 则可以创Z?/span> Project 实例。通过 criteria ?/span> add(Project) Ҏ加入到查询条件中厅R?/span>
?/span>
3
使用 Criteria q行查询Q主要要清晰的是 Hibernate 提供了那些类和方法来满开发中查询条g的创建和l装Q其l构层次如何。这样用v来便可得心应手?/span>
以上代码在Session范围内通过Hibernatecȝinitialize()Ҏ昑ּ初始化了Customer代理cd例,因此当Session关闭后,可以正常讉KCustomer游离对象?/font>
Distributed Objects With Hibernate
Problem:
You are building a three tier distributed system and you are passing persistent objects between tiers. When you send the objects back to the server, you want to save the only the changes.
Solutions:
1)Hibernate added the select-before-update option in 2.1. Setting this option on your class will cause Hibernate to load the data from the database and compare that to the data in your object to determine what has changed. It makes use of a version or timestamp field to enforce optimistic concurrency. This works well but introduces additional database access that could effect performance.
2)Save the original data for each persistent object and implement a custom EntityPersister to return the original state to Hibernate instead of accessing the state in the database.
Implementing Solution 2:
Step 1: Save the original state for each persistent object
The easiest way to implement this is to have each persistent object remember the original values of any properties that changed. If you make all your persistent objects proper JavaBeans, you can capture this in the base class when the object fires a propertyChanged event:
public abstract class AbstractDomainObject implements Serializable {
private PropertyChangeSupport support = new PropertyChangeSupport(this);
private Map originalValues = new HashMap();
public AbstractDomainObject() {
super();
}
public Map getOriginalState() {
return originalValues;
}
public void addPropertyChangeListener(PropertyChangeListener propertyChangeListener) {
support.addPropertyChangeListener(propertyChangeListener);
}
protected void firePropertyChange(String property, Object oldValue, Object newValue) {
if (!originalValues.containsKey(property)) {
originalValues.put(property, oldValue);
}
support.firePropertyChange(property, oldValue, newValue);
}
}
Step 2: Create your domain objects
A domain object might look like follows. Because it fires propertyChange events, the base class will remember original values of properties that changed. Note that you will want to map the properties as access=field since the setter fires a propertyChange event when called.
public class Customer extends AbstractDomainObject {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
String oldValue = this.name;
this.name = name;
firePropertyChange("name", oldValue, name);
}
}
Step 3: Create a custome entity persister
Create a custom entity persister and override getCurrentPersistentState. Set the persister for each class to this custom persister.
public Object[] getCurrentPersistentState(Serializable id, Object version, SessionImplementor session) throws HibernateException {
AbstractDomainObject entity = (AbstractDomainObject) session.getEntity(new Key(id, this));
Map originalValues = entity.getOriginalState();
Type[] types = getPropertyTypes();
String[] propertyNames = getPropertyNames();
Object[] values = new Object[propertyNames.length];
boolean[] includeProperty = getPropertyUpdateability();
for (int i = 0; i < propertyNames.length; i++) {
if (includeProperty[i]) {
if (originalValues.containsKey(propertyNames[i])) {
values[i] = types[i].disassemble(originalValues.get(propertyNames[i]), session);
} else {
values[i] = types[i].disassemble(getPropertyValue(entity, propertyNames[i]), session);
}
}
}
return values;
}
What about collections you ask? Well, Hibernate keeps track of changes to collections in the collection class wrappers for you.
Please note this solution has worked great in my example programs, but I have not yet implemented it in a production program.
Hibernate配置文g可以有两U格式,一U是hibernate.propertiesQ另一U是hibernate.cfg.xml。后者稍微方便一些,当增加hbm映射文g的时候,可以直接在hibernate.cfg.xml里面增加Q不必像hibernate.properties必须在初始化代码中加入。但不管怎么_两种的配|项都是一LQ下面详l介l:
在Hibernate的src目录下有一个hibernate.properties模板Q我们不必自׃头写Q修Ҏ板就可以?/p>
代码:
hibernate.query.substitutions true 1, false 0, yes 'Y', no 'N'
q个配置意思是当你?Hibernate里面输入true的时候,Hibernate会{化ؓ0插入数据库,当你在Hibernate里面输入false的时候, Hibernate会{化ؓ1插入数据库,后面的YQN同理。对于某些数据库Q例如Oracle来说Q没有boolean数据cdQ就是采?代表 trueQ?代表falseQ因此用这个配|在Hibernate里面直接用true/false会非常直观?
代码:
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:///test
hibernate.connection.username root
hibernate.connection.password
q是一个连接MySQL数据库的例子Q很直观Q不必解释,不同的数据库的连接参数模板中全部l出了?
代码:
hibernate.connection.pool_size 1
hibernate.statement_cache.size 25
q是Hibernate自带的连接池的配|参敎ͼ在默认情况下采用。意义很直观Q不多解释。只是提醒一点,Hibernateq个q接池是非常原始非常单的q接池,如果你在目中用Hibernate的话Q徏议你首选App Server的连接池Q次选Hibernate带的DBCPq接池。自带的q接池应该做为末选?
如果你采用DBCPq接池,除了要配|DBCPq接池以外,q需要取消掉下行的注释:
代码:
hibernate.connection.provider_class net.sf.hibernate.connection.DBCPConnectionProvider
其它的连接池同理?
如果采用App Server的连接池Q假设App Serverq接池的DataSource的JNDI名称?mypool"的话Q配|应该如下:
代码:
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.datasource mypool
hibernate.connection.provider_class net.sf.hibernate.connection.DatasourceConnectionProvider
其它参数׃必写了,因ؓ已经在App Server配置q接池的时候指定好了?
如果你不是在App Server环境中用HibernateQ例如远E客LE序Q但是你又想用App Server的数据库q接池,那么你还需要配|JNDI的参敎ͼ例如Hibernateq接q程Weblogic上的数据库连接池Q?
代码:
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.datasource mypool
hibernate.connection.provider_class net.sf.hibernate.connection.DatasourceConnectionProvider
hibernate.jndi.class weblogic.jndi.WLInitialContextFactory
hibernate.jndi.url t3://servername:7001/
最后,如果你需要在EJB或者JTA中用HibernateQ需要取消下行的注释Q?
代码:
hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
杂项配置Q?
代码:
hibernate.show_sql false
是否Hibernate发送给数据库的sql昄出来Q这是一个非帔R常有用处的功能。当你在调试Hibernate的时候,让Hibernate打印sql语句Q可以帮助你q速解决问题?
代码:
#hibernate.connection.isolation 4
指定数据库的隔离U别Q往往不同的数据库有自己定义的隔离U别Q未必是Hibernate的设|所能更改的Q所以也不必ȝ它了?
代码:
hibernate.jdbc.fetch_size 50
hibernate.jdbc.batch_size 25
q两个选项非常非常非常重要Q!Q将严重影响Hibernate的CRUD性能!
?/span> : C = create, R = read, U = update, D = delete
Fetch Size 是设定JDBC的Statementd数据的时候每ơ从数据库中取出的记录条数。例如一ơ查?万条记录Q对于Oracle的JDBC驱动来说Q是不会1ơ性把1万条取出来的Q而只会取出Fetch Size条数Q当U录集遍历完了这些记录以后,再去数据库取Fetch Size条数据。因此大大节省了无谓的内存消耗。当然Fetch Size讄大Q读数据库的ơ数少Q速度快QFetch Size小Q读数据库的ơ数多Q速度慢。这有点像^时我们写E序写硬盘文件一P讄一个BufferQ每ơ写入BufferQ等Buffer满了以后Q一ơ写入硬盘,道理相同?
Oracle数据库的JDBC驱动默认的Fetch Size=10Q是一个非怿守的讑֮Q根据我的测试,当Fetch Size=50的时候,性能会提?倍之多,当Fetch Size=100Q性能q能l箋提升20%QFetch Sizel箋增大Q性能提升的就不显著了。因此我使用Oracle的一定要?/span>Fetch Size讑ֈ50?
不过q不是所有的数据库都支持Fetch SizeҎ,例如MySQL׃支持。MySQL像我上面说的U最坏的情况Q他L一下就?万条记录完全取出来,内存消耗会非常非常惊hQ这个情况就没有什么好办法?/span> ?/span>
Batch Size是设定对数据库进行批量删除,扚w更新和批量插入的时候的Ҏ大小Q有点相当于讄Buffer~冲区大的意思。Batch Size大Q批量操作的向数据库发送sql的次数越,速度p快。我做的一个测试结果是当Batch Size=0的时候,使用Hibernate对Oracle数据库删?万条记录需?5U,Batch Size = 50的时候,删除仅仅需?U!Q!可见有多么大的性能提升Q很多h做Hibernate和JDBC的插入性能试会奇怪的发现Hibernate速度臛_是JDBC的两倍,是因ؓHibernate使用了Batch InsertQ而他们写的JDBC没有使用Batch的缘故。以我的l验来看Q?span style="COLOR: red">Oracle数据?Batch Size = 30 的时候比较合适,50也不错,性能会l提?/span>Q?0以上Q性能提升的非常微弱,反而消耗内存更加多Q就没有必要了?
代码:
#hibernate.jdbc.use_scrollable_resultset true
讑֮是否可以使用JDBC2.0规范的可滚动l果集,q对Hibernate的分|C有一定的作用Q默认就好了?
代码:
#hibernate.cglib.use_reflection_optimizer false
默认打开Q启用cglib反射优化。cglib是用来在Hibernate中动态生成PO字节码的Q打开优化可以加快字节码构造的速度?
不过Q当你在调试E序q程中,特别是和proxyQlazy loading相关的应用中Q代码出错,但是出错提示信息有语焉不详,那么你可以把cglib优化xQ这样Hibernate会输出比较详l的调试信息Q帮助你debug?/p>
hibernate2 升为hibernate3的需要注意的?br />
1.首先hibernate2.jar替换为hibernate3.jar(hibernate-3.0.5)
hibernate-tools.jar也替换成新的(从hibernate-tools-3.0.0.alpha4a扑և来的)
2.所有程序中的net.sf.hibernate替换为org.hibernate.
3.但是有例?br />net.sf.hibernate.expression.Expression换ؓorg.hibernate.criterion.Expression
如果用eclipse,用ctrl+shift+o快捷键可以加快速度
4.在用hql查询时将
createSQLQuery(hql,"c",EZCampaignDTO.class);改ؓcreateSQLQuery(hql).addEntity("c",EZCampaignDTO.class);
5.在批量插入时
原来的int size = ((SessionFactoryImpl)(session.getSessionFactory())).getJdbcBatchSize()
改ؓint size = ((SessionFactoryImpl)(session.getSessionFactory())).getSettings().getJdbcBatchSize();
6.在计count?br />原来的int size = ((Integer) session.iterate(hql).next()).intValue();
改ؓint size = ((Integer) session.createQuery(hql).iterate().next()).intValue();
其中hql="select count(*) from " + DAOVar.contactClass;
7.q有是?hbm中的hibernate-mapping-2.0.dtd替换为hibernate-mapping-3.0.dtd
Hibernate Mapping DTD 2.0替换为Hibernate Mapping DTD 3.0
8.hibernate.cfg.xml?br />Hibernate Mapping DTD 2.0替换为Hibernate Mapping DTD 3.0
<property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
9.hibernate.properties中类?br />
10.cache-config.xml?br /><provider className="net.sf.hibernate.cache.OSCacheProvider"/>替换?br /><provider className="org.hibernate.cache.OSCacheProvider"/>
11.classeshibernate.properties?br />hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
hibernate.dialect=org.hibernate.dialect.SQLServerDialect
晕s?怎么q里q有
q是用编辑器暴力替换一下吧q脆
然后部v,集成试,希望一切ok
l果咣铛,q是报错
12.在自动外部模块部分有一个功能是Ҏ模版自动生成.hbm文g在load,l果出来?hbm中有问题:
生成?<composite-id unsaved-value="any" mapped="false">其中mapped="false" 出错.
找了半天才发现在|上的hibernate-mapping-3.0.dtd文g有支持mapped="false"q个属?而本地的hebernate3.0.5中的
hibernate-mapping-3.0.dtd文g没有q个属??hibernate也太不负责了? 解决办法把hibernate-mapping-3.0.dtd
copy到jboss\bin目录下然?在template文g?br /><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "hibernate-mapping-3.0.dtd">
然后他会在jboss\bin目录下读取该文g
13.重新试,q是咣铛
发现子类ȝcL据时抛出异常
"org.hibernate.LazyInitializationException: could not initialize proxy"
延迟抓取出的?hb3对many-to-one的默认处理是lazy = "proxy"
没有搞懂到底怎么回事,把所有many-to-one,one-to-one都加上lazy="false"
再测试终于大功告?/span>
在用hibernateq程中经常碰C些异常,有些很常见,l过个hl验和网上的搜集Q也ȝ一下:
一.CGLIB异常
org.springframework.orm.hibernate.HibernateSystemException: exception setting property value with CGLIB (set hibernate.cglib.use_reflection_optimizer=false for more info) setter of com.anyi.fa.model.FaCard.setCardND; nested exception is net.sf.hibernate.PropertyAccessException: exception setting property value with CGLIB (set hibernate.cglib.use_reflection_optimizer=false for more info) setter of com.anyi.fa.model.FaCard.setCardND
net.sf.hibernate.PropertyAccessException: exception setting property value with CGLIB (set hibernate.cglib.use_reflection_optimizer=false for more info) setter of com.anyi.fa.model.FaCard.setCardND
at net.sf.hibernate.persister.AbstractEntityPersister.setPropertyValues(AbstractEntityPersister.java:220)
at net.sf.hibernate.impl.SessionImpl.initializeEntity(SessionImpl.java:2224)
at net.sf.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:319)
at net.sf.hibernate.loader.Loader.doQuery(Loader.java:309)
at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:138)
at net.sf.hibernate.loader.Loader.loadEntity(Loader.java:941)
at net.sf.hibernate.loader.Loader.loadEntity(Loader.java:961)
at net.sf.hibernate.loader.EntityLoader.load(EntityLoader.java:59)
at net.sf.hibernate.loader.EntityLoader.load(EntityLoader.java:51)
at net.sf.hibernate.persister.EntityPersister.load(EntityPersister.java:413)
at net.sf.hibernate.impl.SessionImpl.doLoad(SessionImpl.java:2131)
此中异常比较常见Q一般是因ؓnull造成的。例如:一个int映射到数据库中,但从数据库读取时是nullD样就会出现此中异常?/p>
解决方式Q如果允ؓI的字段做一包装Qint-->Integer,long-->LongQdouble--->Double{)Q其实这在系l设计时应该根据实际情况考虑到的?/p>
?。gq加载问?/p>
net.sf.hibernate.LazyInitializationException:
Failed to lazily initialize a collection - no session or session was closed
此类问题也是比较常见的,一般是׃采用了gq加载机?lazy=true)Q在session关闭之后又调用gq加载的数据或方法造成的?/font>
解决方式:
在session关闭之前dQ或调用HIbernate.initalize()Ҏ?/font>
?BigDecimal属性映时要指定小C数?/font>
?其他是一些联更新删除,d建约束错误,操作主,子表序的问题了Q一般比较容易解?
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1108781
// Fields
private AllTablePbId id;
// Property accessors
public AllTablePbId getId() {
return this.id;
}
public void setId(AllTablePbId id) {
this.id = id;
}
}
public class AllTablePbId implements java.io.Serializable {
// Fields
private String owner;
private String tableName;
private String columnName;
private String dataType;
private String pbcCnam;
private String pbcCmnt;
// Property accessors
public String getOwner() {
return this.owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public String getTableName() {
return this.tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getColumnName() {
return this.columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getDataType() {
return this.dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public String getPbcCnam() {
return this.pbcCnam;
}
public void setPbcCnam(String pbcCnam) {
this.pbcCnam = pbcCnam;
}
public String getPbcCmnt() {
return this.pbcCmnt;
}
public void setPbcCmnt(String pbcCmnt) {
this.pbcCmnt = pbcCmnt;
}
}
配置文gQ?br /><hibernate-mapping>
<class name="com.hhkj.workflow.bean.AllTablePb" table="V_ALLTAB_PB" schema="CANP">
<composite-id name="id" class="com.hhkj.workflow.bean.AllTablePbId">
<key-property name="owner" type="string">
<column name="OWNER" length="30" />
</key-property>
<key-property name="tableName" type="string">
<column name="TABLE_NAME" length="30" />
</key-property>
<key-property name="columnName" type="string">
<column name="COLUMN_NAME" length="30" />
</key-property>
<key-property name="dataType" type="string">
<column name="DATA_TYPE" length="106" />
</key-property>
<key-property name="pbcCnam" type="string">
<column name="PBC_CNAM" length="30" />
</key-property>
<key-property name="pbcCmnt" type="string">
<column name="PBC_CMNT" length="254" />
</key-property>
</composite-id>
</class>
</hibernate-mapping>
q样可以通过AllTablePb.getId()取得相关的信息?br /> 感觉myeclipse的确不错Q特别是对于使用hibernateq不是非常熟l的人来_通过它可以帮解决不少问题?br /> 通过q样对视囄操作Q同样也可以用到对于那些没有定义主键的表Q操作方法是一L?br /> 呵呵Q个人的一点体会,Ƣ迎大家多提意见?/p>