mirror of https://github.com/apache/openjpa.git
OPENJPA-2269: Fix duplicate key exception when inserting into sequence table on multithreaded init.
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@1391185 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
837638b91b
commit
e424097b56
|
@ -474,6 +474,7 @@ public class TableJDBCSeq extends AbstractJDBCSeq implements Configurable {
|
|||
*/
|
||||
private void insertSequence(ClassMapping mapping, Connection conn)
|
||||
throws SQLException {
|
||||
|
||||
if (_log.isTraceEnabled())
|
||||
_log.trace(_loc.get("insert-seq"));
|
||||
|
||||
|
@ -895,12 +896,20 @@ public class TableJDBCSeq extends AbstractJDBCSeq implements Configurable {
|
|||
closeConnection(conn);
|
||||
|
||||
if (!sequenceSet) {
|
||||
// insert a new sequence column.
|
||||
// Prefer connection2 / non-jta-data-source when inserting
|
||||
// a sequence column regardless of Seq.type.
|
||||
conn = _conf.getDataSource2(store.getContext())
|
||||
.getConnection();
|
||||
insertSequence(mapping, conn);
|
||||
// insert a new sequence column. Prefer connection2 / non-jta-data-source when inserting a
|
||||
// sequence column regardless of Seq.type.
|
||||
conn = _conf.getDataSource2(store.getContext()).getConnection();
|
||||
try {
|
||||
insertSequence(mapping, conn);
|
||||
} catch (SQLException e) {
|
||||
// it is possible another thread already got in and inserted this sequence. Try to keep going
|
||||
if (_log.isTraceEnabled()) {
|
||||
_log.trace(
|
||||
"Caught an exception while trying to insert sequence. Will try to reselect the " +
|
||||
"seqence. ", e);
|
||||
}
|
||||
}
|
||||
|
||||
conn.close();
|
||||
|
||||
// now we should be able to update using the connection per
|
||||
|
|
|
@ -50,4 +50,45 @@ public class Dog {
|
|||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + id;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Dog other = (Dog) obj;
|
||||
if (id != other.id) {
|
||||
return false;
|
||||
}
|
||||
if (name == null) {
|
||||
if (other.name != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!name.equals(other.name)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Dog [id=" + id + ", name=" + name + "]";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.persistence.generationtype;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
|
||||
import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
|
||||
|
||||
public class TestTableGeneratorMultithreadedInitialization extends AbstractPersistenceTestCase {
|
||||
Object[] props = new Object[] { Dog.class
|
||||
// , "openjpa.Log", "SQL=trace"
|
||||
};
|
||||
|
||||
public void setUp() throws Exception {
|
||||
EntityManagerFactory emf = createNamedEMF(getPersistenceUnitName(), props);
|
||||
EntityManager em = emf.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
em.createNativeQuery("DROP TABLE ID_Gen").executeUpdate();
|
||||
em.createNativeQuery("DROP TABLE dog").executeUpdate();
|
||||
em.getTransaction().commit();
|
||||
emf.close();
|
||||
}
|
||||
|
||||
public void test() throws Exception {
|
||||
|
||||
EntityManagerFactory emf1 = createNamedEMF(getPersistenceUnitName(), props);
|
||||
EntityManagerFactory emf2 = createNamedEMF(getPersistenceUnitName(), props);
|
||||
EntityManagerFactory emf3 = createNamedEMF(getPersistenceUnitName(), props);
|
||||
|
||||
assertNotEquals(emf1, emf2);
|
||||
|
||||
emf1.createEntityManager().close();
|
||||
emf2.createEntityManager().close();
|
||||
|
||||
final EntityManager em1 = emf1.createEntityManager();
|
||||
final EntityManager em2 = emf2.createEntityManager();
|
||||
final EntityManager em3 = emf3.createEntityManager();
|
||||
|
||||
Worker w1 = new Worker(em1);
|
||||
Worker w2 = new Worker(em2);
|
||||
|
||||
w1.start();
|
||||
w2.start();
|
||||
|
||||
w1.join();
|
||||
w2.join();
|
||||
|
||||
assertNull("Caught an exception in worker 1" + w1.getException(), w1.getException());
|
||||
assertNull("Caught an exception in worker 2" + w2.getException(), w2.getException());
|
||||
|
||||
Dog d1 = w1.getDog();
|
||||
Dog d2 = w2.getDog();
|
||||
assertNotNull(d1);
|
||||
assertNotNull(d2);
|
||||
assertNotEquals(d1, d2);
|
||||
|
||||
Dog d1_found = em3.find(Dog.class, d1.getId());
|
||||
Dog d2_found = em3.find(Dog.class, d2.getId());
|
||||
|
||||
assertEquals(d1_found, d1);
|
||||
assertEquals(d2_found, d2);
|
||||
|
||||
emf1.close();
|
||||
emf2.close();
|
||||
emf3.close();
|
||||
}
|
||||
|
||||
class Worker extends Thread {
|
||||
final EntityManager em;
|
||||
Dog dog = new Dog();
|
||||
Exception exception;
|
||||
|
||||
Worker(EntityManager e) {
|
||||
em = e;
|
||||
}
|
||||
|
||||
public Dog getDog() {
|
||||
return dog;
|
||||
}
|
||||
|
||||
public Exception getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
em.getTransaction().begin();
|
||||
em.persist(dog);
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
} catch (Exception e) {
|
||||
exception = e;
|
||||
e.printStackTrace();
|
||||
// TODO: handle exception
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue