From 90355300bbec7ad38404dee8b25e3a4eb017e5aa Mon Sep 17 00:00:00 2001 From: Jeremy Bauer Date: Mon, 26 Apr 2010 19:34:34 +0000 Subject: [PATCH] OPENJPA-1604 Added Optimistic check as part the logic for setting the default lock mode for named queries in order to retain 1.x behavior. git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@938203 13f79535-47bb-0310-9956-ffa450edef68 --- .../TestOptimisticNamedQueryLockMode.java | 129 ++++++++++++++++++ .../AnnotationPersistenceMetaDataParser.java | 3 +- .../XMLPersistenceMetaDataParser.java | 3 +- 3 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestOptimisticNamedQueryLockMode.java diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestOptimisticNamedQueryLockMode.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestOptimisticNamedQueryLockMode.java new file mode 100644 index 000000000..7710fd51e --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestOptimisticNamedQueryLockMode.java @@ -0,0 +1,129 @@ +/* + * 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 javax.persistence.EntityManager; +import javax.persistence.LockModeType; +import javax.persistence.Query; + +import org.apache.openjpa.persistence.FetchPlan; +import org.apache.openjpa.persistence.OpenJPAEntityManager; +import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI; +import org.apache.openjpa.persistence.OpenJPAQuery; +import org.apache.openjpa.persistence.TransactionRequiredException; +import org.apache.openjpa.persistence.test.AllowFailure; +import org.apache.openjpa.persistence.test.SQLListenerTestCase; + +/** + * Tests whether the lock mode on named query emits a FOR UPDATE clause in target SQL + * query when Optimistic=true (default), with pessimistic lock manager. + */ +public class TestOptimisticNamedQueryLockMode extends SQLListenerTestCase { + public void setUp() { + super.setUp(CLEAR_TABLES, LockEmployee.class, + "openjpa.LockManager", "pessimistic" + ); + } + + /* + * Optimistic=true, but a lock mode specified - assert statement will lock. + */ + public void testForUpdateClausePresentInNamedQueryWithLockMode() { + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + assertClausePresentInSQL("FOR UPDATE", em.createNamedQuery("findEmployeeByIdWithLock").setParameter("id", 0)); + em.getTransaction().rollback(); + em.getTransaction().begin(); + assertClausePresentInSQL("FOR UPDATE", em.createNamedQuery("findEmployeeByIdWithLock").setParameter("id", 0)); + em.getTransaction().rollback(); + em.getTransaction().begin(); + assertClausePresentInSQL("FOR UPDATE", em.createNamedQuery("findEmployeeByIdWithLock").setParameter("id", 0)); + em.getTransaction().rollback(); + em.close(); + } + + /* + * Optimistic=true, but a no lock mode specified - assert statement does not lock. + */ + public void testForUpdateClausePresentInQueryWithDefault() { + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + assertClauseAbsentInSQL("FOR UPDATE", em.createNamedQuery("findEmployeeById").setParameter("id", 0)); + assertClauseAbsentInSQL("FOR UPDATE", em.createNamedQuery("findEmployeeById").setParameter("id", 0)); + + OpenJPAEntityManager oem = (OpenJPAEntityManager)em; + OpenJPAQuery q = oem.createNamedQuery("findEmployeeById").setParameter("id", 0); + FetchPlan fp = q.getFetchPlan(); + fp.setReadLockMode(LockModeType.NONE); + + em.getTransaction().commit(); + em.close(); + } + + /* + * Optimistic=true, lock mode = none set explicitly on the fetch plan. + */ + public void testForUpdateClauseAbsentInQueryWithFetchPlanNoneLockMode() { + OpenJPAEntityManagerSPI em = emf.createEntityManager(); + em.getTransaction().begin(); + + OpenJPAQuery q = em.createNamedQuery("findEmployeeById").setParameter("id", 0); + FetchPlan fp = q.getFetchPlan(); + fp.setReadLockMode(LockModeType.NONE); + assertClauseAbsentInSQL("FOR UPDATE", q); + + q = em.createNamedQuery("findEmployeeByIdWithNoLock").setParameter("id", 0); + fp = q.getFetchPlan(); + fp.setReadLockMode(LockModeType.NONE); + assertClauseAbsentInSQL("FOR UPDATE", q); + + em.getTransaction().commit(); + em.close(); + } + + /* + * Optimistic = false, explicit no locking on the named query + */ + public void testForUpdateClauseAbsentInQueryWithExplictNoLock() { + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + assertClauseAbsentInSQL("FOR UPDATE", em.createNamedQuery("findEmployeeByIdWithNoLock").setParameter("id", 0)); + assertClauseAbsentInSQL("FOR UPDATE", em.createNamedQuery("findEmployeeByIdWithNoLock").setParameter("id", 0)); + em.getTransaction().commit(); + em.close(); + } + + String getLastSQL() { + String last = sql.get(getSQLCount() - 1); + assertNotNull("No last sql found", last); + return last; + } + + void assertClausePresentInSQL(String clause, Query q) { + q.getResultList(); + String last = getLastSQL(); + assertTrue(clause + " is not present in " + last, last.toUpperCase().indexOf(clause) != -1); + } + + void assertClauseAbsentInSQL(String clause, Query q) { + q.getResultList(); + String last = getLastSQL(); + assertTrue(clause + " is not absent in " + last, last.toUpperCase().indexOf(clause) == -1); + } +} diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java index 8ffc4024c..862625c39 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java @@ -1848,10 +1848,11 @@ public class AnnotationPersistenceMetaDataParser LockModeType lmt = query.lockMode(); if (query.lockMode() != null) { String lm = _conf.getLockManager(); + boolean optimistic = _conf.getOptimistic(); if (lm != null) { lm = lm.toLowerCase(); if (lm.contains("pessimistic")) { - if (lmt == LockModeType.NONE) { + if (lmt == LockModeType.NONE && !optimistic) { if (_log.isWarnEnabled() == true) { _log.warn(_loc.get("override-named-query-lock-mode", new String[] { "annotation", query.name(), _cls.getName() })); diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java index b1cecccfc..fa90b805c 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java @@ -1708,10 +1708,11 @@ public class XMLPersistenceMetaDataParser } LockModeType lmt = LockModeType.valueOf(lockModeString); String lm = _conf.getLockManager(); + boolean optimistic = _conf.getOptimistic(); if (lm != null) { lm = lm.toLowerCase(); if (lm.contains("pessimistic")) { - if (lmt == LockModeType.NONE) { + if (lmt == LockModeType.NONE && !optimistic) { if (log != null && log.isWarnEnabled() == true) { log.warn(_loc.get("override-named-query-lock-mode", new String[] { "xml", queryName, _cls.getName() }));