You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by al...@apache.org on 2009/11/20 00:28:46 UTC
svn commit: r882358 - in /openjpa/trunk:
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/
openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/
Author: allee8285
Date: Thu Nov 19 23:28:45 2009
New Revision: 882358
URL: http://svn.apache.org/viewvc?rev=882358&view=rev
Log:
OPENJPA-1394 - DB2 supports Order By clause with recording locking using "WITH R*" construct. By enabling this feature in the DB2 dictionary, row locking can be perform with the fetch and eliminate the time window other thread snike in to fetch the same row.
Added:
openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/Department.java (with props)
openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/Employee.java (with props)
openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestPessimisticLocks.java (with props)
Modified:
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java?rev=882358&r1=882357&r2=882358&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java Thu Nov 19 23:28:45 2009
@@ -122,6 +122,7 @@
supportsDeferredConstraints = false;
supportsDefaultDeleteAction = false;
supportsAlterTableWithDropColumn = false;
+ supportsLockingWithOrderClause = true;
supportsNullTableForGetColumns = false;
requiresCastForMathFunctions = true;
Added: openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/Department.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/Department.java?rev=882358&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/Department.java (added)
+++ openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/Department.java Thu Nov 19 23:28:45 2009
@@ -0,0 +1,79 @@
+/*
+ * 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.lockmgr;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Collection;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+
+@Entity
+public class Department implements Externalizable {
+
+ private int id;
+
+ private String name;
+
+ private Collection<Employee> employees;
+
+ @OneToMany(cascade=CascadeType.ALL, mappedBy="department")
+ public Collection<Employee> getEmployees() {
+ return employees;
+ }
+
+ @Id
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String toString() {
+ return this.getClass().getName() + '@'
+ + Integer.toHexString(System.identityHashCode(this)) + "[id="
+ + getId() + "] first=" + getName();
+ }
+
+ public void readExternal(ObjectInput in) throws IOException,
+ ClassNotFoundException {
+ id = in.readInt();
+ name = (String) in.readObject();
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeInt(id);
+ out.writeObject(name);
+ }
+}
Propchange: openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/Department.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/Employee.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/Employee.java?rev=882358&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/Employee.java (added)
+++ openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/Employee.java Thu Nov 19 23:28:45 2009
@@ -0,0 +1,94 @@
+/*
+ * 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.lockmgr;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+
+@Entity
+public class Employee implements Externalizable {
+
+ private int id;
+
+ private String firstName;
+ private String lastName;
+ private Department department;
+
+ @Id
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ @ManyToOne
+ @JoinColumn(name="FK_DEPT")
+ public Department getDepartment() {
+ return department;
+ }
+
+ public void setDepartment(Department department) {
+ this.department = department;
+ }
+
+ public String toString() {
+ return this.getClass().getName() + '@'
+ + Integer.toHexString(System.identityHashCode(this)) + "[id="
+ + getId() + "] first=" + getFirstName()
+ + ", last=" + getLastName();
+ }
+
+ public void readExternal(ObjectInput in) throws IOException,
+ ClassNotFoundException {
+ id = in.readInt();
+ firstName = (String) in.readObject();
+ lastName = (String) in.readObject();
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeInt(id);
+ out.writeObject(firstName);
+ out.writeObject(lastName);
+ }
+}
Propchange: openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/Employee.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestPessimisticLocks.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestPessimisticLocks.java?rev=882358&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestPessimisticLocks.java (added)
+++ openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestPessimisticLocks.java Thu Nov 19 23:28:45 2009
@@ -0,0 +1,242 @@
+/*
+ * 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.lockmgr;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+import javax.persistence.LockModeType;
+import javax.persistence.PessimisticLockException;
+import javax.persistence.Query;
+import javax.persistence.QueryTimeoutException;
+
+import org.apache.openjpa.persistence.test.SQLListenerTestCase;
+
+/**
+ * Test Pessimistic Lock and exception behavior against EntityManager and Query interface methods.
+ */
+public class TestPessimisticLocks extends SQLListenerTestCase {
+
+ public void setUp() {
+ setSupportedDatabases(
+// org.apache.openjpa.jdbc.sql.DerbyDictionary.class,
+// org.apache.openjpa.jdbc.sql.OracleDictionary.class,
+ org.apache.openjpa.jdbc.sql.DB2Dictionary.class);
+ if (isTestsDisabled()) {
+ return;
+ }
+
+ setUp(Employee.class, Department.class, "openjpa.LockManager", "mixed");
+ String empTable = getMapping(Employee.class).getTable().getFullName();
+ String deptTable = getMapping(Department.class).getTable().getFullName();
+
+ EntityManager em = null;
+ try {
+ em = emf.createEntityManager();
+ em.getTransaction().begin();
+
+ em.createQuery("delete from " + empTable).executeUpdate();
+ em.createQuery("delete from " + deptTable).executeUpdate();
+
+ em.getTransaction().commit();
+
+ Employee e1, e2;
+ Department d1, d2;
+ d1 = new Department();
+ d1.setId(10);
+ d1.setName("D10");
+
+ e1 = new Employee();
+ e1.setId(1);
+ e1.setDepartment(d1);
+ e1.setFirstName("first.1");
+ e1.setLastName("last.1");
+
+ d2 = new Department();
+ d2.setId(20);
+ d2.setName("D20");
+
+ e2 = new Employee();
+ e2.setId(2);
+ e2.setDepartment(d2);
+ e2.setFirstName("first.2");
+ e2.setLastName("last.2");
+
+ em.getTransaction().begin();
+ em.persist(d1);
+ em.persist(d2);
+ em.persist(e1);
+ em.persist(e2);
+ em.getTransaction().commit();
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (em != null && em.isOpen()) {
+ em.close();
+ }
+ }
+ }
+
+ /*
+ * Test a find with pessimistic lock after a query with pessimistic lock and expect PessimisticLockException.
+ */
+ public void testFindWithLockTimeoutAfterQueryWithPessimisticLocks() {
+ EntityManager em1 = emf.createEntityManager();
+ EntityManager em2 = emf.createEntityManager();
+ try {
+ em1.getTransaction().begin();
+
+ Query query = em1.createQuery(
+ "select e from Employee e where e.id < 10 order by e.id").setFirstResult(1);
+ query.setLockMode(LockModeType.PESSIMISTIC_READ);
+ List<Employee> q = query.getResultList();
+ assertEquals("Expected 1 element with emplyee id=2", q.size(), 1);
+ assertEquals("Test Employee first name = 'first.2'", q.get(0).getFirstName(), "first.2");
+
+ em2.getTransaction().begin();
+
+ Map<String,Object> map = new HashMap<String,Object>();
+ map.put("javax.persistence.lock.timeout", 2000);
+ em2.find(Employee.class, 2, LockModeType.PESSIMISTIC_READ, map);
+ fail("Unexcpected find succeeded. Should throw a PessimisticLockException.");
+ } catch (QueryTimeoutException e) {
+ // TODO: DB2: This is the current unexpected exception due to OPENJPA-991.
+ // Remove this when the problem is fixed
+// System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage());
+ } catch (PessimisticLockException e) {
+ // TODO: This is the expected exception but will be fixed under OPENJPA-991
+// System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage());
+ } catch (Exception ex) {
+ fail("Caught unexpected " + ex.getClass().getName() + ":" + ex.getMessage());
+ } finally {
+ if( em1.getTransaction().isActive())
+ em1.getTransaction().rollback();
+ if( em2.getTransaction().isActive())
+ em2.getTransaction().rollback();
+ }
+
+ try {
+ em1.getTransaction().begin();
+
+ Query query = em1.createQuery(
+ "select e.department from Employee e where e.id < 10 order by e.department.id").setFirstResult(1);
+ query.setLockMode(LockModeType.PESSIMISTIC_READ);
+ List<Department> q = query.getResultList();
+ assertEquals("Expected 1 element with department id=20", q.size(), 1);
+ assertEquals("Test department name = 'D20'", q.get(0).getName(), "D20");
+
+ em2.getTransaction().begin();
+
+ Map<String,Object> map = new HashMap<String,Object>();
+ map.put("javax.persistence.lock.timeout", 2000);
+ Employee emp = em2.find(Employee.class, 1, LockModeType.PESSIMISTIC_READ, map);
+ assertNotNull("Query locks department but find locks Employee.", emp);
+ fail("Unexcpected find succeeded. Should throw a PessimisticLockException.");
+ } catch (QueryTimeoutException e) {
+ // TODO: This is the current unexpected exception due to OPENJPA-991. Remove this when the problem is fixed
+// System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage());
+ } catch (PessimisticLockException e) {
+ // TODO: This is the expected exception but will be fixed under OPENJPA-991
+// System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage());
+ } catch (Exception ex) {
+ fail("Caught unexpected " + ex.getClass().getName() + ":" + ex.getMessage());
+ } finally {
+ if( em1.getTransaction().isActive())
+ em1.getTransaction().rollback();
+ if( em2.getTransaction().isActive())
+ em2.getTransaction().rollback();
+ }
+ em1.close();
+ em2.close();
+ }
+
+ /*
+ * Test a query with pessimistic lock after a find with pessimistic lock and expect PessimisticLockException.
+ */
+ public void testQueryAfterFindWithPessimisticLocks() {
+ EntityManager em1 = emf.createEntityManager();
+ EntityManager em2 = emf.createEntityManager();
+ try {
+ em2.getTransaction().begin();
+
+ Map<String,Object> map = new HashMap<String,Object>();
+ map.put("javax.persistence.lock.timeout", 2000);
+ em2.find(Employee.class, 1, LockModeType.PESSIMISTIC_READ, map);
+
+ em1.getTransaction().begin();
+
+ Query query = em1.createQuery(
+ "select e.department from Employee e where e.id < 10 order by e.department.id").setFirstResult(1);
+ query.setLockMode(LockModeType.PESSIMISTIC_READ);
+ List<Department> q = query.getResultList();
+
+ fail("Unexcpected find succeeded. Should throw a PessimisticLockException.");
+ } catch (PessimisticLockException e) {
+ // This is the expected exception.
+ } catch (Exception ex) {
+ fail("Caught unexpected " + ex.getClass().getName() + ":" + ex.getMessage());
+ } finally {
+ if( em1.getTransaction().isActive())
+ em1.getTransaction().rollback();
+ if (em2.getTransaction().isActive())
+ em2.getTransaction().rollback();
+ }
+ em1.close();
+ em2.close();
+ }
+
+ /*
+ * Test a query with pessimistic lock with query timeout set after a find
+ * with pessimistic lock and expect QueryTimeoutException.
+ */
+ public void testQueryWithQueryTimeoutAfterFindWithPessimisticLocks() {
+ EntityManager em1 = emf.createEntityManager();
+ EntityManager em2 = emf.createEntityManager();
+ try {
+ em2.getTransaction().begin();
+
+ Map<String,Object> map = new HashMap<String,Object>();
+ map.put("javax.persistence.lock.timeout", 2000);
+ em2.find(Employee.class, 1, LockModeType.PESSIMISTIC_READ, map);
+
+ em1.getTransaction().begin();
+
+ Query query = em1.createQuery(
+ "select e.department from Employee e where e.id < 10 order by e.department.id").setFirstResult(1);
+ query.setLockMode(LockModeType.PESSIMISTIC_READ);
+ query.setHint("javax.persistence.query.timeout", 2000);
+ List<Department> q = query.getResultList();
+
+ fail("Unexcpected find succeeded. Should throw a PessimisticLockException.");
+ } catch (QueryTimeoutException e) {
+ // This is the expected exception.
+ } catch (Exception ex) {
+ fail("Caught unexpected " + ex.getClass().getName() + ":" + ex.getMessage());
+ } finally {
+ if( em1.getTransaction().isActive())
+ em1.getTransaction().rollback();
+ if( em2.getTransaction().isActive())
+ em2.getTransaction().rollback();
+ }
+ em1.close();
+ em2.close();
+ }
+}
Propchange: openjpa/trunk/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestPessimisticLocks.java
------------------------------------------------------------------------------
svn:eol-style = native