??xml version="1.0" encoding="utf-8" standalone="yes"?>
我写的hql为:(x)
from Department as d where d.employees.name='Tom';
q行时出现异常:(x)org.hibernate.QueryException: illegal attempt to dereference collection
是因为:(x)在上面的HQL语句 中,Department的关联实体employees是一个集合,而不直接是一个Employee实体?/p>
? Hibernate3.2.2以前的版本,Hibernate?x)对兌实体自动使用隐式的inner joinQ?/p>
也就是说如下SQL语句 不会(x)有Q何问?nbsp;:from Department as d where d.employees.name='Tom';
? Hibernate3.2.3以后QHibernate改变?sh)(jin)这U隐式的inner join的策?
对于如下q条语句Q?/p>
from Department as d where d.employees.name='Tom';
如果employees是普通组件属 性,或单个的兌实体Q则Hibernate?x)自动生成隐式的inner join
如果myEvents是也一个集合,那么对不Pp?
l将?x)出?org.hibernate.QueryException: illegal attempt to dereference
collection异常?br />
据Hibernate官方说法:
q样可以让这使得隐含兌更具定性(原文QThis makes
implicit joins more deterministic Q?/p>
推荐q样写:(x)
from Department as d inner join fetch d.employees e where e.name='Tom';通过使用@TransactionAttribute 注释或部|描q符Q开发者能够指定事务属性。EJB 容器通过分析事务属性便能够知道如何处理EJB lg的事务需求。EJB 事务属性的取值有Q?
Q? QRequired Q如果EJB lg必须Lq行在事务中Q则应该使用Required 模式。如果已l有事务在运行,则EJB lg参与其中Q如果没有事务运行,则EJB 容器?x)?f)EJB lg启动新的事务?
Required 是默认和最怋用的事务属性倹{这个值指定必d事务之内调用EJB Ҏ(gu)。如果从非事务性客L(fng)调用Ҏ(gu)Q那么容器会(x)在调用方法之前开始事务,q且在方法返回时l束事务。另一斚wQ如果调用者从事务性上下文调用Ҏ(gu)Q那? Ҏ(gu)?x)联l已有事务。在从客h传播事务的情况下Q如果我们的Ҏ(gu)表示应该回滚事务Q那么容器不仅回回滚整个事务Q而且?x)向客户端抛出异常,从而让客户? 知道它开始的事务已经被另一个方法回滚了(jin)?
Q? QRequires_New Q当客户调用EJB Ӟ如果L希望启动新的事务Q则应该使用RequiresNew 事务属性,如果客户在调用EJB lg时已l存在事务,则当前事务会(x)被挂Pq而容器启动新的事务,q将调用h委派lEJB lg。也是_(d)如果客户端已l有?jin)事务,那么它暂停该事务Q知道方法返回位|,C务是成功q是p|都不?x)?jing)响客L(fng)已有的事务。EJB lg执行相应的业务操作,容器?x)提交或回滚事务Q最l容器将恢复原有的事务,当然Q如果客户在调用EJB lg时不存在事务Q则不需要执行事务的挂v或恢复操作?
RequiresNew 事务属性非常有用。如果EJB lg需要事务的ACID 属性,q且EJB lgq行在单个独立的工作单元中,从而不?x)将其他外部逻辑也包括在当前的事务中Q则必须使用RequiredNew? 务属性。如果需要事务,但是不希望事务的回滚影响客户端,应该用它。另外,当不希望客户端的回滚影响你的时候,也应该用这个倹{日志记录是个很好的 例子Q即使父事务回滚Q你也希望把错误情况记录到日志中Q另一斚wQ日志记录细调试信息的p|不应该导致回滚整个事务,q且问题应该仅限于日志记录组? 内?
Q? QSupports Q如果某个EJB lg使用?jin)Supports 事务属性,则只有调用它的客户已l启用了(jin)事务Ӟq一EJB lg才会(x)q行在事务中。如果客户ƈ没有q行在事务中Q则EJB l徏也不?x)运行在事务中。Supports 同Required 事务属性很怼Q但是,Required 要求EJB lg必须q行在事务中。如果用Support 事务属性,EJB l徏很可嫩没有运行在事务中?
Q? QMandatory QMandatory 事务属性要求调用EJB lg的客户必dl运行在事务中。如果从非事务性客L(fng)调用使用Mandatory 属性的EJB Ҏ(gu)Q那么客户将接受到系l抛出的javax.ejb.EJBTransactionRequiredException 异常。EJB lg使用Mandatory 事务属性是非常安全的,它能够保证EJB l徏q行在事务中。如果客h有运行在事务中,则不能够调用到应用了(jin)Mandatory 事务属性的EJB lg。但是,Mandatory 事务属性要求第3 方(?qing)客P(j)在调用EJB lg前必d动了(jin)事务。EJB 容器q不?x)?f)Mandatory 事务属性自动启动新事务Q这是同Support 事务属性的最主要区别?
Q? QNotSupported Q如果EJB lg使用?jin)NotSupport 事务属性,它根本不?x)参与到事务中。如果调用者用相兌的事务调用方法,容器׃(x)暂停事务Q调用方法,然后再方法返回时恢复事务。通常Q此属性只用于非实物性的自动认模式中,支持JMS 提供者的MDB ?
Q? QNever Q如果EJB lg使用Never 事务属性,它就不能够参与到事务中,而且Q如果调用它的客户已l处于事务中Q则容器?x)将javax.ejb.EJBException 异常抛给客户?
事务效果图,其中QT1 和T2 ? 个不同的事务QT1 是客戯求传递的事务QT2 是容器启动的事务Q通过下表Q能够理解各U事务属性在影响事务长度和范围方面所L(fng)重要作用?
事务属? |
客户事务 |
EJB lg事务 |
Required |
? T1 |
T2 T1 |
RequiresNew |
? T1 |
T2 T2 |
Supports |
? T1 |
? T1 |
Mandatory |
? T1 |
错误 T1 |
NotSupported |
? T1 |
? ? |
Never |
? T1 |
? 错误 |
@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语句是:(x)
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注释Ӟ需要注意以下几个问题:(x)
l 因ؓ(f)枚Dcd的有名称和g个属性,所以在持久化时可以选择持久化名U或是持久化倹{通过EnumType来定义,它有两个值如下所C?/span>
public enum EnumType {
ORDINAL,
STRING
}
ORDINAL表示持久化的为枚丄型的|STRING表示持久化的为枚丄型的名称。默认ؓ(f)ORDINALQ持久化倹{例如以上示例中标注的ؓ(f)STRINGQ这h久化实体后,数据库中保存的是枚Dcd的名Uͼ如图所C?/span>
若此时改?/span>ORDINALQ代码如下:(x)
@Enumerated(EnumType.ORDINAL)
public CustomerType getType() {
return type;
}
则同h久化的实体后Q数据库保存的结果如?/span>所C?/span>
l 如何选择STRING?/span>ORDINALQ?/span>
如果使用STRING保存Q虽然从数据库中查询数据旉常直观,能够清楚的看?gu)cd代表意义Q但q样也会(x)带来其他的问题。若此时枚Dcd的定义改变,例如上例中的枚Dcd名称改ؓ(f)Q?/span>
public enum CustomerType {
CUST_COMPETITOR, INVESTOR, PARTNER, VENDER
}
则此时数据库中保存的“COMPETITOR”的值将不能转化为枚丄?/span>CustomerType中的“CUST_COMPETITOR”的倹{但若?/span>ORDINAL则不?x)带来这U问题。所以徏议?/span>ORDINALcd来持久化枚Dcd?/span>
l 枚Dcd的定义位|,实体外部VS实体内部?/span>
上例?/span>CustomerType枚Dcd定义?/span>CustomerEO实体内部Q这是因为只?/span>CustomerEOq个实体?x)?/span>CustomerTypecdQ其他的实体不会(x)使用该类型。该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;
}
}
EJB3.1专家l通过JCP发布?u>?/font>博文以提供更多的关于专家l工作情늚信息Q包括对通用EJBlg映射的支持:(x)
“对开发者来说造成挫|的一个共同的源泉是用来解析和查找EJB引用的映信息(如全局JNDI名)(j)的不可移植性。我们不断探索以该信息标准化得应用无需特定于厂商的EJBlg映射可以部|?#8221;
专家l仍处在定义EJB3.1q程的早期阶D,所以上面列出来的特性有可能发生变化。这也是我们通过邮g向专家组提供反馈信息来参与到下一版规范的制定工作中去的绝x?x)?/p>