??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(已装?jin)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)?什么都不作,不会(x)存在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)?什么都不作,不会(x)存在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)
只有讄?jin)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 (?, ?)
可见,插入?jin)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|,因ؓ(f)没有U联关系,所以course记录d不进?造成外健p|
b) 删除记录情况
Student student=(Student)session.load(Student.class,new Integer(22));
session.delete(student);
正常,删除?jin)student表中的记录student(22),同时删除?jin)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 子目录,Ҏ(gu)我们实际采用的数据库打开对应的配|文件。如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以及(qing)数据库用
户名和密码?/p>
1) 修改Build.xml
修改MiddleGen 根目录下的build.xml 文gQ此文g是Middlegen-Hibernate 的Ant构徏配置。Middlegen-Hibernate根据build.xml文g中的具体参数生成数据库表映射文g。可配置的项目包括:(x)
a) 目标数据库配|文件地址
查找关键?”!ENTITY”Q得刎ͼ(x)
<!DOCTYPE project [
<!ENTITY database SYSTEM
"file:./config/database/hsqldb.xml">
]>
默认情况下,MiddleGen 采用的是hsqldb.xmlQ?br>其修改为我们所用的数据库配|文Ӟmysql.xmlQ:(x)
<!DOCTYPE project [
<!ENTITY database SYSTEM
"file:./config/database/mysql.xml">
]>
b) Application name
查找Q?br><property value="airline"/>
“aireline”是MiddleGen原始配置中默认的 Application NameQ将其修改ؓ(f)我们
所希望的名Uͼ?#8220;HibernateSample”Q?br><property value="HibernateSample"/>
c) 输出目录
查找关键?#8220;name="build.gen-src.dir"”Q得刎ͼ(x)
<property
value="${build.dir}/gen-src"/>
修改value="${build.dir}/gen-src"使其指向我们所期望的输出目录,
q里我们修改为:(x)<property
value="C:\sample"/>
d) 对应代码的Package name
查找关键?#8220;destination”Q得刎ͼ(x)
<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如果设|ؓ(f)trueQ则生成的代码将包含
xdoclet tagQ这Z后在开发过E中借助xdocletq行映射调整提供?jin)帮助。注意,如果使用的数据库为SQLServerQ需要将build.xml部分删除(参见?^的文?Q否则Middlegen?x)报出找不到表的错误?br>x(chng)为止QMiddleGen 已经配置完毕Q在MiddleGen 根目录下q行antQ就出?br>MiddleGen的界面:(x)
2 *.xml?java
在得?xml?使用ant hbm2java 卛_得到相应的java文g
ȝ:
我第一ơ运行成?但是后来则出现如下类似错?(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()是不?x)放出来的。所以在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)不会(x)起作用!
(4)׃有了(jin)FK保护Q你是无法单独删除User的。同Ӟ׃你指定了(jin)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在查询Ҏ(gu)设计上可以灵zȝҎ(gu) Criteria 的特Ҏ(gu)方便地进行查询条件的l装。所以现在对 Hibernate ?Criteria 深入研究一下。?Hibernate Reference 》及(qing)|上其它一些资料对 Criteria 已经做了(jin)很多介绍?/p>
最q在目中?/span> Spring ?/span> Hibernate q行开发,有感?/span> Criteria 比较好用Q在查询Ҏ(gu)设计上可以灵zȝҎ(gu) Criteria 的特Ҏ(gu)方便地进行查询条件的l装。所以现在对 Hibernate ?/span> Criteria 深入研究一下。?/span> Hibernate Reference 》及(qing)|上其它一些资料对 Criteria 已经做了(jin)很多介绍。本文主要是?/span> Criteria 的结构入手来q行分析?/span>
(tng) (tng) (tng) (tng) (tng) (tng) 如图 1 ?/span> Hibernate 设计?/span> CriteriaSpecification 作ؓ(f) Criteria 的顶U接口,其下面提供了(jin) Criteria ?/span> DetachedCriteria ?/span>
Criteria ?/span> DetachedCriteria 的主要区别在于创建的形式不一P Criteria 是在U的Q所以它是由 Hibernate Session q行创徏的;?/span> DetachedCriteria 是离U的Q创建时无需 Session Q?/span> DetachedCriteria 提供?/span> 4 个静(rn)态方?/span> forClass(Class) ?/span> forEntityName(Name) q行 DetachedCriteria 实例的创建?/span> Spring 的框架提供了(jin)
getHibernateTemplate().findByCriteria(detachedCriteria) Ҏ(gu)可以很方便地Ҏ(gu)
DetachedCriteria 来返回查询结果?/span>
如图 1 Q?/span> Criteria ?/span> DetachedCriteria 均可使用 Criterion ?/span> Projection 讄查询条g。可以设|?/span> FetchMode( 联合查询抓取的模?/span> ) Q设|排序方式。对?/span> Criteria q可以设|?/span> FlushModel Q冲?/span> Session 的方式)(j)?/span> LockMode Q数据库锁模式)(j)?/span>
下面对 Criterion ?/span> Projection q行详细说明?/span>
(tng) (tng) (tng) (tng) (tng) (tng)
?/span> 1
(tng) (tng) (tng) (tng) (tng) (tng) Criterion ?/span> Criteria 的查询条件?/span>
Criteria 提供?/span> add(Criterion criterion) Ҏ(gu)来添加查询条件。图 2 ?/span> Criterion 的结构图?/span> Criterion 接口的主要实现包括:(x) Example ?/span> Junction ?/span> SimpleExpression 。?/span> Junction 的实际用是它的两个子类 conjunction ?/span> disjunction Q分别是使用 AND ?/span> OR 操作W进行来联结查询条g集合?/span>
Criterion 的实例可以通过 Restrictions 工具cL创徏Q?/span> Restrictions 提供?jin)大量的静(rn)态方法,?/span> eq Q等于)(j)?/span> ge Q大于等于)(j)?/span> between {来Ҏ(gu)的创?/span> Criterion 查询条g
Q?/span> SimpleExpression 实例Q。除此之外, Restrictions q提供了(jin)Ҏ(gu)来创?/span> conjunction ?/span> disjunction 实例Q通过往该实例的 add(Criteria) Ҏ(gu)来增加查询条件Ş成一个查询条仉合?/span>
至于 Example 的创建有所不同Q?/span> Example 本n提供?jin)一个静(rn)态方?/span> create(Object entity) Q即Ҏ(gu)一个对象(实际使用中一般是映射到数据库的对象)(j)来创建。然后可以设|一些过滤条Ӟ(x)
Example exampleUser =Example.create(u)
.ignoreCase() // 忽略大小?/span>
.enableLike(MatchMode.ANYWHERE);
// ?/span> String cd的属性,无论在那里值在那里都匹配。相当于 %value%
?/span>
2
(tng) (tng) (tng) (tng) (tng) (tng)
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 可以让开发者很Ҏ(gu)Ҏ(gu)个字D进行统计查询?/span>
(tng) (tng) (tng) (tng) (tng) (tng) Property 是对某个字段q行查询条g的设|,如通过
(tng) (tng) (tng) (tng) (tng) Porperty.forName(“color?.in(new String[]{“black?”red?”write”}); 则可以创Z?/span> Project 实例。通过 criteria ?/span> add(Project) Ҏ(gu)加入到查询条件中厅R?/span>
?/span>
3
(tng) (tng) (tng) (tng) (tng) (tng)
(tng) (tng) (tng) (tng) (tng) (tng) 使用 Criteria q行查询Q主要要清晰的是 Hibernate 提供?jin)那些类和方法来满开发中查询条g的创建和l装Q其l构层次如何。这样用v来便可得?j)应手?/span>
(tng)以上代码在Session范围内通过Hibernatecȝinitialize()Ҏ(gu)昑ּ初始化了(jin)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必须在初始化代码中加入。但不管怎么_(d)两种的配|项都是一L(fng)Q下面详l介l:(x)
在Hibernate的src目录下有一个hibernate.properties模板Q我们不必自׃头写Q修Ҏ(gu)板就可以?/p>
代码:
hibernate.query.substitutions true 1, false 0, yes 'Y', no 'N'
q个配置意思是当你?Hibernate里面输入true的时候,Hibernate?x){化ؓ(f)0插入数据库,当你在Hibernate里面输入false的时候, Hibernate?x){化ؓ(f)1插入数据库,后面的YQN同理。对于某些数据库Q例如Oracle来说Q没有boolean数据cdQ就是采?代表 trueQ?代表falseQ因此用这个配|在Hibernate里面直接用true/false?x)非常直观?
代码:
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出?jin)?
代码:
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接池,除了(jin)要配|DBCPq接池以外,q需要取消掉下行的注释:(x)
代码:
hibernate.connection.provider_class net.sf.hibernate.connection.DBCPConnectionProvider
其它的连接池同理?
如果采用App Server的连接池Q假设App Serverq接池的DataSource的JNDI名称?mypool"的话Q配|应该如下:(x)
代码:
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.datasource mypool
hibernate.connection.provider_class net.sf.hibernate.connection.DatasourceConnectionProvider
其它参数׃必写?jin),因?f)已经在App Server配置q接池的时候指定好?jin)?
如果你不是在App Server环境中用HibernateQ例如远E客L(fng)E序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所以也不必ȝ它了(jin)?
代码:
hibernate.jdbc.fetch_size 50
hibernate.jdbc.batch_size 25
q两个选项非常非常非常重要Q!Q将严重影响Hibernate的CRUD性能!
: C = create, R = read, U = update, D = delete
Fetch Size 是设定JDBC的Statementd数据的时候每ơ从数据库中取出的记录条数。例如一ơ查?万条记录Q对于Oracle的JDBC驱动来说Q是不会(x)1ơ性把1万条取出来的Q而只?x)取出Fetch Size条数Q当U录集遍历完?jin)这些记录以后,再去数据库取Fetch Size条数据。因此大大节省了(jin)无谓的内存消耗。当然Fetch Size讄大Q读数据库的ơ数少Q速度快QFetch Size小Q读数据库的ơ数多Q速度慢。这有点像^时我们写E序写硬盘文件一P讄一个BufferQ每ơ写入BufferQ等Buffer满了(jin)以后Q一ơ写入硬盘,道理相同?
Oracle数据库的JDBC驱动默认的Fetch Size=10Q是一个非怿守的讑֮Q根据我的测试,当Fetch Size=50的时候,性能?x)提?倍之多,当Fetch Size=100Q性能q能l箋(hu)提升20%QFetch Sizel箋(hu)增大Q性能提升的就不显著了(jin)。因此我使用Oracle的一定要?/span>Fetch Size讑ֈ50?
不过q不是所有的数据库都支持Fetch SizeҎ(gu),例如MySQL׃支持。MySQL像我上面说的那U最坏的情况Q他L一下就?万条记录完全取出来,内存消耗会(x)非常非常惊hQ这个情况就没有什么好办法?/span> (tng)
Batch Size是设定对数据库进行批量删除,扚w更新和批量插入的时候的Ҏ(gu)大小Q有点相当于讄Buffer~冲区大的意思。Batch Size大Q批量操作的向数据库发送sql的次数越,速度p快。我做的一个测试结果是当Batch Size=0的时候,使用Hibernate对Oracle数据库删?万条记录需?5U,Batch Size = 50的时候,删除仅仅需?U!Q!可见有多么大的性能提升Q很多h做Hibernate和JDBC的插入性能试?x)奇怪的发现Hibernate速度臛_是JDBC的两倍,是因ؓ(f)Hibernate使用?jin)Batch InsertQ而他们写的JDBC没有使用Batch的缘故。以我的l验来看Q?span style="COLOR: red">Oracle数据?Batch Size = 30 的时候比较合适,50也不错,性能?x)l提?/span>Q?0以上Q性能提升的非常微弱,反而消耗内存更加多Q就没有必要?jin)?
代码:
#hibernate.jdbc.use_scrollable_resultset true
讑֮是否可以使用JDBC2.0规范的可滚动l果集,q对Hibernate的分|C有一定的作用Q默认就好了(jin)?
代码:
#hibernate.cglib.use_reflection_optimizer false
默认打开Q启用cglib反射优化。cglib是用来在Hibernate中动态生成PO字节码的Q打开优化可以加快字节码构造的速度?
不过Q当你在调试E序q程中,特别是和proxyQlazy loading相关的应用中Q代码出错,但是出错提示信息有语焉不详,那么你可以把cglib优化x(chng)Q这样Hibernate?x)输出比较详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换ؓ(f)org.hibernate.criterion.Expression
如果用eclipse,用ctrl+shift+o快捷键可以加快速度
4.在用hql查询时将
createSQLQuery(hql,"c",EZCampaignDTO.class);改ؓ(f)createSQLQuery(hql).addEntity("c",EZCampaignDTO.class);
5.在批量插入时
原来的int size = ((SessionFactoryImpl)(session.getSessionFactory())).getJdbcBatchSize()
改ؓ(f)int size = ((SessionFactoryImpl)(session.getSessionFactory())).getSettings().getJdbcBatchSize();
6.在计count?br />原来的int size = ((Integer) session.iterate(hql).next()).intValue();
改ؓ(f)int size = ((Integer) session.createQuery(hql).iterate().next()).intValue();
其中h(hun)ql="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.在自动外部模块部分有一个功能是Ҏ(gu)模版自动生成.hbm文g在load,l果出来?hbm中有问题:
生成?<composite-id unsaved-value="any" mapped="false">其中mapped="false" 出错.
找了(jin)半天才发现在|上的hibernate-mapping-3.0.dtd文g有支持mapped="false"q个属?而本地的hebernate3.0.5中的
hibernate-mapping-3.0.dtd文g没有q个属??hibernate也太不负责了(jin)? 解决办法把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">
然后他会(x)在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也ȝ一下:(x)
一.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
(tng)at net.sf.hibernate.persister.AbstractEntityPersister.setPropertyValues(AbstractEntityPersister.java:220)
(tng)at net.sf.hibernate.impl.SessionImpl.initializeEntity(SessionImpl.java:2224)
(tng)at net.sf.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:319)
(tng)at net.sf.hibernate.loader.Loader.doQuery(Loader.java:309)
(tng)at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:138)
(tng)at net.sf.hibernate.loader.Loader.loadEntity(Loader.java:941)
(tng)at net.sf.hibernate.loader.Loader.loadEntity(Loader.java:961)
(tng)at net.sf.hibernate.loader.EntityLoader.load(EntityLoader.java:59)
(tng)at net.sf.hibernate.loader.EntityLoader.load(EntityLoader.java:51)
(tng)at net.sf.hibernate.persister.EntityPersister.load(EntityPersister.java:413)
(tng)at net.sf.hibernate.impl.SessionImpl.doLoad(SessionImpl.java:2131)
(tng)此中异常比较常见Q一般是因ؓ(f)null造成的。例如:(x)一个int映射到数据库中,但从数据库读取时是nullD样就?x)出现此中异常?/p>
解决方式Q如果允ؓ(f)I的字段做一包装Qint-->Integer,long-->LongQdouble--->Double{)(j)Q其实这在系l设计时应该根据实际情况考虑到的?/p>
?。gq加载问?/p>
net.sf.hibernate.LazyInitializationException:
(tng)Failed to lazily initialize a collection - no session or session was closed
此类问题?sh)是比较常见的,一般是׃采用?jin)gq加载机?lazy=true)Q在session关闭之后又调用gq加载的数据或方法造成的?/font>
解决方式:
(tng) (tng) 在session关闭之前dQ或调用HIbernate.initalize()Ҏ(gu)?/font>
?BigDecimal属性映时要指定小C数?/font>
?其他是一些联更新删除,d建约束错误,操作主,子表序的问题(sh)(jin)Q一般比较容易解? (tng)
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1108781
(tng)// Fields
(tng)private AllTablePbId id;
(tng)// Property accessors
(tng)public AllTablePbId getId() {
(tng) return this.id;
(tng)}
(tng)public void setId(AllTablePbId id) {
(tng) this.id = id;
(tng)}
}
public class AllTablePbId implements java.io.Serializable {
(tng)// Fields
(tng)private String owner;
(tng)private String tableName;
(tng)private String columnName;
(tng)private String dataType;
(tng)private String pbcCnam;
(tng)private String pbcCmnt;
(tng)// Property accessors
(tng)public String getOwner() {
(tng) return this.owner;
(tng)}
(tng)public void setOwner(String owner) {
(tng) this.owner = owner;
(tng)}
(tng)public String getTableName() {
(tng) return this.tableName;
(tng)}
(tng)public void setTableName(String tableName) {
(tng) this.tableName = tableName;
(tng)}
(tng)public String getColumnName() {
(tng) return this.columnName;
(tng)}
(tng)public void setColumnName(String columnName) {
(tng) this.columnName = columnName;
(tng)}
(tng)public String getDataType() {
(tng) return this.dataType;
(tng)}
(tng)public void setDataType(String dataType) {
(tng) this.dataType = dataType;
(tng)}
(tng)public String getPbcCnam() {
(tng) return this.pbcCnam;
(tng)}
(tng)public void setPbcCnam(String pbcCnam) {
(tng) this.pbcCnam = pbcCnam;
(tng)}
(tng)public String getPbcCmnt() {
(tng) return this.pbcCmnt;
(tng)}
(tng)public void setPbcCmnt(String pbcCmnt) {
(tng) this.pbcCmnt = pbcCmnt;
(tng)}
}
配置文gQ?br /><hibernate-mapping>
(tng)<class name="com.hhkj.workflow.bean.AllTablePb" table="V_ALLTAB_PB" schema="CANP">
(tng) <composite-id name="id" class="com.hhkj.workflow.bean.AllTablePbId">
(tng) (tng) <key-property name="owner" type="string">
(tng) (tng) (tng) <column name="OWNER" length="30" />
(tng) (tng) </key-property>
(tng) (tng) <key-property name="tableName" type="string">
(tng) (tng) (tng) <column name="TABLE_NAME" length="30" />
(tng) (tng) </key-property>
(tng) (tng) <key-property name="columnName" type="string">
(tng) (tng) (tng) <column name="COLUMN_NAME" length="30" />
(tng) (tng) </key-property>
(tng) (tng) <key-property name="dataType" type="string">
(tng) (tng) (tng) <column name="DATA_TYPE" length="106" />
(tng) (tng) </key-property>
(tng) (tng) <key-property name="pbcCnam" type="string">
(tng) (tng) (tng) <column name="PBC_CNAM" length="30" />
(tng) (tng) </key-property>
(tng) (tng) <key-property name="pbcCmnt" type="string">
(tng) (tng) (tng) <column name="PBC_CMNT" length="254" />
(tng) (tng) </key-property>
(tng) </composite-id>
(tng)</class>
</hibernate-mapping>
q样可以通过AllTablePb.getId()取得相关的信息?br /> (tng) (tng) (tng) (tng) (tng) 感觉myeclipse的确不错Q特别是对于使用hibernateq(sh)是非常熟l的人来_(d)通过它可以帮解决不少问题?br /> (tng) (tng) (tng) (tng) (tng) 通过q样对视囄操作Q同样也可以用到对于那些没有定义主键的表Q操作方法是一L(fng)?br /> (tng) (tng) (tng) (tng) (tng) 呵呵Q个人的一点体?x),Ƣ迎大家多提意见?/p>