You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by cu...@apache.org on 2012/09/27 21:36:44 UTC

svn commit: r1391185 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/generationtype/

Author: curtisr7
Date: Thu Sep 27 19:36:44 2012
New Revision: 1391185

URL: http://svn.apache.org/viewvc?rev=1391185&view=rev
Log:
OPENJPA-2269: Fix duplicate key exception when inserting into sequence table on multithreaded init.

Added:
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/generationtype/TestTableGeneratorMultithreadedInitialization.java   (with props)
Modified:
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/generationtype/Dog.java

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java?rev=1391185&r1=1391184&r2=1391185&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java Thu Sep 27 19:36:44 2012
@@ -474,6 +474,7 @@ public class TableJDBCSeq extends Abstra
      */
     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 Abstra
                 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

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/generationtype/Dog.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/generationtype/Dog.java?rev=1391185&r1=1391184&r2=1391185&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/generationtype/Dog.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/generationtype/Dog.java Thu Sep 27 19:36:44 2012
@@ -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 + "]";
+    }
+    
+    
 }

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/generationtype/TestTableGeneratorMultithreadedInitialization.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/generationtype/TestTableGeneratorMultithreadedInitialization.java?rev=1391185&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/generationtype/TestTableGeneratorMultithreadedInitialization.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/generationtype/TestTableGeneratorMultithreadedInitialization.java Thu Sep 27 19:36:44 2012
@@ -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
+            }
+        }
+    }
+}

Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/generationtype/TestTableGeneratorMultithreadedInitialization.java
------------------------------------------------------------------------------
    svn:eol-style = native