我想我刚刚发现,两种不同的JPA实现在约束违例和回滚方面的工作方式不同。
@Test(expectedExceptions = @@.class) // CVE or RB?
public void testXXX() {
final EntityManager manager = LocalPU.createEntityManager();
try {
final EntityTransaction transaction = manager.getTransaction();
transaction.begin();
try {
manager.persist(<wrong>); // this is where CVE coming from
transaction.commit(); // this is where RB coming from
} catch (RollbackException re) {
// <---------------------------------------- hibernate here
throw re;
} catch (ConstraintViolationException cve) {
// <---------------------------------------- eclipselink here
transaction.rollback();
throw cve;
} catch (Exception e) {
transaction.rollback();
e.printStackTrace(System.err);
Assert.fail(e.getMessage());
}
} finally {
manager.close();
}
}
哪种实施方式正确?
@Entity
@Table(name = "NAME_MUST_NOT_BE_NULL")
public class NameMustNotBeNull {
protected NameMustNotBeNull() {
this(null);
}
public NameMustNotBeNull(final String name) {
super();
this.name = name;
}
@Id
@GeneratedValue(strategy = GenerationType.TABLE,
generator = "NAME_MUST_NOT_BE_NULL_ID_GENERATOR")
@TableGenerator(name = "NAME_MUST_NOT_BE_NULL_ID_GENERATOR",
table = PrimaryKeyValue.TABLE,
pkColumnName = PrimaryKeyValue.PK_COLUMN_NAME,
valueColumnName = PrimaryKeyValue.VALUE_COLUMN_NAME,
pkColumnValue = "NAME_MUST_NOT_BE_NULL_ID")
@NotNull
@XmlTransient
private Long id;
@Basic(optional = false)
@Column(name = "NAME", nullable = false)
@NotNull
private String name;
}
public class NameMustNotBeNullTest {
@Test(expectedExceptions = RollbackException.class)
public void testNullName() {
final EntityManager manager = LocalPU.createEntityManager();
try {
final EntityTransaction transaction = manager.getTransaction();
transaction.begin();
try {
final NameMustNotBeNull entity = new NameMustNotBeNull(null);
try {
manager.persist(entity);
} catch (ConstraintViolationException cve) {
System.out.println(cve.toString());
}
transaction.commit();
Assert.fail("persisted with null name");
} catch (RollbackException re) {
System.out.println(re.toString());
throw re;
} catch (Exception e) {
transaction.rollback();
e.printStackTrace(System.err);
Assert.fail(e.getMessage());
}
} finally {
manager.close();
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="localPU" transaction-type="RESOURCE_LOCAL">
<!-- I'm testing with one of following providers uncommented -->
<!--<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>-->
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>....persistence.NameMustNotBeNull</class>
<properties>
<property name="javax.persistence.jdbc.driver"
value="org.apache.derby.jdbc.EmbeddedDriver"/>
<property name="javax.persistence.jdbc.url"
value="jdbc:derby:memory:corrsDB;create=true"/>
<!--<property name="javax.persistence.jdbc.user" value=""/>-->
<!--<property name="javax.persistence.jdbc.password" value=""/>-->
<!-- eclipselink -->
<property name="eclipselink.create-ddl-jdbc-file-name" value="target/createDDL.jdbc"/>
<property name="eclipselink.ddl-generation" value="create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="both"/>
<property name="eclipselink.drop-ddl-jdbc-file-name" value="target/dropDDL.jdbc"/>
<property name="eclipselink.logging.level.sql" value="INFO"/>
<property name="eclipselink.logging.parameters" value="false"/>
<property name="eclipselink.target-database" value="Derby"/>
<!-- hibernate -->
<property name="hibernate.archive.autodetection" value="class" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect"/>
</properties>
</persistence-unit>
</persistence>
Running ...NameMustNotBeNullTest
1월 17, 2013 11:45:14 오전 org.hibernate.validator.internal.util.Version <clinit>
INFO: HV000001: Hibernate Validator 4.3.0.Final
javax.validation.ConstraintViolationException: Bean Validation constraint(s) violated while executing Automatic Bean Validation on callback event:'prePersist'. Please refer to embedded ConstraintViolations for details.
javax.persistence.RollbackException: Transaction rolled back because transaction was set to RollbackOnly.
Running ...NameMustNotBeNullTest
1월 17, 2013 11:50:14 오전 org.hibernate.validator.internal.util.Version <clinit>
INFO: HV000001: Hibernate Validator 4.3.0.Final
javax.persistence.RollbackException: Error while committing the transaction
如您所见,似乎两个提供商都启用了Bean验证。
EclipseLink引发CVE,EntityManager#persist()
并标记了回滚。
然后Hibernate抛出RB EntityTransaction#commit()
。
这里是有关您的行为的更多详细信息。
根据JPA 2规范(第102页)
如果validate方法返回的ConstraintViolation对象集不为空,则持久性提供程序必须抛出javax.validation.ConstraintViolationException,其中包含对返回的ConstraintViolation对象集的引用,并且必须将事务标记为回滚。
并从hibernate文档
如果发现一个实体无效,则ConstraintViolationException传播约束违例列表,该约束公开了ConstraintViolations集。
当在提交时发生违规时,此异常包装在RollbackException中。否则,[由Hibernate
Validator]返回ConstraintViolationException(例如,在调用flush()时)。
此外,从jpa 2规格开始(第101页)
默认情况下,默认Bean验证组(默认组)将在持久化和更新前生命周期验证事件时进行验证
将所有这些放在一起,我几乎不会感到困惑,因为在我看来,HibernatePersistenceProvider的行为不遵循JPA 2规范,因为:
显然,在您的情况下,调用(以及使用HibernatePersistenceProvider时)ConstraintViolationException
不会引发persist
。
因此,根据我的理解并回答您的问题:
(注意:我希望其他人可以确认或不同意我的分析)
重要编辑
我对自己的结论感到困惑。因此,我尝试重现OP描述的行为,但无法立即重现此行为。
我所做的与OP描述的内容非常相似:
@NotNull
字段。@NotNull
在一个简单的测试中,尝试对字段为null的实例执行persist()。persist()
操作将javax.validation.ConstraintViolationException
+标记为事务rollback only
我的测试与描述OP的测试之间的主要区别是id生成。在成功的测试中,我使用了一个简单的@GeneratedValue
。
将ID生成策略更改为:
@GeneratedValue(strategy = GenerationType.TABLE,
generator = "NAME_MUST_NOT_BE_NULL_ID_GENERATOR")
@TableGenerator(name = "NAME_MUST_NOT_BE_NULL_ID_GENERATOR",
pkColumnValue = "NAME_MUST_NOT_BE_NULL_ID")
我发现了OP描述的确切行为:
javax.validation.ConstraintViolationException
被抛出persist()
使用的EclipseLink时。persist()
使用hibernate时不会抛出任何异常。因此,当使用Hibernate +时 strategy = GenerationType.TABLE
:行为是不同的。我很确定它没有遵循JPA2规范。
我想我刚刚发现两种不同的JPA实现对约束违规和回滚的工作方式不同。 哪个实现是正确的? 如您所见,Bean验证似乎对两个提供程序都启用了。 EclipseLink将CVE打开,并标记回滚 和Hibernate在上抛出RB。
问题内容: 我有一个如下定义的可连接pthread运行器函数: 该线程应该加入主线程。 每当我通过Valgrind运行程序时,都会出现 以下泄漏 : 我检查了手册页中的pthread,其中说: 奇迹般地,当我用return语句替换pthread_exit()时, 泄漏消失了 。 我的实际问题有三点: 有人可以解释为什么return语句没有泄漏吗? 相对于从线程退出,两个语句之间是否存在一些根本区别
我正在分析android上的改型,并有一个关于回调与不使用它们的问题。我的印象是,回调只用于客户机可能希望的成功和失败响应。否则我会省略它。下面是一个没有回调的改型接口示例: 下面是一个带有回调的示例(我希望我是正确的): 我对两件事感到困惑:
问题内容: 当我想阻止其他事件处理程序在某个事件被触发后执行时,可以使用两种技术之一。我将在示例中使用jQuery,但这也适用于纯JS: 1。 2。 这两种停止事件传播的方法之间是否有显着差异? 对我来说,比执行方法更简单,更短并且更容易出错。使用该方法时,您必须记住正确的大小写,括号等。 另外,我必须在回调中定义第一个参数才能调用该方法。也许,出于某些原因,我应该避免这样做并改为使用它?有什么更
我有本地回购。我创建了整个应用程序,但现在我想把它推到远程回购。我已经有远程回购以及。我怎样才能连接这两个回购而不失去任何工作,我已经做了?
问题内容: 我想知道是否和相同。 例如,如果事件处理程序是使用旧模型添加的 }; 然后,阻止默认操作,例如。 如果事件处理程序使用添加,例如 ); 然后,不要阻止默认操作。 所有浏览器的行为都一样吗? 和之间还有更多区别吗? 在哪里可以找到一些有关行为的文档(我在MDN中找不到)? 问题答案: 的W3C文档对象模型事件规范在 _1.3.1。 事件注册接口_指出,EventListener中没有返回