Skip to content

Commit d12ce67

Browse files
committed
HHH-9888 - Oracle database constraint violation reported as RollbackException with JTA transaction manager
(cherry picked from commit 918c9d4)
1 parent 9050b78 commit d12ce67

File tree

1 file changed

+143
-0
lines changed

1 file changed

+143
-0
lines changed
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.test.tm;
8+
9+
import java.util.Map;
10+
import javax.persistence.Column;
11+
import javax.persistence.Entity;
12+
import javax.persistence.Id;
13+
import javax.transaction.RollbackException;
14+
import javax.transaction.Status;
15+
import javax.transaction.SystemException;
16+
import javax.transaction.TransactionManager;
17+
18+
import org.hibernate.JDBCException;
19+
import org.hibernate.Session;
20+
import org.hibernate.cfg.AvailableSettings;
21+
import org.hibernate.engine.spi.SessionImplementor;
22+
23+
import org.hibernate.testing.TestForIssue;
24+
import org.hibernate.testing.jta.TestingJtaBootstrap;
25+
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
26+
import org.hibernate.test.resource.transaction.jta.JtaPlatformStandardTestingImpl;
27+
import org.junit.Test;
28+
29+
import org.jboss.logging.Logger;
30+
31+
import static org.junit.Assert.assertEquals;
32+
import static org.junit.Assert.fail;
33+
34+
/**
35+
* @author Steve Ebersole
36+
*/
37+
public class BeforeCompletionFailureTest extends BaseNonConfigCoreFunctionalTestCase {
38+
private static final Logger log = Logger.getLogger( BeforeCompletionFailureTest.class );
39+
40+
@Override
41+
protected Class[] getAnnotatedClasses() {
42+
return new Class[] { SimpleEntity.class };
43+
}
44+
45+
@Override
46+
protected void addSettings(Map settings) {
47+
super.addSettings( settings );
48+
TestingJtaBootstrap.prepare( settings );
49+
settings.put( AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, "jta" );
50+
}
51+
52+
@Test
53+
@TestForIssue( jiraKey = "HHH-9888" )
54+
public void testUniqueConstraintViolationDuringManagedFlush() throws Exception {
55+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
56+
// set up test data
57+
58+
Session session = openSession();
59+
session.getTransaction().begin();
60+
session.save( newEntity( 1 ) );
61+
session.getTransaction().commit();
62+
session.close();
63+
64+
65+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
66+
// do the test
67+
68+
final TransactionManager tm = JtaPlatformStandardTestingImpl.INSTANCE.transactionManager();
69+
assertEquals( Status.STATUS_NO_TRANSACTION, tm.getStatus() );
70+
71+
// begin the transaction ("CMT" style)
72+
tm.begin();
73+
74+
session = openSession();
75+
76+
session.save( newEntity( 2 ) );
77+
78+
// complete the transaction ("CMT" style) - this leads to the managed flush
79+
// which should lead to the UK violation
80+
try {
81+
tm.commit();
82+
fail( "Expecting a failure from JTA commit" );
83+
}
84+
catch (RollbackException expected) {
85+
log.info( "Test encountered expected JTA RollbackException; looking for nested JDBCException", expected );
86+
boolean violationExceptionFound = false;
87+
Throwable cause = expected;
88+
while ( cause != null ) {
89+
if ( cause instanceof JDBCException ) {
90+
log.info( "Found JDBCException, assuming related to UK violation", cause );
91+
violationExceptionFound = true;
92+
break;
93+
}
94+
cause = cause.getCause();
95+
}
96+
97+
if ( !violationExceptionFound ) {
98+
fail( "Did not find JDBCException in JTA RollbackException chain" );
99+
}
100+
}
101+
finally {
102+
if ( !( (SessionImplementor) session ).isClosed() ) {
103+
session.close();
104+
}
105+
}
106+
107+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
108+
// clean up test data
109+
110+
session = openSession();
111+
session.getTransaction().begin();
112+
session.createQuery( "delete SimpleEntity" ).executeUpdate();
113+
session.getTransaction().commit();
114+
session.close();
115+
}
116+
117+
private SimpleEntity newEntity(int id) {
118+
// since "key" is reused, should violate the UK
119+
return new SimpleEntity( id, "key", "name" );
120+
}
121+
122+
private void runTest() {
123+
124+
}
125+
126+
@Entity(name = "SimpleEntity")
127+
public static class SimpleEntity {
128+
@Id
129+
public Integer id;
130+
@Column(unique = true)
131+
public String key;
132+
public String name;
133+
134+
public SimpleEntity() {
135+
}
136+
137+
public SimpleEntity(Integer id, String key, String name) {
138+
this.id = id;
139+
this.key = key;
140+
this.name = name;
141+
}
142+
}
143+
}

0 commit comments

Comments
 (0)