??xml version="1.0" encoding="utf-8" standalone="yes"?>
设计上可以灵zȝҎ Criteria 的特Ҏ方便地进行查询条件的l装。现在对
Hibernate的Criteria 的用法进行ȝQ?/font>
Hibernate 设计?CriteriaSpecification 作ؓ Criteria 的父接口Q下面提供了
Criteria和DetachedCriteria ?
Criteria ?DetachedCriteria
的主要区别在于创建的形式不一P Criteria 是在U的Q所
以它是由 Hibernate Session q行创徏的;?DetachedCriteria 是离U的Q创建时无需
SessionQDetachedCriteria 提供?2 个静态方?
forClass(Class) ?forEntityName(Name)
q行DetachedCriteria 实例的创建?Spring
的框架提供了getHibernateTemplate
().findByCriteria(detachedCriteria) Ҏ可以很方便地ҎDetachedCriteria
来返回查询结
果?
Criteria ?DetachedCriteria 均可使用 Criterion ?Projection 讄查询条g。可以设
|?FetchMode( 联合查询抓取的模?) Q设|排序方式。对?
Criteria q可以设|?FlushModel
Q冲?Session 的方式)?LockMode Q数据库锁模式)?
下面?Criterion ?Projection q行详细说明?/font>
Criterion ?Criteria
的查询条件。Criteria 提供?add(Criterion criterion) Ҏ?/font>
d查询条g?br />
Criterion 接口的主要实现包括:
Example ?Junction ?SimpleExpression 。?
Junction 的实际用是它的两个子类 conjunction ?disjunction
Q分别是使用 AND ?OR ?/font>
作符q行来联
l查询条仉合?br />
Criterion 的实例可以通过 Restrictions 工具cL创徏QRestrictions
提供了大量的静?/font>
ҎQ如 eq Q等于)?
ge Q大于等于)?between {来Ҏ的创?Criterion 查询条g
QSimpleExpression 实例Q。除此之外, Restrictions q提供了Ҏ来创?
conjunction ?
disjunction
实例Q通过往该实例的 add(Criteria) Ҏ来增加查询条件Ş成一个查询条仉?/font>
?br />
至于 Example 的创建有所不同Q?Example
本n提供了一个静态方?create(Object
entity) Q即Ҏ一个对象(实际使用中一般是映射到数据库的对象)来创建。然后可以设|一?/font>
qo条gQ?
Example exampleUser
=Example.create(u)
.ignoreCase() // 忽略大小?
.enableLike(MatchMode.ANYWHERE);
// ?String cd的属性,无论在那里值在那里都匹配。相当于 %value%
Project 主要是让 Criteria
能够q行报表查询Qƈ可以实现分组?Project 主要?
SimpleProjection ?ProjectionList ?Property 三个实现。其?
SimpleProjection ?
ProjectionList
的实例化是由内徏?Projections 来完成,如提供的 avg ?count ?max ?
min ?sum 可以让开发者很ҎҎ个字D进行统计查询?
Property 是对某个字段q行查询条g的设|,如通过Porperty.forName(“color”).in
(new String[]{“black”,”red”,”write”});
则可以创Z?Project 实例。通过
criteria
?add(Project) Ҏ加入到查询条件中厅R?
使用 Criteria q行查询Q主要要清晰的是 Hibernate 提供了那些类和方法来满开发中?/font>
询条件的创徏和组装,下面介绍几种用法Q?/font>
1. 创徏一个Criteria 实例
org.hibernate.Criteria
接口表示特定持久cȝ一个查询。Session?Criteria实例的工厂?br />
Criteria crit =
sess.createCriteria(Cat.class);
crit.setMaxResults(50);
List cats =
crit.list();
2. 限制l果集内?br />
一个单独的查询条g?
org.hibernate.criterion.Criterion 接口的一个实例?/font>
org.hibernate.criterion.Restrictionsc?
定义了获得某些内|Criterioncd的工厂方法?br />
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add(
Restrictions.between("weight", minWeight, maxWeight) )
.list();
U束可以按逻辑分组?
List cats =
sess.createCriteria(Cat.class)
.add( Restrictions.like("name",
"Fritz%") )
.add( Restrictions.or(
Restrictions.eq(
"age", new Integer(0) ),
Restrictions.isNull("age")
) )
.list();
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
.add( Restrictions.disjunction()
.add(
Restrictions.isNull("age") )
.add( Restrictions.eq("age", new
Integer(0) ) )
.add( Restrictions.eq("age", new Integer(1) )
)
.add( Restrictions.eq("age", new Integer(2) ) )
) )
.list();
Hibernate提供了相当多的内|criterioncd(Restrictions 子类),
但是其有用的是可以允许
你直接?
SQL?br />
List cats = sess.createCriteria(Cat.class)
.add(
Restrictions.sql("lower({alias}.name) like lower(?)", "Fritz%",
Hibernate.STRING) )
.list();
{alias}
占位W应当被替换查询实体的列别名?
Property实例是获得一个条件的另外一U途径。你可以通过调用
Property.forName() 创徏一?/font>
Property?
Property age = Property.forName("age");
List
cats = sess.createCriteria(Cat.class)
.add(
Restrictions.disjunction()
.add( age.isNull() )
.add( age.eq( new Integer(0) ) )
.add( age.eq( new Integer(1)
) )
.add( age.eq( new Integer(2) ) )
) )
.add(
Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
.list();
3. l果集排?br />
你可以用org.hibernate.criterion.Order来ؓ查询l果?
序?
List cats = sess.createCriteria(Cat.class)
.add(
Restrictions.like("name", "F%")
.addOrder( Order.asc("name") )
.addOrder( Order.desc("age") )
.setMaxResults(50)
.list();
List cats = sess.createCriteria(Cat.class)
.add(
Property.forName("name").like("F%") )
.addOrder(
Property.forName("name").asc() )
.addOrder(
Property.forName("age").desc() )
.setMaxResults(50)
.list();
4. 兌
你可以用createCriteria()非常Ҏ的在互相兌的实体间建立 U束?br />
List
cats = sess.createCriteria(Cat.class)
.add(
Restrictions.like("name", "F%")
.createCriteria("kittens")
.add( Restrictions.like("name", "F%")
.list();
注意W二?createCriteria()q回一个新?
Criteria实例Q该实例引用kittens 集合中的元素?
接下来,替换形态在某些情况下也是很有用的?br />
List
cats = sess.createCriteria(Cat.class)
.createAlias("kittens",
"kt")
.createAlias("mate", "mt")
.add(
Restrictions.eqProperty("kt.name", "mt.name") )
.list();
(createAlias()q不创徏一个新?Criteria实例?
Cat实例所保存的之前两ơ查询所q回的kittens集合?没有被条仉qo的。如果你希望只获?/font>
W合条g的kittensQ?你必M用returnMaps()?
List
cats = sess.createCriteria(Cat.class)
.createCriteria("kittens",
"kt")
.add( Restrictions.eq("name", "F%") )
.returnMaps()
.list();
Iterator iter = cats.iterator();
while ( iter.hasNext() )
{
Map map = (Map) iter.next();
Cat cat = (Cat)
map.get(Criteria.ROOT_ALIAS);
Cat kitten = (Cat) map.get("kt");
}
5. 动态关联抓?br />
你可以用setFetchMode()在运行时定义?
态关联抓取的语义?
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.setFetchMode("mate",
FetchMode.EAGER)
.setFetchMode("kittens", FetchMode.EAGER)
.list();
q个查询可以通过外连接抓取mate和kittens?br />
6. 查询CZ
org.hibernate.criterion.Example
cd怽通过一个给定实?构徏一个条件查询?br />
Cat cat = new Cat();
cat.setSex('F');
cat.setColor(Color.BLACK);
List
results = session.createCriteria(Cat.class)
.add(
Example.create(cat) )
.list();
版本属性、标识符和关联被忽略。默认情况下gؓnull的属性将被排除?
可以自行调整
Example使之更实用?
Example example = Example.create(cat)
.excludeZeroes() //exclude zero valued properties
.excludeProperty("color") //exclude the property named "color"
.ignoreCase() //perform case insensitive string comparisons
.enableLike(); //use like for string comparisons
List
results = session.createCriteria(Cat.class)
.add(example)
.list();
甚至可以使用
examples在关联对象上攄条g?br />
List results =
session.createCriteria(Cat.class)
.add( Example.create(cat) )
.createCriteria("mate")
.add( Example.create( cat.getMate() )
)
.list();
7.
投媄(Projections)、聚合(aggregationQ和分组QgroupingQ?br />
org.hibernate.criterion.Projections
?Projection 的实例工厂。我们通过调用
setProjection()应用投媄C个查询?
List results =
session.createCriteria(Cat.class)
.setProjection(
Projections.rowCount() )
.add( Restrictions.eq("color",
Color.BLACK) )
.list();
List results =
session.createCriteria(Cat.class)
.setProjection(
Projections.projectionList()
.add( Projections.rowCount() )
.add( Projections.avg("weight") )
.add(
Projections.max("weight") )
.add(
Projections.groupProperty("color") )
)
.list();
在一个条件查询中没有必要昑ּ的?"group
by" 。某些投q型就是被定义?分组投媄Q他
们也出现在SQL的group by子句中?
可以选择把一个别名指z一个投影,q样可以使投影DU束或排序所引用。下面是两种不同?/font>
实现方式Q?br />
List results =
session.createCriteria(Cat.class)
.setProjection(
Projections.alias( Projections.groupProperty("color"), "colr" ) )
.addOrder( Order.asc("colr") )
.list();
List results =
session.createCriteria(Cat.class)
.setProjection(
Projections.groupProperty("color").as("colr") )
.addOrder(
Order.asc("colr") )
.list();
alias()和as()Ҏ便的一个投影实例包装到?
外一?别名的Projection实例中。简而言之,
当你d一个投影到一个投影列表中?你可以ؓ它指定一个别名:
List results =
session.createCriteria(Cat.class)
.setProjection(
Projections.projectionList()
.add( Projections.rowCount(),
"catCountByColor" )
.add( Projections.avg("weight"),
"avgWeight" )
.add( Projections.max("weight"), "maxWeight" )
.add( Projections.groupProperty("color"), "color" )
)
.addOrder( Order.desc("catCountByColor") )
.addOrder(
Order.desc("avgWeight") )
.list();
List results =
session.createCriteria(Domestic.class, "cat")
.createAlias("kittens", "kit")
.setProjection(
Projections.projectionList()
.add(
Projections.property("cat.name"), "catName" )
.add(
Projections.property("kit.name"), "kitName" )
)
.addOrder(
Order.asc("catName") )
.addOrder( Order.asc("kitName") )
.list();
也可以?
Property.forName()来表C投影:
List results =
session.createCriteria(Cat.class)
.setProjection(
Property.forName("name") )
.add(
Property.forName("color").eq(Color.BLACK) )
.list();
List results =
session.createCriteria(Cat.class)
.setProjection(
Projections.projectionList()
.add(
Projections.rowCount().as("catCountByColor") )
.add(
Property.forName("weight").avg().as("avgWeight") )
.add(
Property.forName("weight").max().as("maxWeight") )
.add(
Property.forName("color").group().as("color" )
)
.addOrder( Order.desc("catCountByColor") )
.addOrder(
Order.desc("avgWeight") )
.list();
8. ȝ(detached)查询和子查询
DetachedCriteria
cM你在一个session范围之外创徏一个查询,q且可以使用L?Session?/font>
执行它?br />
DetachedCriteria query =
DetachedCriteria.forClass(Cat.class)
.add(
Property.forName("sex").eq('F') );
//创徏一个Session
Session session =
.;
Transaction txn = session.beginTransaction();
List results =
query.getExecutableCriteria(session).setMaxResults(100).list();
txn.commit();
session.close();
DetachedCriteria也可以用以表C子查询。条件实例包含子?
询可以通过 Subqueries或?/font>
Property
获得?br />
DetachedCriteria avgWeight =
DetachedCriteria.forClass(Cat.class)
.setProjection(
Property.forName("weight").avg() );
session.createCriteria(Cat.class)
.add( Property.forName("weight).gt(avgWeight) )
.list();
DetachedCriteria weights =
DetachedCriteria.forClass(Cat.class)
.setProjection(
Property.forName("weight") );
session.createCriteria(Cat.class)
.add( Subqueries.geAll("weight", weights) )
.list();
怺兌的子查询也是有可能的Q?br />
DetachedCriteria
avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
.setProjection( Property.forName("weight").avg() )
.add(
Property.forName("cat2.sex").eqProperty("cat.sex") );
session.createCriteria(Cat.class,
"cat")
.add( Property.forName("weight).gt(avgWeightForSex) )
.list();
]]>
我写的hql为:
from Department as d where d.employees.name='Tom';
q行时出现异常:org.hibernate.QueryException: illegal attempt to dereference collection
是因为:在上面的HQL语句 中,Department的关联实体employees是一个集合,而不直接是一个Employee实体?/p>
? Hibernate3.2.2以前的版本,Hibernate会对兌实体自动使用隐式的inner joinQ?/p>
也就是说如下SQL语句 不会有Q何问?nbsp;:from Department as d where d.employees.name='Tom';
? Hibernate3.2.3以后QHibernate改变了这U隐式的inner join的策?
对于如下q条语句Q?/p>
from Department as d where d.employees.name='Tom';
如果employees是普通组件属 性,或单个的兌实体Q则Hibernate会自动生成隐式的inner join
如果myEvents是也一个集合,那么对不Pp?
l将会出?org.hibernate.QueryException: illegal attempt to dereference
collection异常?br />
据Hibernate官方说法:
q样可以让这使得隐含兌更具定性(原文QThis makes
implicit joins more deterministic Q?/p>
推荐q样写:
from Department as d inner join fetch d.employees e where e.name='Tom';在前一日志中自动生成hibernate配置文g的时候,会在dao层用到getSession()Ҏ来操作数据库记录Q但是他q有个方法getHibernateTemplate()Q这两个ҎI竟有什么区别呢Q?/p>
1.使用getSession()Ҏ你只要承sessionFactoryQ而用getHibernateTemplate()Ҏ必须l承 HibernateDaoSupport当然包括sessionFactoryQ这点区别都不是特别重要的,下面q些区别很重要?/p>
2.getSession()Ҏ是没有经qspring包装的,spring会把最原始的sessionl你Q在使用完之后必自p用相应的 closeҎQ而且也不会对声明式事务进行相应的理Q一旦没有及时关闭连接,׃D数据库连接池的连接数? 出,getHibernateTemplate()Ҏ是经qspring装的,例如d相应的声明式事务理Q由spring理相应的连接?/p>
在实际的使用q程中发现的getHibernateTemplate()比getSession()Ҏ要好很多Q但是有些方法在getHibernateTemplate()q没有提供,q时我们用HibernateCallback 回调的方法管理数据库.
例如如下代码Q?/p>
/**
* 使用 hql 语句q行操作
* @param hql HSQL 查询语句Q用回调函数访问外部变量,必须是final的)
* @param offset 开始取数据的下?br />
* @param length d数据记录?br />
* @return List l果?br />
*/
public List getListForPage ( final String hql , final int offset , final int length ) {
List list = getHibernateTemplate().executeFind ( new HibernateCallback ( ) {
public Object doInHibernate ( Session session ) throws HibernateException, SQLException {
Query query = session.createQuery ( hql ) ;
query.setFirstResult ( offset ) ;
query.setMaxResults ( length ) ;
List list = query.list ( ) ;
return list ;
}
}) ;
return list ;
}
遇到q种错误Q一般是因ؓq发q大引v的?/p>
查询解决Ҏ:
查看一下数据库现有的进E数Q是否已l达到参数processes的大?/p>
1.select count(*) from v$process; 取得数据库目前的q程数?br /> 2.select value from v$parameter where name = 'processes'; 取得q程数的上限?br /> 3.如已辑ֈ上限Q修改initSID.ora中的processes的大?br /> 4.重新启动数据库到nomount状态下Q执行create spfile from pfile; qstartup open?/p>
查询数据库自启动以来最大的q发数量
select * from v$license
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
</filter-class>
<init-param>
<param-name>singleSession</param-name>
<param-value>true</param-value>
</init-param><!-- ?spring 中的sesssionfactory ID 一?-->
</filter>
<filter-mapping><filter-name>hibernateFilter</filter-name><url-pattern>*.do</url-pattern><!-- *.jsp, *.do--></filter-mapping>
Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
q时候再ȝ上找解决Ҏ, 会有: 把参?singleSession改ؓfalse, p? 不过, 改完? 估计不久׃遇到另一个郁L异常:
org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions
q下完了, 两个Ҏ都不? 到底怎么? q好, ?a title="http://xuliangyong.javaeye.com/blog/144818" >http://xuliangyong.javaeye.com/blog/144818的主上, l了一个方? 是改写 OpenSessionInViewFilter 的代? 非常感谢, 下面l出的就是最l方?
web.xml
< filter-name >hibernateFilter</filter-name>
< filter-class > org.springframework.orm.hibernate3.support.OurOpenSessionInViewFilter </filter-class>
OurOpenSessionInViewFilter.java 代码:
package org.springframework.orm.hibernate3.support;
import org.hibernate.*;
/** * 单session模式? 默认会发生无法提交的错误: * Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition. * 需要设|FlushModeq刷新session. * 参? http://xuliangyong.javaeye.com/blog/144818 * @author 刘长?/span> */publicclass OurOpenSessionInViewFilter extends OpenSessionInViewFilter {
public OurOpenSessionInViewFilter() {
super.setFlushMode(FlushMode.AUTO);
}
protectedvoid closeSession(Session session, SessionFactory sessionFactory) {
session.flush();
try {
session.getTransaction().commit();
} catch (HibernateException e) {
// TODO Auto-generated catch block//e.printStackTrace();
}
super.closeSession(session, sessionFactory);
}
}
如果各位有更好的解决Ҏ, Ƣ迎讨论?!!
题外?
感觉 Spring + Hibernate 的健壮性还是不够啊! Ҏ抛异? q是事实, 也许q是开源Y件的通病?
About a year and an half ago I wrote an entry about the problem that rises when mapping an entity with multiple bags using eager fetching. At the end of the entry I suggested three different solutions: (a) to use lazy fetching, (b) to use sets instead of bags, and (c) to use the @IndexColumn annotation. Few months later I elaborated on the usage of @IndexColumn, this time another way – using the @CollectionId annotation.
Environment
· Hibernate Entity Manager – 3.3.1.GA
· Hibernate core – 3.2.5.GA
· Hibernate annotations- 3.3.0.GA
· Database – PostgreSQL 8.1
Just before we start a warning – the @CollectionId annotation is a Hibernate specific annotation – not a part of the specification. And it doesn't work on one-to-many associations (but it can be used in conjunction with one-to-many associations). After putting that behind of us lets see the problem.
Assume the following entities relation, a parent entity has two collections of child entities. Both collections should be eagerly loaded.
First try will be to just to map it as is (Child1 has a many-to-many association; Child2 has a one-to-many):
@ManyToMany( fetch = FetchType.EAGER, cascade=CascadeType.ALL)
@JoinTable(name = "PARENT_CHILD1",
joinColumns = @JoinColumn(name = "PARENT_ID", referencedColumnName = "ID"),
inverseJoinColumns = @JoinColumn(name = "CHILD1_ID", referencedColumnName = "ID"))
List<Child1> child1s = new LinkedList<Child1>();
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
List<Child2> child2s = new LinkedList<Child2>();
But when loading a persistence unit with the above configuration the "org.hibernate.HibernateException: cannot simultaneously fetch multiple bags" will be thrown.
The reason is that when we add the @CollectionId to a List or a Collection its semantics changes from "just a bag" to "a bag with primary key" (a.k.a, idbag). It means that a surrogate key is assigned to each row on the collection
When transforming the association to Child1 into an idbag (using the @CollectionId annotation) the problem is solved. The reason is that when we switch the association semantics from "a simple bag" to "a bag with primary key" (a.k.a, idbag) it means that a surrogate key is assigned to each row on the collection.
@Entity
public class Parent {
………
@ManyToMany( fetch = FetchType.EAGER, cascade=CascadeType.ALL)
@JoinTable(name = "PARENT_CHILD1",
joinColumns = @JoinColumn(name = "PARENT_ID", referencedColumnName = "ID"),
inverseJoinColumns = @JoinColumn(name = "CHILD1_ID", referencedColumnName = "ID"))
@GenericGenerator(name="uuid-gen", strategy = "uuid")
@CollectionId(columns = @Column(name = "COL_ID"), type = @Type(type = "string"), generator = "uuid-gen")List<Child1> child1s = new LinkedList<Child1>();
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
List<Child2> child2s = new LinkedList<Child2>();
}
The problem with bags is that when Hibernate eagerly loads multiple collections it issues an outer join select to the RDBMS which can cause multiple entries on some of the collections. But when using an idbag each row in the collections is uniquely identified by the surrogate key, therefore Hibernate can identify it within the collection, even if the SQL statement returns an entry more than once.
Notice the usage of a generator assigned to the collection id, the generator is responsible for creating the surrogate keys of the collection rows. I decided to use the UUID strategy. You can, of course, use JPA standard generators (such as Sequence or Table generators). The @CollectionId references the COL_ID column on PARENT_CHILD1 table (the join table). The value of the collection id is invisible to the application (it is not being mapped to a property).
The Hibernate annotations documentation says that to announce idbag semantics you should assign the @CollectionId to a @ManyToMany, @CollectionOfElements, or @OneToMany (look at the table on this section), but the Hibernate core documentation it says "Hibernate provides a feature that allows you to map many to many associations and collections of values to a table with a surrogate key." (here). I've tried it and indeed when annotating a @OneToMany collection with the @CollectionId an exception with the message "one-to-many collections with identifiers are not supported " is thrown by Hibernate.
Don't forge that you can use idbag for reasons other than solving multiple eager associations. For example it can give a major performance boost over simple bags for mutative operations. If entries in a collection have surrogate keys Hibernate will be able to locate the matching rows in the database using these keys (each row in the association table becomes unique) – there is no need for the fetch -> delete-all -> insert-all cycle when updating the collection.
Posted at 03:49PM Jan 18, 2008 by Eyal Lupu in Persistence | Comments[6]
Posted by Emmanuel Bernard on January 21, 2008 at 09:33 PM GMT+02:00 #
Posted by Eyal Lupu on January 21, 2008 at 11:56 PM GMT+02:00 #
Posted by Geoffrey De Smet on January 23, 2008 at 11:11 AM GMT+02:00 #
Posted by Eyal Lupu on January 23, 2008 at 11:59 AM GMT+02:00 #
Posted by Emmanuel Bernard on January 23, 2008 at 04:48 PM GMT+02:00 #
Posted by Bartosz Jakubowski on October 22, 2008 at 01:26 PM GMT+02:00 #
get和load方式是根据id取得一个记?
下边详细说一下get和load的不同,因ؓ有些时候ؓ了对比也会把find加进来?
1.从返回结果上ҎQ?
load方式索不到的话会抛出org.hibernate.ObjectNotFoundException异常
getҎ索不到的话会q回null
2.从检索执行机制上ҎQ?
getҎ和findҎ都是直接从数据库中检?
而loadҎ的执行则比较复杂
?首先查找session的persistent Context中是否有~存Q如果有则直接返?
?如果没有则判断是否是lazyQ如果不是直接访问数据库索,查到记录q回Q查不到抛出异常
?如果是lazy则需要徏立代理对象,对象的initialized属性ؓfalseQtarget属性ؓnull
?在访问获得的代理对象的属性时,索数据库Q如果找到记录则把该记录的对象复制到代理对象的target上,q将initialized=trueQ如果找不到抛出异??
3.Ҏ区别说明
? 如果你用loadҎQhibernate认ؓ该id对应的对象(数据库记录)在数据库中是一定存在的Q所以它可以攑ֿ的用,它可以放心的使用代理? 延迟加蝲该对象。在用到对象中的其他属性数据时才查询数据库Q但是万一数据库中不存在该记录Q那没办法,只能抛异常。所说的loadҎ抛异常是指在使用 该对象的数据Ӟ数据库中不存在该数据时抛异常Q而不是在创徏q个对象?注意Q这是׃“延迟加蝲”在作??
׃session中的~存对于hibernate来说是个相当廉h的资源,所以在load时会先查一下session~存看看该id对应的对象是否存在,不存在则创徏代理。所以如果你知道该id在数据库中一定有对应记录存在可以用loadҎ来实现gq加载?
?对于getҎQhibernate会确认一下该id对应的数据是否存在,首先在session~存中查找,然后在二U缓存中查找Q还没有查数据库,数据库中没有p回null?
对于load和getҎq回cdQ虽然好多书中都q么_“get()永远只返回实? c?#8221;Q但实际上这是不正确的,getҎ如果? session~存中找C该id对应的对象,如果刚好该对象前面是被代理过的,如被loadҎ使用q,或者被其他兌对象延迟加蝲q,那么q回的还? 原先的代理对象,而不是实体类对象Q如果该代理对象q没有加载实体数据(是id以外的其他属性数据)Q那么它会查询二U缓存或者数据库来加载数据,但是 q回的还是代理对象,只不q已l加载了实体数据?
getҎ首先查询session~存Q没有的话查询二U缓存,最后查询数据库Q反而loadҎ创徏旉先查询session~存Q没有就创徏代理Q实际用数据时才查询二U缓存和数据库?
4.单ȝ
M对于get和load的根本区别,一句话Qhibernate对于loadҎ认ؓ该数据在数据库中一定存在,可以攑ֿ的用代理来延迟加蝲Q如果在使用q程中发C问题Q只能抛异常Q而对于getҎQhibernate一定要获取到真实的数据Q否则返回null?/p>
文章出处Q?a >http://www.diybl.com/course/3_program/java/javajs/2008531/118292.html
hibernate的各U保存方式的?save,persist,update,saveOrUpdte,merge,flush,lock)?对象的三U状?/p>
hibernate的保?/p>
hibernate对于对象的保存提供了太多的方法,他们之间有很多不同,q里l说一下,以便区别?/p>
一、预备知?/p>
对于hibernateQ它的对象有三种状态,transient、persistent、detached
下边是常见的译办法Q?/p>
transientQ瞬态或者自由?/p>
(new DeptPo(1,”行政?#8221;,20,”行政相关”)Q该po的实例和session没有兌Q该po的实例处于transient)
persistentQ持久化状?/p>
(和数据库中记录想影射的Po实例Q它的状态是persistent, 通过get和load{得到的对象都是persistent)
detachedQ脱状态或者游L?/p>
(1)当通过get或loadҎ得到的po对象它们都处于persistent,但如果执 行delete(po)?但不能执行事?,该po状态就处于detached, (表示和sessionq兌),因delete而变成游L可以通过save或saveOrUpdate()变成持久?/p>
(2)当把session关闭Ӟsession~存中的persistent的po对象也变成detached
因关闭session而变成游L的可以通过lock、save、update变成持久?/p>
持久态实例可以通过调用 delete()变成q状态?/p>
通过get()或load()Ҏ得到的实例都是持久化状态的?/p>
q状态的实例可以通过调用lock()或者replicate()q行持久化?/p>
save()和persist()会引发SQL的INSERTQdelete()会引发SQLDELETEQ?/p>
而update()或merge()会引发SQL UPDATE。对持久化(persistentQ实例的修改在刷新提交的时候会被检到Q它也会引vSQL UPDATE?/p>
saveOrUpdate()或者replicate()会引发SQLINSERT或者UPDATE
二、save 和update区别
把这一Ҏ在第一位的原因是因一Ҏ最常用的?/p>
save的作用是把一个新的对象保?/p>
update是把一个脱状态的对象或自由态对象(一定要和一个记录对应)更新到数据库
三、update 和saveOrUpdate区别
q个是比较好理解的,思义QsaveOrUpdate基本上就是合成了save和update,而update只是update;引用hibernate reference中的一D话来解释他们的使用场合和区?/p>
通常下面的场景会使用update()或saveOrUpdate()Q?
E序在第一个session中加载对?接着把session关闭
该对象被传递到表现?
对象发生了一些改?
该对象被q回C务逻辑层最l到持久?
E序创徏W二session调用W二个session的update()Ҏ持久q些改动
saveOrUpdate(po)做下面的?
如果该po对象已经在本session中持久化了,在本session中执行saveOrUpdate不做M?
如果savaOrUpdate(新po)与另一个与本session兌的po对象拥有相同的持久化标识(identifier)Q抛Z个异?
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [org.itfuture.www.po.Xtyhb#5]
saveOrUpdate如果对象没有持久化标?identifier)属性,对其调用save() Q否则update() q个对象
四、persist和save区别
q个是最qL的一对,表面上看h使用哪个都行Q在hibernate reference文档中也没有明确的区分他?
q里l出一个明的区分。(可以跟进src看一下,虽然实现步骤cMQ但是还是有l微的差别)
主要内容区别Q?/p>
1Qpersist把一个瞬态的实例持久化,但是q?不保?标识W?identifier主键对应的属?被立d入到持久化实例中Q标识符的填入可能被推迟到flush的时候?/p>
2Qsave, 把一个瞬态的实例持久化标识符Q及时的产生,它要q回标识W,所以它会立x行Sql insert
五、saveOrUpdate,merge和update区别
比较update和merge
update的作用上边说了,q里说一下merge?/p>
如果session中存在相同持久化标识(identifier)的实例,用用L出的对象覆盖session已有的持久实?
(1)当我们用update的时候,执行完成后,会抛出异?
(2)但当我们使用merge的时候,把处理自由态的po对象A的属性copy到session当中处于持久态的po的属性中Q执行完成后原来是持久状态还是持久态,而我们提供的Aq是自由?/p>
六、flush和update区别
q两个的区别好理?/p>
update操作的是在自由态或q状?因session的关闭而处于脱状?的对?/updateSQL
而flush是操作的在持久状态的对象?/p>
默认情况下,一个持久状态的对象的改动(包含set容器Q是不需要update的,只要你更改了对象的|{待hibernate flushp动更新或保存到数据库了。hibernate flush发生在以下几U情况中Q?/p>
1Q?调用某些查询的和手动flush(),session的关闭、SessionFactory关闭l合
get()一个对象,把对象的属性进行改?把资源关闭?/p>
2Qtransaction commit的时候(包含了flushQ?/p>
七、lock和update区别
update是把一个已l更改过的脱状态的对象变成持久状?/p>
lock是把一个没有更改过的脱状态的对象变成持久状?针对的是因Session的关闭而处于脱状态的po对象(2)Q不能针对因delete而处于脱状态的po对象)
对应更改一个记录的内容Q两个的操作不同Q?/p>
update的操作步骤是Q?/p>
(1)属性改动后的脱的对象的修?>调用update
lock的操作步骤是Q?/p>
(2)调用lock把未修改的对象从q状态变成持久状?->更改持久状态的对象的内?->{待flush或者手动flush
八、clear和evcit的区?/p>
clear完整的清除session~存
evcit(obj)把某个持久化对象从session的缓存中清空?/p>
@Entity
@Table(name = "customer")
public class CustomerEO implements java.io.Serializable {
……
private CustomerType type;
@Enumerated(EnumType.STRING)
public CustomerType getType() {
return type;
}
public void setType(CustomerType type) {
this.type = type;
}
public enum CustomerType {
COMPETITOR, INVESTOR, PARTNER, VENDER
}
}
在实体中虽然标注成枚丄型,但当实体持久化后Q表中所对应的g旧是基本的数据类型,以上代码创徏表的SQL语句是:
CREATE TABLE customer (
id int(20) NOT NULL auto_increment,
name varchar(255),
type varchar(255),
PRIMARY KEY (id)
)
使用枚Dcd后,在创建实体时便可以直接引用枚丄型,例如以下代码所C?/font>
CustomerEO customer = new CustomerEO();
customer.setName("Janet2");
customer.setType(CustomerType.PARTNER);
entityManager.persist(customer);
在?/span>@Enumerated注释Ӟ需要注意以下几个问题:
l 因ؓ枚Dcd的有名称和g个属性,所以在持久化时可以选择持久化名U或是持久化倹{通过EnumType来定义,它有两个值如下所C?/span>
public enum EnumType {
ORDINAL,
STRING
}
ORDINAL表示持久化的为枚丄型的|STRING表示持久化的为枚丄型的名称。默认ؓORDINALQ持久化倹{例如以上示例中标注的ؓSTRINGQ这h久化实体后,数据库中保存的是枚Dcd的名Uͼ如图所C?/span>
若此时改?/span>ORDINALQ代码如下:
@Enumerated(EnumType.ORDINAL)
public CustomerType getType() {
return type;
}
则同h久化的实体后Q数据库保存的结果如?/span>所C?/span>
l 如何选择STRING?/span>ORDINALQ?/span>
如果使用STRING保存Q虽然从数据库中查询数据旉常直观,能够清楚的看cd代表意义Q但q样也会带来其他的问题。若此时枚Dcd的定义改变,例如上例中的枚Dcd名称改ؓQ?/span>
public enum CustomerType {
CUST_COMPETITOR, INVESTOR, PARTNER, VENDER
}
则此时数据库中保存的“COMPETITOR”的值将不能转化为枚丄?/span>CustomerType中的“CUST_COMPETITOR”的倹{但若?/span>ORDINAL则不会带来这U问题。所以徏议?/span>ORDINALcd来持久化枚Dcd?/span>
l 枚Dcd的定义位|,实体外部VS实体内部?/span>
上例?/span>CustomerType枚Dcd定义?/span>CustomerEO实体内部Q这是因为只?/span>CustomerEOq个实体会?/span>CustomerTypecdQ其他的实体不会使用该类型。该cd与这个实体关pȝ密联pR?/span>
但若此时多个实体公用一个枚丄型时Q则可以枚丄型单独定义,定义在实体的外部。有q样一个枚丄?/span>BusinessLineQ它定义在实体外部,代码如下Q?/span>
public enum BusinessLine {
REAL_ESTATE,FINANCE, NON_PROFIT
}
例如CustomerEO实体增加一?/span>BusinessLine的枚丄型,代码如下所C?/span>
@Entity
@Table(name = "customer")
public class CustomerEO implements java.io.Serializable {
……
private BusinessLine businessLine;
@Enumerated(EnumType.STRING)
public BusinessLine getBusinessLine() {
return businessLine;
}
public void setBusinessLine(BusinessLine businessLine) {
this.businessLine = businessLine;
}
}
We want a collection field belonging to an entity object to be sorted.
There are two possible solutions:
OrderBy
annotation where you set the actual ORDER BY
SQL clause. In that case, the collection can be of any type (e.g. Collection
).If you want the collection to be sorted at all times, make it of type SortedSet
or SortedMap
and set the Sort
annotation.
Comparable
set type to SortType.NATURAL
.SortType.COMPARATOR
and specify your own Comparator
class in the comparator
attribute.OrderBy
in both the javax.persistence
package as well as the org.hibernate.annotations
package. The former should be used.