From 8c8636fce98d7907c444bc9f7dc2c94321163d68 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Fri, 30 Oct 2009 04:09:05 +0000 Subject: [PATCH] OPENJPA-1306 - Add basic extended lock scope support, 3 junit testing basic, secondary table, join table, inheritance entity, element collections (lazy/eager), 1x1 (lazy/eager) and 1xm (lazy/eager). git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@831194 13f79535-47bb-0310-9956-ffa450edef68 --- .../kernel/DelegatingFetchConfiguration.java | 17 + .../openjpa/kernel/FetchConfiguration.java | 18 +- .../kernel/FetchConfigurationImpl.java | 19 +- .../org/apache/openjpa/kernel/LockScopes.java | 39 + .../openjpa/kernel/localizer.properties | 1 + .../persistence/lock/extended/LSE1x1Lf.java | 113 ++ .../persistence/lock/extended/LSE1x1LfJT.java | 115 ++ .../lock/extended/LSE1x1LfJTLzy.java | 116 ++ .../lock/extended/LSE1x1LfLzy.java | 114 ++ .../persistence/lock/extended/LSE1x1Rt.java | 79 ++ .../persistence/lock/extended/LSE1xmLf.java | 118 ++ .../lock/extended/LSE1xmLfEgr.java | 119 ++ .../persistence/lock/extended/LSE1xmLfJT.java | 120 ++ .../lock/extended/LSE1xmLfJTEgr.java | 119 ++ .../persistence/lock/extended/LSE1xmRt.java | 79 ++ .../persistence/lock/extended/LSEBase.java | 110 ++ .../persistence/lock/extended/LSEEleCol.java | 118 ++ .../lock/extended/LSEEleColEgr.java | 119 ++ .../persistence/lock/extended/LSEJoinAbs.java | 81 ++ .../persistence/lock/extended/LSEJoinCon.java | 76 + .../persistence/lock/extended/LSESecTbl.java | 112 ++ .../lock/extended/LSESngTblAbs.java | 100 ++ .../lock/extended/LSESngTblCon.java | 76 + .../lock/extended/LockScopeTestCase.java | 324 +++++ .../lock/extended/Test1x1LockScope.java | 937 +++++++++++++ .../lock/extended/Test1xmLockScope.java | 1126 +++++++++++++++ .../lock/extended/TestBasicLockScope.java | 1225 +++++++++++++++++ .../AnnotationPersistenceMetaDataParser.java | 6 +- .../apache/openjpa/persistence/FetchPlan.java | 12 +- .../persistence/FetchPlanHintHandler.java | 5 + .../openjpa/persistence/FetchPlanImpl.java | 10 + .../openjpa/persistence/LockScopesHelper.java | 49 + .../XMLPersistenceMetaDataParser.java | 21 +- 33 files changed, 5675 insertions(+), 18 deletions(-) create mode 100644 openjpa-kernel/src/main/java/org/apache/openjpa/kernel/LockScopes.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1Lf.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1LfJT.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1LfJTLzy.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1LfLzy.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1Rt.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmLf.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmLfEgr.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmLfJT.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmLfJTEgr.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmRt.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEBase.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEEleCol.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEEleColEgr.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEJoinAbs.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEJoinCon.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSESecTbl.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSESngTblAbs.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSESngTblCon.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LockScopeTestCase.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/Test1x1LockScope.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/Test1xmLockScope.java create mode 100644 openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/TestBasicLockScope.java create mode 100644 openjpa-persistence/src/main/java/org/apache/openjpa/persistence/LockScopesHelper.java diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingFetchConfiguration.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingFetchConfiguration.java index 5ffc8a3c9..f14de8f9c 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingFetchConfiguration.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingFetchConfiguration.java @@ -401,6 +401,23 @@ public class DelegatingFetchConfiguration } } + public int getLockScope() { + try { + return _fetch.getLockScope(); + } catch (RuntimeException re) { + throw translate(re); + } + } + + public FetchConfiguration setLockScope(int scope) { + try { + _fetch.setLockScope(scope); + return this; + } catch (RuntimeException re) { + throw translate(re); + } + } + public int getReadLockLevel() { try { return _fetch.getReadLockLevel(); diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfiguration.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfiguration.java index 2dacc0185..0d732207d 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfiguration.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfiguration.java @@ -36,7 +36,7 @@ import org.apache.openjpa.meta.FieldMetaData; * @author Pinaki Poddar */ public interface FetchConfiguration - extends Serializable, Cloneable, LockLevels, QueryFlushModes { + extends Serializable, Cloneable, LockLevels, LockScopes, QueryFlushModes { /** * Constant to revert any setting back to its default value. @@ -268,7 +268,21 @@ public interface FetchConfiguration * @since 0.3.1 */ public FetchConfiguration setLockTimeout(int timeout); - + + /** + * The lock scope for next fetch. + * + * @since 2.0.0 + */ + public int getLockScope(); + + /** + * The lock scope for next fetch. + * + * @since 2.0.0 + */ + public FetchConfiguration setLockScope(int scope); + /** * The number of milliseconds to wait for a query, or -1 for no * limit. diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java index cf4639522..c785e5f8b 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java @@ -78,7 +78,7 @@ public class FetchConfigurationImpl public int flushQuery = 0; public int lockTimeout = -1; public int queryTimeout = -1; - public int lockMode = 0; + public int lockScope = LOCKSCOPE_NORMAL; public int readLockLevel = LOCK_NONE; public int writeLockLevel = LOCK_NONE; public Set fetchGroups = null; @@ -168,6 +168,7 @@ public class FetchConfigurationImpl setExtendedPathLookup(fetch.getExtendedPathLookup()); setLockTimeout(fetch.getLockTimeout()); setQueryTimeout(fetch.getQueryTimeout()); + setLockScope(fetch.getLockScope()); clearFetchGroups(); addFetchGroups(fetch.getFetchGroups()); clearFields(); @@ -482,6 +483,22 @@ public class FetchConfigurationImpl return this; } + public int getLockScope() { + return _state.lockScope; + } + + public FetchConfiguration setLockScope(int scope) { + if (scope != DEFAULT + && scope != LockScopes.LOCKSCOPE_NORMAL + && scope != LockScopes.LOCKSCOPE_EXTENDED) + throw new IllegalArgumentException(_loc.get( + "bad-lock-scope", new Integer(scope)).getMessage()); + if (scope == DEFAULT ) + _state.lockScope = LOCKSCOPE_NORMAL; + else + _state.lockScope = scope; + return this; + } public int getReadLockLevel() { String lockModeKey = "openjpa.FetchPlan.ReadLockMode"; diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/LockScopes.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/LockScopes.java new file mode 100644 index 000000000..7f1ae2c52 --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/LockScopes.java @@ -0,0 +1,39 @@ +/* + * 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.kernel; + +/** + * Defines lock scope levels used for MixedLockManager. + * + * @since 2.0.0 + */ +public interface LockScopes { + + /** + * Generic Normal lock scope level. Value of 0. + * + */ + public static final int LOCKSCOPE_NORMAL = 0; + + /** + * Generic extended lock scope level. Value of 10. + */ + public static final int LOCKSCOPE_EXTENDED = 10; + +} diff --git a/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties b/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties index af50e5288..cabe787a4 100644 --- a/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties +++ b/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties @@ -448,4 +448,5 @@ fill-factory-error: Error while fill data with factory strategy. The error \ occurred while invoking "{0}" with key "{1}" and value "{2}" of type "{3}". \ See nested exception for details. writebehind-cfg-err: Missing required WriteBehind configuration parameter "{0}" +bad-lock-scope: This lock manager does not recognize lock scope "{0}". diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1Lf.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1Lf.java new file mode 100644 index 000000000..fd63ee437 --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1Lf.java @@ -0,0 +1,113 @@ +/* + * 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.lock.extended; + +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.LockModeType; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToOne; +import javax.persistence.QueryHint; +import javax.persistence.Version; + +@NamedQueries ( value={ + @NamedQuery( + name="findLSE1x1LfNormal" + , query="SELECT c FROM LSE1x1Lf c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + ), + @NamedQuery( + name="findLSE1x1LfExtended" + , query="SELECT c FROM LSE1x1Lf c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + , hints={@QueryHint(name="javax.persistence.lock.scope",value="EXTENDED")} + ) + } + ) + +@Entity +public class LSE1x1Lf implements Externalizable { + + @Id + private int id; + + @Version + private int version; + + private String firstName; + + @OneToOne + private LSE1x1Rt uniRight; + + 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 LSE1x1Rt getUniRight() { + return uniRight; + } + + public void setUniRight(LSE1x1Rt uniRight) { + this.uniRight = uniRight; + } + + public int getVersion() { + return version; + } + + public String toString() { + return this.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(this)) + "[id=" + getId() + + ", ver=" + getVersion() + ", firstName=" + firstName + "]" + + " uniRight=" + getUniRight() + ; + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + id = in.readInt(); + version = in.readInt(); + firstName = in.readUTF(); + uniRight = (LSE1x1Rt) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(id); + out.writeInt(version); + out.writeUTF(firstName); + out.writeObject(uniRight); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1LfJT.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1LfJT.java new file mode 100644 index 000000000..fc780658b --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1LfJT.java @@ -0,0 +1,115 @@ +/* + * 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.lock.extended; + +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.JoinTable; +import javax.persistence.LockModeType; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToOne; +import javax.persistence.QueryHint; +import javax.persistence.Version; + +@NamedQueries ( value={ + @NamedQuery( + name="findLSE1x1LfJTNormal" + , query="SELECT c FROM LSE1x1LfJT c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + ), + @NamedQuery( + name="findLSE1x1LfJTExtended" + , query="SELECT c FROM LSE1x1LfJT c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + , hints={@QueryHint(name="javax.persistence.lock.scope",value="EXTENDED")} + ) + } + ) + +@Entity +public class LSE1x1LfJT implements Externalizable { + + @Id + private int id; + + @Version + private int version; + + private String firstName; + + @OneToOne + @JoinTable(name="Uni1x1LfJT_Uni1x1RT") + private LSE1x1Rt uniRightJT; + + 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 LSE1x1Rt getUniRightJT() { + return uniRightJT; + } + + public void setUniRightJT(LSE1x1Rt uniRightJT) { + this.uniRightJT = uniRightJT; + } + + public int getVersion() { + return version; + } + + public String toString() { + return this.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(this)) + "[id=" + getId() + + ", ver=" + getVersion() + ", firstName=" + firstName + "]" + + " uniRightJT=" + getUniRightJT() + ; + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + id = in.readInt(); + version = in.readInt(); + firstName = in.readUTF(); + uniRightJT = (LSE1x1Rt) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(id); + out.writeInt(version); + out.writeUTF(firstName); + out.writeObject(uniRightJT); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1LfJTLzy.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1LfJTLzy.java new file mode 100644 index 000000000..057d9e900 --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1LfJTLzy.java @@ -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.lock.extended; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinTable; +import javax.persistence.LockModeType; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToOne; +import javax.persistence.QueryHint; +import javax.persistence.Version; + +@NamedQueries ( value={ + @NamedQuery( + name="findLSE1x1LfJTLzyNormal" + , query="SELECT c FROM LSE1x1LfJTLzy c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + ), + @NamedQuery( + name="findLSE1x1LfJTLzyExtended" + , query="SELECT c FROM LSE1x1LfJTLzy c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + , hints={@QueryHint(name="javax.persistence.lock.scope",value="EXTENDED")} + ) + } + ) + +@Entity +public class LSE1x1LfJTLzy implements Externalizable { + + @Id + private int id; + + @Version + private int version; + + private String firstName; + + @OneToOne(fetch=FetchType.LAZY) + @JoinTable(name="Uni1x1LfJT_Uni1x1RT") + private LSE1x1Rt uniRightJT; + + 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 LSE1x1Rt getUniRightJT() { + return uniRightJT; + } + + public void setUniRightJT(LSE1x1Rt uniRightJT) { + this.uniRightJT = uniRightJT; + } + + public int getVersion() { + return version; + } + + public String toString() { + return this.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(this)) + "[id=" + getId() + + ", ver=" + getVersion() + ", firstName=" + firstName + "]" + + " uniRightJT=" + getUniRightJT() + ; + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + id = in.readInt(); + version = in.readInt(); + firstName = in.readUTF(); + uniRightJT = (LSE1x1Rt) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(id); + out.writeInt(version); + out.writeUTF(firstName); + out.writeObject(uniRightJT); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1LfLzy.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1LfLzy.java new file mode 100644 index 000000000..2826b5372 --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1LfLzy.java @@ -0,0 +1,114 @@ +/* + * 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.lock.extended; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.LockModeType; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToOne; +import javax.persistence.QueryHint; +import javax.persistence.Version; + +@NamedQueries ( value={ + @NamedQuery( + name="findLSE1x1LfLzyNormal" + , query="SELECT c FROM LSE1x1LfLzy c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + ), + @NamedQuery( + name="findLSE1x1LfLzyExtended" + , query="SELECT c FROM LSE1x1LfLzy c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + , hints={@QueryHint(name="javax.persistence.lock.scope",value="EXTENDED")} + ) + } + ) + +@Entity +public class LSE1x1LfLzy implements Externalizable { + + @Id + private int id; + + @Version + private int version; + + private String firstName; + + @OneToOne(fetch=FetchType.LAZY) + private LSE1x1Rt uniRight; + + 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 LSE1x1Rt getUniRight() { + return uniRight; + } + + public void setUniRight(LSE1x1Rt uniRight) { + this.uniRight = uniRight; + } + + public int getVersion() { + return version; + } + + public String toString() { + return this.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(this)) + "[id=" + getId() + + ", ver=" + getVersion() + ", firstName=" + firstName + "]" + + " uniRight=" + getUniRight() + ; + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + id = in.readInt(); + version = in.readInt(); + firstName = in.readUTF(); + uniRight = (LSE1x1Rt) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(id); + out.writeInt(version); + out.writeUTF(firstName); + out.writeObject(uniRight); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1Rt.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1Rt.java new file mode 100644 index 000000000..67f178af3 --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1x1Rt.java @@ -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.lock.extended; + +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.Version; + +@Entity +public class LSE1x1Rt implements Externalizable { + + @Id + private int id; + + @Version + private int version; + + private String lastName; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public int getVersion() { + return version; + } + + public String toString() { + return this.getClass().getName() + '@' + + Integer.toHexString(System.identityHashCode(this)) + "[id=" + + getId() + ", ver=" + getVersion() + ", lastName=" + lastName + "]"; + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + id = in.readInt(); + version = in.readInt(); + lastName = in.readUTF(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(id); + out.writeInt(version); + out.writeUTF(lastName); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmLf.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmLf.java new file mode 100644 index 000000000..a1f4e64bf --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmLf.java @@ -0,0 +1,118 @@ +/* + * 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.lock.extended; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Collection; +import java.util.HashSet; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.LockModeType; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToMany; +import javax.persistence.QueryHint; +import javax.persistence.Version; + +@NamedQueries ( value={ + @NamedQuery( + name="findLSE1xmLfNormal" + , query="SELECT c FROM LSE1xmLf c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + ), + @NamedQuery( + name="findLSE1xmLfExtended" + , query="SELECT c FROM LSE1xmLf c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + , hints={@QueryHint(name="javax.persistence.lock.scope",value="EXTENDED")} + ) + } + ) + +@Entity +public class LSE1xmLf implements Externalizable { + + @Id + private int id; + + @Version + private int version; + + private String firstName; + + @OneToMany // (cascade=CascadeType.ALL) (mappedBy="ownerOne") + private Collection uniRight = new HashSet(); + + 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 Collection getUniRight() { + return uniRight; + } + + public void setUnitRight(Collection uniRight) { + this.uniRight = uniRight; + } + + public void addUnitRight(LSE1xmRt uniRight) { + this.uniRight.add(uniRight); + } + + public int getVersion() { + return version; + } + + public String toString() { + return this.getClass().getName() + '@' + + Integer.toHexString(System.identityHashCode(this)) + "[id=" + + getId() + ", ver=" + getVersion() + ", firstName=" + firstName + "] ownedMany=" + getUniRight(); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + id = in.readInt(); + version = in.readInt(); + firstName = in.readUTF(); + uniRight = (Collection) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(id); + out.writeInt(version); + out.writeUTF(firstName); + out.writeObject(uniRight); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmLfEgr.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmLfEgr.java new file mode 100644 index 000000000..8c1fbf811 --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmLfEgr.java @@ -0,0 +1,119 @@ +/* + * 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.lock.extended; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Collection; +import java.util.HashSet; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.LockModeType; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToMany; +import javax.persistence.QueryHint; +import javax.persistence.Version; + +@NamedQueries ( value={ + @NamedQuery( + name="findLSE1xmLfEgrNormal" + , query="SELECT c FROM LSE1xmLfEgr c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + ), + @NamedQuery( + name="findLSE1xmLfEgrExtended" + , query="SELECT c FROM LSE1xmLfEgr c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + , hints={@QueryHint(name="javax.persistence.lock.scope",value="EXTENDED")} + ) + } + ) + +@Entity +public class LSE1xmLfEgr implements Externalizable { + + @Id + private int id; + + @Version + private int version; + + private String firstName; + + @OneToMany(fetch=FetchType.EAGER) //(mappedBy="ownerOne") + private Collection uniRight = new HashSet(); + + 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 Collection getUniRight() { + return uniRight; + } + + public void setUnitRight(Collection uniRight) { + this.uniRight = uniRight; + } + + public void addUnitRight(LSE1xmRt uniRight) { + this.uniRight.add(uniRight); + } + + public int getVersion() { + return version; + } + + public String toString() { + return this.getClass().getName() + '@' + + Integer.toHexString(System.identityHashCode(this)) + "[id=" + + getId() + ", ver=" + getVersion() + ", firstName=" + firstName + "] ownedMany=" + getUniRight(); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + id = in.readInt(); + version = in.readInt(); + firstName = in.readUTF(); + uniRight = (Collection) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(id); + out.writeInt(version); + out.writeUTF(firstName); + out.writeObject(uniRight); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmLfJT.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmLfJT.java new file mode 100644 index 000000000..31d00ea67 --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmLfJT.java @@ -0,0 +1,120 @@ +/* + * 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.lock.extended; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Collection; +import java.util.HashSet; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinTable; +import javax.persistence.LockModeType; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToMany; +import javax.persistence.QueryHint; +import javax.persistence.Version; + +@NamedQueries ( value={ + @NamedQuery( + name="findLSE1xmLfJTNormal" + , query="SELECT c FROM LSE1xmLfJT c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + ), + @NamedQuery( + name="findLSE1xmLfJTExtended" + , query="SELECT c FROM LSE1xmLfJT c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + , hints={@QueryHint(name="javax.persistence.lock.scope",value="EXTENDED")} + ) + } + ) + +@Entity +public class LSE1xmLfJT implements Externalizable { + + @Id + private int id; + + @Version + private int version; + + private String firstName; + + @JoinTable + @OneToMany //(mappedBy="ownerOne") + private Collection uniRight = new HashSet(); + + 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 Collection getUniRight() { + return uniRight; + } + + public void setUnitRight(Collection uniRight) { + this.uniRight = uniRight; + } + + public void addUnitRight(LSE1xmRt uniRight) { + this.uniRight.add(uniRight); + } + + public int getVersion() { + return version; + } + + public String toString() { + return this.getClass().getName() + '@' + + Integer.toHexString(System.identityHashCode(this)) + "[id=" + + getId() + ", ver=" + getVersion() + ", firstName=" + firstName + "] ownedMany=" + getUniRight(); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + id = in.readInt(); + version = in.readInt(); + firstName = in.readUTF(); + uniRight = (Collection) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(id); + out.writeInt(version); + out.writeUTF(firstName); + out.writeObject(uniRight); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmLfJTEgr.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmLfJTEgr.java new file mode 100644 index 000000000..91cf9dd12 --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmLfJTEgr.java @@ -0,0 +1,119 @@ +/* + * 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.lock.extended; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Collection; +import java.util.HashSet; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.LockModeType; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToMany; +import javax.persistence.QueryHint; +import javax.persistence.Version; + +@NamedQueries ( value={ + @NamedQuery( + name="findLSE1xmLfJTEgrNormal" + , query="SELECT c FROM LSE1xmLfJTEgr c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + ), + @NamedQuery( + name="findLSE1xmLfJTEgrExtended" + , query="SELECT c FROM LSE1xmLfJTEgr c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + , hints={@QueryHint(name="javax.persistence.lock.scope",value="EXTENDED")} + ) + } + ) + +@Entity +public class LSE1xmLfJTEgr implements Externalizable { + + @Id + private int id; + + @Version + private int version; + + private String firstName; + + @OneToMany(fetch=FetchType.EAGER)//(mappedBy="ownerOne") + private Collection uniRight = new HashSet(); + + 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 Collection getUniRight() { + return uniRight; + } + + public void setUnitRight(Collection uniRight) { + this.uniRight = uniRight; + } + + public void addUnitRight(LSE1xmRt uniRight) { + this.uniRight.add(uniRight); + } + + public int getVersion() { + return version; + } + + public String toString() { + return this.getClass().getName() + '@' + + Integer.toHexString(System.identityHashCode(this)) + "[id=" + + getId() + ", ver=" + getVersion() + ", firstName=" + firstName + "] ownedMany=" + getUniRight(); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + id = in.readInt(); + version = in.readInt(); + firstName = in.readUTF(); + uniRight = (Collection) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(id); + out.writeInt(version); + out.writeUTF(firstName); + out.writeObject(uniRight); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmRt.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmRt.java new file mode 100644 index 000000000..dee40b994 --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSE1xmRt.java @@ -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.lock.extended; + +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.Version; + +@Entity +public class LSE1xmRt implements Externalizable { + + @Id + private int id; + + @Version + private int version; + + private String lastName; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public int getVersion() { + return version; + } + + public String toString() { + return this.getClass().getName() + '@' + + Integer.toHexString(System.identityHashCode(this)) + "[id=" + + getId() + ", ver=" + getVersion() + ", lastName=" + lastName + "]"; + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + id = in.readInt(); + version = in.readInt(); + lastName = in.readUTF(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(id); + out.writeInt(version); + out.writeUTF(lastName); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEBase.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEBase.java new file mode 100644 index 000000000..39a748edd --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEBase.java @@ -0,0 +1,110 @@ +/* + * 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.lock.extended; + +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.LockModeType; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.QueryHint; +import javax.persistence.Version; + +@NamedQueries ( value={ + @NamedQuery( + name="findLSEBaseNormal" + , query="SELECT c FROM LSEBase c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + ), + @NamedQuery( + name="findLSEBaseExtended" + , query="SELECT c FROM LSEBase c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + , hints={@QueryHint(name="javax.persistence.lock.scope",value="EXTENDED")} + ) + } +) + +@Entity +public class LSEBase implements Externalizable { + + @Id + private int id; + + @Version + private int version; + + private String firstName; + private String lastName; + + 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; + } + + public int getVersion() { + return version; + } + + public String toString() { + return this.getClass().getName() + '@' + + Integer.toHexString(System.identityHashCode(this)) + "[id=" + + getId() + ", ver=" + getVersion() + "] first=" + getFirstName() + + ", last=" + getLastName(); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + id = in.readInt(); + version = in.readInt(); + firstName = (String) in.readObject(); + lastName = (String) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(id); + out.writeInt(version); + out.writeObject(firstName); + out.writeObject(lastName); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEEleCol.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEEleCol.java new file mode 100644 index 000000000..72600f01e --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEEleCol.java @@ -0,0 +1,118 @@ +/* + * 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.lock.extended; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.HashSet; +import java.util.Set; + +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.LockModeType; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.QueryHint; +import javax.persistence.Version; + +@NamedQueries ( value={ + @NamedQuery( + name="findLSEEleColNormal" + , query="SELECT c FROM LSEEleCol c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + ), + @NamedQuery( + name="findLSEEleColExtended" + , query="SELECT c FROM LSEEleCol c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + , hints={@QueryHint(name="javax.persistence.lock.scope",value="EXTENDED")} + ) + } + ) + +@Entity +public class LSEEleCol implements Externalizable { + + @Id + private int id; + + @Version + private int version; + + private String firstName; + + @ElementCollection + protected Set collection = new HashSet(); + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String name) { + this.firstName = name; + } + + public Set getCollection() { + return collection; + } + + public void setCollection(Set collection) { + this.collection = collection; + } + + public void addCollection(String element) { + collection.add(element); + } + + public int getVersion() { + return version; + } + + public String toString() { + return this.getClass().getName() + '@' + + Integer.toHexString(System.identityHashCode(this)) + "[id=" + + getId() + ", ver=" + getVersion() + ", firstName=" + getFirstName() + "] one=" + getCollection(); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + id = in.readInt(); + version = in.readInt(); + firstName = in.readUTF(); + collection = (Set) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(id); + out.writeInt(version); + out.writeUTF(firstName); + out.writeObject(collection); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEEleColEgr.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEEleColEgr.java new file mode 100644 index 000000000..aebfbefd3 --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEEleColEgr.java @@ -0,0 +1,119 @@ +/* + * 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.lock.extended; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.HashSet; +import java.util.Set; + +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.LockModeType; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.QueryHint; +import javax.persistence.Version; + +@NamedQueries ( value={ + @NamedQuery( + name="findLSEEleColEgrNormal" + , query="SELECT c FROM LSEEleColEgr c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + ), + @NamedQuery( + name="findLSEEleColEgrExtended" + , query="SELECT c FROM LSEEleColEgr c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + , hints={@QueryHint(name="javax.persistence.lock.scope",value="EXTENDED")} + ) + } + ) + +@Entity +public class LSEEleColEgr implements Externalizable { + + @Id + private int id; + + @Version + private int version; + + private String firstName; + + @ElementCollection(fetch=FetchType.EAGER) + protected Set collection = new HashSet(); + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String name) { + this.firstName = name; + } + + public Set getCollection() { + return collection; + } + + public void setCollection(Set collection) { + this.collection = collection; + } + + public void addCollection(String element) { + collection.add(element); + } + + public int getVersion() { + return version; + } + + public String toString() { + return this.getClass().getName() + '@' + + Integer.toHexString(System.identityHashCode(this)) + "[id=" + + getId() + ", ver=" + getVersion() + ", firstName=" + getFirstName() + "] one=" + getCollection(); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + id = in.readInt(); + version = in.readInt(); + firstName = in.readUTF(); + collection = (Set) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(id); + out.writeInt(version); + out.writeUTF(firstName); + out.writeObject(collection); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEJoinAbs.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEJoinAbs.java new file mode 100644 index 000000000..9df09c15c --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEJoinAbs.java @@ -0,0 +1,81 @@ +/* + * 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.lock.extended; + +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.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.Version; + +@Entity +@Inheritance(strategy=InheritanceType.JOINED) +public abstract class LSEJoinAbs implements Externalizable { + + @Id + private int id; + + @Version + private int version; + + private String firstName; + 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 int getVersion() { + return version; + } + + public String toString() { + return this.getClass().getName() + '@' + + Integer.toHexString(System.identityHashCode(this)) + "[id=" + + getId() + ", ver=" + getVersion() + "] first=" + getFirstName(); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + id = in.readInt(); + version = in.readInt(); + firstName = (String) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(id); + out.writeInt(version); + out.writeObject(firstName); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEJoinCon.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEJoinCon.java new file mode 100644 index 000000000..37e8fc715 --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSEJoinCon.java @@ -0,0 +1,76 @@ +/* + * 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.lock.extended; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import javax.persistence.Entity; +import javax.persistence.LockModeType; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.QueryHint; + +@NamedQueries ( value={ + @NamedQuery( + name="findLSEJoinConNormal" + , query="SELECT c FROM LSEJoinCon c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + ), + @NamedQuery( + name="findLSEJoinConExtended" + , query="SELECT c FROM LSEJoinCon c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + , hints={@QueryHint(name="javax.persistence.lock.scope",value="EXTENDED")} + ) + } + ) + +@Entity +public class LSEJoinCon extends LSEJoinAbs implements Externalizable { + + private String lastName; + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String toString() { + return this.getClass().getName() + '@' + + Integer.toHexString(System.identityHashCode(this)) + super.toString() + + ", last=" + getLastName(); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + super.readExternal(in); + lastName = (String) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + super.writeExternal(out); + out.writeObject(lastName); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSESecTbl.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSESecTbl.java new file mode 100644 index 000000000..dc0264d4f --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSESecTbl.java @@ -0,0 +1,112 @@ +/* + * 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.lock.extended; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.LockModeType; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.QueryHint; +import javax.persistence.SecondaryTable; +import javax.persistence.Version; + +@NamedQueries ( value={ + @NamedQuery( + name="findLSESecTblNormal" + , query="SELECT c FROM LSESecTbl c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + ), + @NamedQuery( + name="findLSESecTblExtended" + , query="SELECT c FROM LSESecTbl c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + , hints={@QueryHint(name="javax.persistence.lock.scope",value="EXTENDED")} + ) + } + ) + +@Entity +@SecondaryTable(name="LSESecTblDtl") +public class LSESecTbl implements Externalizable { + + @Id + private int id; + + @Version + private int version; + + private String firstName; + @Column(table="LSESecTblDtl") + private String lastName; + + 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; + } + + public int getVersion() { + return version; + } + + public String toString() { + return this.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(this)) + "[id=" + getId() + + ", ver=" + getVersion() + "] first=" + getFirstName() + ", last=" + getLastName(); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + id = in.readInt(); + version = in.readInt(); + firstName = (String) in.readObject(); + lastName = (String) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(id); + out.writeInt(version); + out.writeObject(firstName); + out.writeObject(lastName); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSESngTblAbs.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSESngTblAbs.java new file mode 100644 index 000000000..7c2156f0d --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSESngTblAbs.java @@ -0,0 +1,100 @@ +/* + * 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.lock.extended; + +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.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.LockModeType; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.QueryHint; +import javax.persistence.Version; + +@NamedQueries ( value={ + @NamedQuery( + name="findLSESngTblAbsNormal" + , query="SELECT c FROM LSESngTblAbs c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + ), + @NamedQuery( + name="findLSESngTblAbsExtended" + , query="SELECT c FROM LSESngTblAbs c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + , hints={@QueryHint(name="javax.persistence.lock.scope",value="EXTENDED")} + ) + } + ) + +@Entity +@Inheritance(strategy=InheritanceType.SINGLE_TABLE) +public abstract class LSESngTblAbs implements Externalizable { + + @Id + private int id; + + @Version + private int version; + + private String firstName; + 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 int getVersion() { + return version; + } + + public String toString() { + return this.getClass().getName() + '@' + + Integer.toHexString(System.identityHashCode(this)) + "[id=" + + getId() + ", ver=" + getVersion() + "] first=" + getFirstName(); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + id = in.readInt(); + version = in.readInt(); + firstName = (String) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeInt(id); + out.writeInt(version); + out.writeObject(firstName); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSESngTblCon.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSESngTblCon.java new file mode 100644 index 000000000..ac0daddaa --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LSESngTblCon.java @@ -0,0 +1,76 @@ +/* + * 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.lock.extended; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import javax.persistence.Entity; +import javax.persistence.LockModeType; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.QueryHint; + +@NamedQueries ( value={ + @NamedQuery( + name="findLSESngTblConNormal" + , query="SELECT c FROM LSESngTblCon c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + ), + @NamedQuery( + name="findLSESngTblConExtended" + , query="SELECT c FROM LSESngTblCon c WHERE c.firstName LIKE :firstName" + , lockMode=LockModeType.PESSIMISTIC_WRITE + , hints={@QueryHint(name="javax.persistence.lock.scope",value="EXTENDED")} + ) + } + ) + +@Entity +public class LSESngTblCon extends LSESngTblAbs implements Externalizable { + + private String lastName; + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String toString() { + return this.getClass().getName() + '@' + + Integer.toHexString(System.identityHashCode(this)) + super.toString() + + ", last=" + getLastName(); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + super.readExternal(in); + lastName = (String) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + super.writeExternal(out); + out.writeObject(lastName); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LockScopeTestCase.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LockScopeTestCase.java new file mode 100644 index 000000000..cce1ec3f4 --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LockScopeTestCase.java @@ -0,0 +1,324 @@ +/* + * 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.lock.extended; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.persistence.EntityManager; +import javax.persistence.LockModeType; +import javax.persistence.PessimisticLockScope; +import javax.persistence.Query; + +import org.apache.openjpa.jdbc.conf.JDBCConfiguration; +import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl; +import org.apache.openjpa.lib.log.Log; +import org.apache.openjpa.persistence.MixedLockLevelsHelper; +import org.apache.openjpa.persistence.OpenJPAEntityManager; +import org.apache.openjpa.persistence.test.SQLListenerTestCase; + +/** + * Base class for locking extended scope tests. + * + * Test JPA 2.0 EM interface normal lock scope behaviors with "mixed" lock + * manager. When an entity instance is locked using pessimistic locking, the + * persistence provider must lock the database row(s) that correspond to the + * non-collection-valued persistent state of that instance. If a joined + * inheritance strategy is used, or if the entity is otherwise mapped to a + * secondary table, this entails locking the row(s) for the entity instance in + * the additional table(s). Entity relationships for which the locked entity + * contains the foreign key will also be locked, but not the state of the + * referenced entities (unless hose entities are explicitly locked). Element + * collections and relationships for which the entity does not contain the + * foreign key (such as relationships that are mapped to join tables or + * unidirectional one-to-many relationships for which the target entity contains + * the foreign key) will not be locked by default. + * + * Element collections and relationships owned by the entity that are contained + * in join tables will be locked if the javax.persistence.lock.scope property is + * specified with a value of PessimisticLockScope.EXTENDED. The state of + * entities referenced by such relationships will not be locked (unless those + * entities are explicitly locked). This property may be passed as an argument + * to the methods of the EntityManager and Query interfaces that allow lock + * modes to be specified or used with the NamedQuery annotation. + * + * @since 2.0 + */ +public abstract class LockScopeTestCase extends SQLListenerTestCase { + + protected final String Select = "SELECT.*FROM.*"; + protected final String Where = ".*WHERE.*"; + protected final String ForUpdateRex = "FOR UPDATE.*"; + protected final String ForUpdateClause = "(" + ForUpdateRex + ")"; + protected final String ForUpdate = ForUpdateClause + "{1}"; + protected final String NoForUpdate = ForUpdateClause + "{0}"; + protected final String DB2LockClause = "(" + ForUpdateRex + + "|FOR READ ONLY WITH R. USE AND KEEP (UPDATE|EXCLUSIVE) LOCKS)"; + protected final String DB2Lock = DB2LockClause + "{1}"; + protected final String NoDB2Lock = DB2LockClause + "{0}"; + + protected List empTableName = new ArrayList();; + + protected Map normalProps; + protected Map extendedProps; + + protected void commonSetUp(Class... eClasses ) { + normalProps = new HashMap(); + extendedProps = new HashMap(); + extendedProps.put("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED); + + for( Class eClazz : eClasses) { + empTableName.add(getMapping(eClazz).getTable().getFullName()); + } + cleanupDB(); + } + + private void cleanupDB() { + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + for (String tableName : empTableName.toArray(new String[empTableName.size()])) { + em.createQuery("delete from " + tableName).executeUpdate(); + } + em.getTransaction().commit(); + } catch(Exception e) { + e.printStackTrace(); + } finally { + if (em != null && em.isOpen()) { + em.close(); + } + } + } + + protected enum DBType { + access, db2, derby, empress, foxpro, h2, hsql, informix, ingres, jdatastore, mysql, oracle, pointbase, postgres, + sqlserver, sybase + }; + + protected DBType getDBType(EntityManager em) { + JDBCConfigurationImpl conf = (JDBCConfigurationImpl) getConfiguration(em); + String dictClassName = getConfiguration(em).getDBDictionaryInstance().getClass().getName(); + String db = conf.dbdictionaryPlugin.alias(dictClassName); + return DBType.valueOf(db); + } + + @SuppressWarnings( { "unused", "deprecation" }) + protected JDBCConfiguration getConfiguration(EntityManager em) { + return ((JDBCConfiguration) ((OpenJPAEntityManager) em).getConfiguration()); + } + + protected Log getLog() { + return emf.getConfiguration().getLog("Tests"); + } + + protected Log getDumpStackLog() { + return emf.getConfiguration().getLog("DumpStack"); + } + + /* + * Set Log=LockTestSQL=TRACE to dump the SQL caught by the SQL listener but do not perform SQL assertion. + */ + protected Log getDumpSQLLog() { + return emf.getConfiguration().getLog("LockTestSQL"); + } + + public void assertLockTestSQLs(String... expected) { + Log log = getDumpSQLLog(); + if( log.isTraceEnabled()) { + log.trace("\r\n" + toString(sql)); + return; + } + assertAnySQLAnyOrder(expected); + } + + protected void logStack(Throwable t) { + StringWriter str = new StringWriter(); + PrintWriter print = new PrintWriter(str); + t.printStackTrace(print); + getDumpStackLog().trace(str.toString()); + } + + // Id designation- + // for basic test: + // [basic=0,sectable=1,singletable=2,join=4,eleColl=5,eleCollEager=6][normal=0|extended=1][entity#] + // For 1x1/1xm tests: + // [1x1=1,1xM=2] [uni=1|bi=2] [left=1|right=2] [normal=1|join=2] [default=0|lazy=1|eager=2] + // [normal=0|extended=1] [n-th entity] + protected void commonLockTest(String testName, Class type, int id0, boolean extended, String queryString, + String namedQueryString, AssertCallback verify) { + getLog().info("** " + testName + "()"); + String entityName = type.getName(); + String scope = extended ? "Extended" : "Normal"; + Map props = extended ? extendedProps : normalProps; + int id1 = id0 + 1; + + EntityManager em = null; + T e0 = null; + T e1 = null; + try { + getLog().info("-- Test find with no lock in " + scope + " scope"); + em = emf.createEntityManager(); + getLog().info(" *Begin a transaction."); + em.getTransaction().begin(); + resetSQL(); + getLog().info(" *Find " + entityName + "(" + id0 + ") with no lock"); + e0 = em.find(type, id0, props); + getLog().info(" *" + (e0 != null ? "F" : "Can not f") + "ind entity"); + verify.findNoLockDbSQL(em); + getLog().info(" *Found entity:" + e0); + assertNotNull(" *Found " + entityName + "(" + id0 + ")", e0); + assertEquals(" *Assert no lock applied", LockModeType.NONE, em.getLockMode(e0)); + + getLog().info(" *Find " + entityName + "(" + id1 + ") with pessimistic force increment lock"); + resetSQL(); + e1 = em.find(type, id1, LockModeType.PESSIMISTIC_FORCE_INCREMENT, props); + getLog().info(" *" + (e1 != null ? "F" : "Can not f") + "ind entity"); + verify.findPessimisticForcIncDbSQL(em); + getLog().info(" *Found entity:" + e1); + assertNotNull(" *Found " + entityName + "(" + id1 + ")", e1); + assertEquals(" *Assert pessimistic force increment lock applied", LockModeType.PESSIMISTIC_FORCE_INCREMENT, + em.getLockMode(e1)); + + getLog().info("Committing transaction."); + em.getTransaction().commit(); + } finally { + em = null; + e0 = e1 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + + try { + getLog().info("-- Test query with pessimistic read lock in " + scope + " scope"); + em = emf.createEntityManager(); + getLog().info(" *Begin a transaction."); + em.getTransaction().begin(); + resetSQL(); + int beforeReadLevel = getConfiguration(em).getReadLockLevelConstant(); + LockModeType beforeReadMode = MixedLockLevelsHelper.fromLockLevel(beforeReadLevel); + getLog().info(" *Save ReadLockLevel before Query:" + beforeReadMode); + getLog().info(" *Query " + entityName + "(" + id0 + ") with PESSIMISTIC_READ lock"); + Query q = em.createQuery(queryString); + if (extended) { + q = q.setHint("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED); + } + q = q.setLockMode(LockModeType.PESSIMISTIC_READ); + q = q.setParameter("firstName", "firstName%" + id0); + List es = q.getResultList(); + getLog().info(" *Found " + es.size() + " entity"); + assertEquals(" *Should find 1 entity", es.size(), 1); + verify.queryPessimisticReadDbSQL(em); + e0 = es.get(0); + getLog().info(" *Found entity:" + e0); + assertNotNull(" *Found " + entityName + "(" + id0 + ")", e0); + assertEquals("Assert pessimistic read lock applied", LockModeType.PESSIMISTIC_READ, em.getLockMode(e0)); + assertEquals(" *Read lock should still be " + beforeReadMode + "after query set lock mode", + beforeReadLevel, getConfiguration(em).getReadLockLevelConstant()); + + getLog().info( + " *Find " + entityName + "(" + id1 + + ") with no lock to verify query lock set does not affect em lock mode."); + resetSQL(); + e1 = em.find(type, id1); + getLog().info(" *" + (e1 != null ? "F" : "Can not f") + "ind entity"); + verify.findNoLockAfterQueryPessimisticReadDbSQL(em); + getLog().info(" *Found entity:" + e1); + assertNotNull(" *Found " + entityName + "(" + id1 + ")", e1); + assertEquals(" *Assert default lock applied", LockModeType.NONE, em.getLockMode(e1)); + + getLog().info("Committing transaction."); + em.getTransaction().commit(); + } finally { + em = null; + e0 = e1 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + + try { + getLog().info("-- Test name query with pessimistic write lock in " + scope + " scope"); + em = emf.createEntityManager(); + getLog().info(" *Begin a transaction."); + em.getTransaction().begin(); + resetSQL(); + int beforeReadLevel = getConfiguration(em).getReadLockLevelConstant(); + LockModeType beforeReadMode = MixedLockLevelsHelper.fromLockLevel(beforeReadLevel); + getLog().info(" *Save ReadLockLevel before Query:" + beforeReadMode); + getLog().info(" *Query " + entityName + "(" + id0 + ") with PESSIMISTIC_WRITE lock"); + Query q = em.createNamedQuery(namedQueryString); + if (extended) { + q = q.setHint("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED); + } + q = q.setParameter("firstName", "firstName%" + id0); + List es = q.getResultList(); + getLog().info(" *Found " + es.size() + " entity"); + assertEquals(" *Found 1 entity", es.size(), 1); + verify.namedQueryPessimisticWriteDbSql(em); + e0 = es.get(0); + getLog().info(" *Found entity:" + e0); + assertNotNull(" *Found " + entityName + "(" + id0 + ")", e0); + assertEquals("Assert pessimistic write lock applied", LockModeType.PESSIMISTIC_WRITE, em.getLockMode(e0)); + + getLog().info(" *Ensure ReadLockLevel remains at level " + beforeReadMode); + assertEquals(" *Read lock should still be " + beforeReadMode + "after query set lock mode", + beforeReadLevel, getConfiguration(em).getReadLockLevelConstant()); + + getLog().info( + " *Find " + entityName + "(" + id1 + + ") with no lock to verify query lock set does not affect em lock mode."); + resetSQL(); + e1 = em.find(type, id1); + getLog().info(" *" + (e1 != null ? "F" : "Can not f") + "ind an entity"); + verify.findNoLockAfterNamedQueryPessimisticWriteDbSql(em); + getLog().info(" *Found entity:" + e1); + assertNotNull(" *Found " + entityName + "(" + id1 + ")", e1); + assertEquals(" *Assert default lock applied", LockModeType.NONE, em.getLockMode(e1)); + + getLog().info("Committing transaction."); + em.getTransaction().commit(); + } finally { + em = null; + e0 = e1 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + } + + protected interface AssertCallback { + public void findNoLockDbSQL(EntityManager em); + + public void findPessimisticForcIncDbSQL(EntityManager em); + + public void queryPessimisticReadDbSQL(EntityManager em); + + public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em); + + public void namedQueryPessimisticWriteDbSql(EntityManager em); + + public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/Test1x1LockScope.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/Test1x1LockScope.java new file mode 100644 index 000000000..bfc602442 --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/Test1x1LockScope.java @@ -0,0 +1,937 @@ +/* + * 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.lock.extended; + +import javax.persistence.EntityManager; + +/** + * LockScopeTestCase subclass to test entity with: + * - Uni-1x1 - eager fetch (default) + * - Uni-1x1 - lazy fetch + * - Uni-1x1 use join table - eager fetch (default) + * - Uni-1x1 use join table - lazy fetch + */ +public class Test1x1LockScope extends LockScopeTestCase { + + public void setUp() { + setUp(LSE1x1Lf.class + , LSE1x1LfLzy.class + , LSE1x1LfJT.class + , LSE1x1LfJTLzy.class + , LSE1x1Rt.class + , "openjpa.LockManager", "mixed", + "openjpa.jdbc.SynchronizeMappings", "buildSchema(ForeignKeys=true)" + ); + commonSetUp(LSE1x1Lf.class + , LSE1x1LfLzy.class + , LSE1x1LfJT.class + , LSE1x1LfJTLzy.class + , LSE1x1Rt.class + ); + } + + public void testNormalUni1x1Lock() { + common1x1Lock("testNormalUni1x1Lock", 1111201, false); + } + + public void testExtendedUni1x1Lock() { + common1x1Lock("testExtendedUni1x1Lock", 1111211, true); + } + + private void common1x1Lock(String testName, int idLf0, boolean extended) { + final String tableLfName = "LSE1x1Lf"; + final String tableRtName = "LSE1x1Rt"; + final String joinTables = tableLfName + ".*JOIN.*" + tableRtName; + getLog().info("** " + testName + "()"); + String scope = extended ? "Extended" : "Normal"; + int idRt0 = idLf0 + 10000; // right table + int idLf1 = idLf0 + 1; + int idRt1 = idRt0 + 1; + + // create test entity. + LSE1x1Lf eLf0 = new LSE1x1Lf(); + LSE1x1Rt eRt0 = new LSE1x1Rt(); + eLf0.setId(idLf0); + eLf0.setFirstName("firstName " + idLf0); + eLf0.setUniRight(eRt0); + eRt0.setId(idRt0); + eRt0.setLastName("lastName " + idRt0); + LSE1x1Lf eLf1 = new LSE1x1Lf(); + LSE1x1Rt eRt1 = new LSE1x1Rt(); + eLf1.setId(idLf1); + eLf1.setFirstName("firstName " + idLf1); + eLf1.setUniRight(eRt1); + eRt1.setId(idRt1); + eRt1.setLastName("lastName " + idRt1); + + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(eLf0); + em.persist(eRt0); + em.persist(eLf1); + em.persist(eRt1); + em.getTransaction().commit(); + } finally { + em = null; + eLf0 = eLf1 = null; + eRt0 = eRt1 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + + commonLockTest(testName, LSE1x1Lf.class, idLf0, extended, + "SELECT c FROM LSE1x1Lf c WHERE c.firstName LIKE :firstName", "findLSE1x1Lf" + scope, + new AssertCallback() { + public void findNoLockDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 + // LEFT OUTER JOIN LSE1x1Rt t1 ON t0.UNIRIGHT_ID = t1.id WHERE t0.id = ? + // optimize for 1 row [params=(int) 1111201] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.id, t1.version, t1.lastName + // FROM LSE1x1Lf t0, LSE1x1Rt t1 WHERE t0.id = ? AND t0.UNIRIGHT_ID = t1.id(+) + // [params=(int) 1111201] + assertLockTestSQLs(Select + tableLfName + ".*" + tableRtName + Where + "\\(\\+\\).*" + + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 + // LEFT OUTER JOIN LSE1x1Rt t1 ON t0.UNIRIGHT_ID = t1.id WHERE t0.id = ? + // [params=(int) 1111201] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + + public void findPessimisticForcIncDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 + // LEFT OUTER JOIN LSE1x1Rt t1 ON t0.UNIRIGHT_ID = t1.id WHERE t0.id = ? + // optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1111202] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1121202] + // SELECT t0.version FROM LSE1x1Lf t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1111202] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + break; + case oracle: // TODO: if jpa2, DO NOT lock LSE1x1RT using "FOR UPDATE OF col" + // SELECT t0.version, t0.firstName, t1.id, t1.version, t1.lastName + // FROM LSE1x1Lf t0, LSE1x1Rt t1 WHERE t0.id = ? AND t0.UNIRIGHT_ID = t1.id(+) + // FOR UPDATE [params=(int) 1111202] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE [params=(int) 1121202] + // SELECT t0.version FROM LSE1x1Lf t0 WHERE t0.id = ? FOR UPDATE [params=(int) 1111202] + assertLockTestSQLs(Select + tableLfName + ".*" + tableRtName + Where + "\\(\\+\\).*" + + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock. + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 + // LEFT OUTER JOIN LSE1x1Rt t1 ON t0.UNIRIGHT_ID = t1.id WHERE t0.id = ? + // [params=(int) 1111202] + // SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1121202] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1121202] + // SELECT t0.id FROM LSE1x1Lf t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1111202] + // SELECT t0.version FROM LSE1x1Lf t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1111202] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + tableLfName + ".*" + Where + ForUpdate, + Select + tableRtName + ".*" + Where + ForUpdate + ); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void queryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 + // LEFT OUTER JOIN LSE1x1Rt t1 ON t0.UNIRIGHT_ID = t1.id + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%1111201] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1121201] + // SELECT t0.version FROM LSE1x1Lf t0 WHERE t0.id = ? [params=(int) 1111201] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + break; + case oracle: // TODO: if jpa2, DO NOT lock LSE1x1RT using "FOR UPDATE OF col" + // SELECT t0.id, t0.version, t0.firstName, t1.id, t1.version, t1.lastName + // FROM LSE1x1Lf t0, LSE1x1Rt t1 + // WHERE (t0.firstName LIKE ?) AND t0.UNIRIGHT_ID = t1.id(+) + // FOR UPDATE [params=(String) firstName%1111201] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1121201] + // SELECT t0.version FROM LSE1x1Lf t0 WHERE t0.id = ? [params=(int) 1111201] + assertLockTestSQLs(Select + tableLfName + ".*" + tableRtName + Where + "\\(\\+\\).*" + + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock. + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + //SELECT t0.id, t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 + // LEFT OUTER JOIN LSE1x1Rt t1 ON t0.UNIRIGHT_ID = t1.id + // WHERE (t0.firstName LIKE ? ESCAPE '\') [params=(String) firstName%1111201] + // SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1121201] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1121201] + // SELECT t0.id FROM LSE1x1Lf t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1111201] + // SELECT t0.version FROM LSE1x1Lf t0 WHERE t0.id = ? [params=(int) 1111201] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + tableLfName + ".*" + Where + ForUpdate, + Select + tableRtName + ".*" + Where + ForUpdate + ); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 + // LEFT OUTER JOIN LSE1x1Rt t1 ON t0.UNIRIGHT_ID = t1.id WHERE t0.id = ? + // optimize for 1 row [params=(int) 1111202] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.id, t1.version, t1.lastName + // FROM LSE1x1Lf t0, LSE1x1Rt t1 WHERE t0.id = ? AND t0.UNIRIGHT_ID = t1.id(+) + // [params=(int) 1111202] + assertLockTestSQLs(Select + tableLfName + ".*" + tableRtName + Where + "\\(\\+\\).*" + + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 + // LEFT OUTER JOIN LSE1x1Rt t1 ON t0.UNIRIGHT_ID = t1.id WHERE t0.id = ? + // [params=(int) 1111202] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + + public void namedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 + // LEFT OUTER JOIN LSE1x1Rt t1 ON t0.UNIRIGHT_ID = t1.id + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%1111201] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1121201] + // SELECT t0.version FROM LSE1x1Lf t0 WHERE t0.id = ? [params=(int) 1111201] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + break; + case oracle: // TODO: if jpa2, DO NOT lock LSE1x1RT using "FOR UPDATE OF col" + // SELECT t0.id, t0.version, t0.firstName, t1.id, t1.version, t1.lastName + // FROM LSE1x1Lf t0, LSE1x1Rt t1 + // WHERE (t0.firstName LIKE ?) AND t0.UNIRIGHT_ID = t1.id(+) + // FOR UPDATE [params=(String) firstName%1111201] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1121201] + // SELECT t0.version FROM LSE1x1Lf t0 WHERE t0.id = ? [params=(int) 1111201] + assertLockTestSQLs(Select + tableLfName + ".*" + tableRtName + Where + "\\(\\+\\).*" + + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock. + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 + // LEFT OUTER JOIN LSE1x1Rt t1 ON t0.UNIRIGHT_ID = t1.id + // WHERE (t0.firstName LIKE ? ESCAPE '\') [params=(String) firstName%1111201] + // SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1121201] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1121201] + // SELECT t0.id FROM LSE1x1Lf t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1111201] + // SELECT t0.version FROM LSE1x1Lf t0 WHERE t0.id = ? [params=(int) 1111201] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + tableLfName + ".*" + Where + ForUpdate, + Select + tableRtName + ".*" + Where + ForUpdate + ); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 + // LEFT OUTER JOIN LSE1x1Rt t1 ON t0.UNIRIGHT_ID = t1.id WHERE t0.id = ? + // optimize for 1 row [params=(int) 1111202] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.id, t1.version, t1.lastName + // FROM LSE1x1Lf t0, LSE1x1Rt t1 WHERE t0.id = ? AND t0.UNIRIGHT_ID = t1.id(+) + // [params=(int) 1111202] + assertLockTestSQLs(Select + tableLfName + ".*" + tableRtName + Where + "\\(\\+\\).*" + + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 + // LEFT OUTER JOIN LSE1x1Rt t1 ON t0.UNIRIGHT_ID = t1.id WHERE t0.id = ? + // [params=(int) 1111202] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + }); + } + + public void testNormalUni1x1LazyLock() { + common1x1LazyLock("testNormalUni1x1LazyLock", 1111101, false); + } + + public void testExtendedUni1x1LazyLock() { + common1x1LazyLock("testExtendedUni1x1LazyLock", 1111111, true); + } + + private void common1x1LazyLock(String testName, int idLf0, boolean extended) { + final String tableLfName = "LSE1x1LfLzy"; +// final String tableRtName = "LockSEUni1x1RT"; + getLog().info("** " + testName + "()"); + String scope = extended ? "Extended" : "Normal"; + int idRt0 = idLf0 + 10000; // right table + int idLf1 = idLf0 + 1; + int idRt1 = idRt0 + 1; + + // create test entity. + LSE1x1LfLzy eLf0 = new LSE1x1LfLzy(); + LSE1x1Rt eRt0 = new LSE1x1Rt(); + eLf0.setId(idLf0); + eLf0.setFirstName("firstName " + idLf0); + eLf0.setUniRight(eRt0); + eRt0.setId(idRt0); + eRt0.setLastName("lastName " + idRt0); + LSE1x1LfLzy eLf1 = new LSE1x1LfLzy(); + LSE1x1Rt eRt1 = new LSE1x1Rt(); + eLf1.setId(idLf1); + eLf1.setFirstName("firstName " + idLf1); + eLf1.setUniRight(eRt1); + eRt1.setId(idRt1); + eRt1.setLastName("lastName " + idRt1); + + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(eLf0); + em.persist(eRt0); + em.persist(eLf1); + em.persist(eRt1); + em.getTransaction().commit(); + } finally { + em = null; + eLf0 = eLf1 = null; + eRt0 = eRt1 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + + commonLockTest(testName, LSE1x1LfLzy.class, idLf0, extended, + "SELECT c FROM LSE1x1LfLzy c WHERE c.firstName LIKE :firstName", "findLSE1x1LfLzy" + scope, + new AssertCallback() { + public void findNoLockDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSE1x1LfLzy t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 1111101] + assertLockTestSQLs(Select + tableLfName + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName FROM LSE1x1LfLzy t0 WHERE t0.id = ? + // [params=(int) 1111101] + case derby: + // SELECT t0.version, t0.firstName FROM LSE1x1LfLzy t0 WHERE t0.id = ? + // [params=(int) 1111101] + default: + assertLockTestSQLs(Select + tableLfName + Where + NoForUpdate); + } + } + + public void findPessimisticForcIncDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSE1x1LfLzy t0 WHERE t0.id = ? + // optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS + // [params=(int) 1111102] + // SELECT t0.version FROM LSE1x1LfLzy t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1111102] + assertLockTestSQLs(Select + tableLfName + Where + DB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName FROM LSE1x1LfLzy t0 WHERE t0.id = ? + // FOR UPDATE [params=(int) 1111102] + // SELECT t0.version FROM LSE1x1LfLzy t0 WHERE t0.id = ? FOR UPDATE [params=(int) 1111102] + case derby: + // SELECT t0.version, t0.firstName FROM LSE1x1LfLzy t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 1111102] + // SELECT t0.version FROM LSE1x1LfLzy t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 1111102] + default: + assertLockTestSQLs(Select + tableLfName + Where + ForUpdate); + } + } + + public void queryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1x1LfLzy t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%1111101] + // SELECT t0.version FROM LSE1x1LfLzy t0 WHERE t0.id = ? [params=(int) 1111101] + assertLockTestSQLs(Select + tableLfName + Where + DB2Lock); + break; + case oracle: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1x1LfLzy t0 WHERE (t0.firstName LIKE ?) + // FOR UPDATE [params=(String) firstName%1111101] + // SELECT t0.version FROM LSE1x1LfLzy t0 WHERE t0.id = ? [params=(int) 1111101] + case derby: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1x1LfLzy t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR + // [params=(String) firstName%1111101] + // SELECT t0.version FROM LSE1x1LfLzy t0 WHERE t0.id = ? [params=(int) 1111101] + default: + assertLockTestSQLs(Select + tableLfName + Where + ForUpdate); + } + } + + public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSE1x1LfLzy t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 1111102] + assertLockTestSQLs(Select + tableLfName + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName FROM LSE1x1LfLzy t0 WHERE t0.id = ? + // [params=(int) 1111102] + case derby: + // SELECT t0.version, t0.firstName FROM LSE1x1LfLzy t0 WHERE t0.id = ? + // [params=(int) 1111102] + default: + assertLockTestSQLs(Select + tableLfName + Where + NoForUpdate); + } + } + + public void namedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1x1LfLzy t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%1111101] + // SELECT t0.version FROM LSE1x1LfLzy t0 WHERE t0.id = ? [params=(int) 1111101] + assertLockTestSQLs(Select + tableLfName + Where + DB2Lock); + break; + case oracle: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1x1LfLzy t0 WHERE (t0.firstName LIKE ?) + // FOR UPDATE [params=(String) firstName%1111101] + // SELECT t0.version FROM LSE1x1LfLzy t0 WHERE t0.id = ? [params=(int) 1111101] + case derby: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1x1LfLzy t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR + // [params=(String) firstName%1111101] + // SELECT t0.version FROM LSE1x1LfLzy t0 WHERE t0.id = ? [params=(int) 1111101] + default: + assertLockTestSQLs(Select + tableLfName + Where + ForUpdate); + } + } + + public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSE1x1LfLzy t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 1111102] + assertLockTestSQLs(Select + tableLfName + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName FROM LSE1x1LfLzy t0 WHERE t0.id = ? + // [params=(int) 1111102] + case derby: + // SELECT t0.version, t0.firstName FROM LSE1x1LfLzy t0 WHERE t0.id = ? + // [params=(int) 1111102] + default: + assertLockTestSQLs(Select + tableLfName + Where + NoForUpdate); + } + } + }); + } + + public void testNormalUni1x1JTLock() { + common1x1JTLock("testNormalUni1x1JTLock", 1112201, false); + } + + public void testExtendedUni1x1JTLock() { + common1x1JTLock("testExtendedUni1x1JTLock", 1112211, true); + } + + private void common1x1JTLock(String testName, int idLf0, boolean extended) { + final String tableLfName = "LSE1x1LfJT"; + final String tableJTName = "Uni1x1LfJT_Uni1x1RT"; + final String tableRtName = "LSE1x1Rt"; + final String joinTables = tableLfName + ".*JOIN.*" + tableJTName + ".*JOIN.*" + tableRtName; + + getLog().info("** " + testName + "()"); + String scope = extended ? "Extended" : "Normal"; + int idRt0 = idLf0 + 10000; // right table + int idLf1 = idLf0 + 1; + int idRt1 = idRt0 + 1; + + // create test entity. + LSE1x1LfJT eLf0 = new LSE1x1LfJT(); + LSE1x1Rt eRt0 = new LSE1x1Rt(); + eLf0.setId(idLf0); + eLf0.setFirstName("firstName " + idLf0); + eLf0.setUniRightJT(eRt0); + eRt0.setId(idRt0); + eRt0.setLastName("lastName " + idRt0); + LSE1x1LfJT eLf1 = new LSE1x1LfJT(); + LSE1x1Rt eRt1 = new LSE1x1Rt(); + eLf1.setId(idLf1); + eLf1.setFirstName("firstName " + idLf1); + eLf1.setUniRightJT(eRt1); + eRt1.setId(idRt1); + eRt1.setLastName("lastName " + idRt1); + + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(eLf0); + em.persist(eRt0); + em.persist(eLf1); + em.persist(eRt1); + em.getTransaction().commit(); + } finally { + em = null; + eLf0 = eLf1 = null; + eRt0 = eRt1 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + + commonLockTest(testName, LSE1x1LfJT.class, idLf0, extended, + "SELECT c FROM LSE1x1LfJT c WHERE c.firstName LIKE :firstName", "findLSE1x1LfJT" + scope, + new AssertCallback() { + public void findNoLockDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t2.id, t2.version, t2.lastName FROM LSE1x1LfJT t0 + // INNER JOIN Uni1x1LfJT_Uni1x1RT t1 ON t0.id = t1.LSE1X1LFJT_ID + // LEFT OUTER JOIN LSE1x1Rt t2 ON t1.UNIRIGHTJT_ID = t2.id WHERE t0.id = ? + // optimize for 1 row [params=(int) 1112201] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t2.id, t2.version, t2.lastName + // FROM LSE1x1LfJT t0, Uni1x1LfJT_Uni1x1RT t1, LSE1x1Rt t2 + // WHERE t0.id = ? AND t0.id = t1.LSE1X1LFJT_ID AND t1.UNIRIGHTJT_ID = t2.id(+) + // [params=(int) 1112201] + assertLockTestSQLs(Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + "\\(\\+\\).*" + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t2.id, t2.version, t2.lastName FROM LSE1x1LfJT t0 + // INNER JOIN Uni1x1LfJT_Uni1x1RT t1 ON t0.id = t1.LSE1X1LFJT_ID + // LEFT OUTER JOIN LSE1x1Rt t2 ON t1.UNIRIGHTJT_ID = t2.id WHERE t0.id = ? + // [params=(int) 1112201] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + + public void findPessimisticForcIncDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t2.id, t2.version, t2.lastName FROM LSE1x1LfJT t0 + // INNER JOIN Uni1x1LfJT_Uni1x1RT t1 ON t0.id = t1.LSE1X1LFJT_ID + // LEFT OUTER JOIN LSE1x1Rt t2 ON t1.UNIRIGHTJT_ID = t2.id WHERE t0.id = ? + // optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1112202] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1122202] + // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1112202] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + break; + case oracle: // TODO: If jpa2, DO NOT lock LSE1x1RT using "FOR UDPATE OF col" + // SELECT t0.version, t0.firstName, t2.id, t2.version, t2.lastName + // FROM LSE1x1LfJT t0, Uni1x1LfJT_Uni1x1RT t1, LSE1x1Rt t2 + // WHERE t0.id = ? AND t0.id = t1.LSE1X1LFJT_ID AND t1.UNIRIGHTJT_ID = t2.id(+) + // FOR UPDATE [params=(int) 1112202] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE [params=(int) 1122202] + // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? FOR UPDATE [params=(int) 1112202] + assertLockTestSQLs(Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + "\\(\\+\\).*" + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock, if jpa2/extended scope, LOCK Uni1x1LfJT_Uni1x1RT + // DO NOT lock LSE1x1Rt + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.version, t0.firstName, t2.id, t2.version, t2.lastName FROM LSE1x1LfJT t0 + // INNER JOIN Uni1x1LfJT_Uni1x1RT t1 ON t0.id = t1.LSE1X1LFJT_ID + // LEFT OUTER JOIN LSE1x1Rt t2 ON t1.UNIRIGHTJT_ID = t2.id WHERE t0.id = ? + // [params=(int) 1112202] + // SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1122202] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1122202] + // SELECT t0.id FROM LSE1x1LfJT t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1112202] + // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1112202] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + tableLfName + ".*" + Where + ForUpdate, + Select + tableRtName + ".*" + Where + ForUpdate + ); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void queryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName, t2.id, t2.version, t2.lastName FROM LSE1x1LfJT t0 + // INNER JOIN Uni1x1LfJT_Uni1x1RT t1 ON t0.id = t1.LSE1X1LFJT_ID + // LEFT OUTER JOIN LSE1x1Rt t2 ON t1.UNIRIGHTJT_ID = t2.id + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%1112201] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1122201] + // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? [params=(int) 1112201] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + break; + case oracle: // TODO: If jpa2, DO NOT lock LSE1x1RT using "FOR UDPATE OF col" + // SELECT t0.id, t0.version, t0.firstName, t2.id, t2.version, t2.lastName + // FROM LSE1x1LfJT t0, Uni1x1LfJT_Uni1x1RT t1, LSE1x1Rt t2 + // WHERE (t0.firstName LIKE ?) AND t0.id = t1.LSE1X1LFJT_ID + // AND t1.UNIRIGHTJT_ID = t2.id(+) FOR UPDATE [params=(String) firstName%1112201] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1122201] + // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? [params=(int) 1112201] + assertLockTestSQLs(Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + "\\(\\+\\).*" + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock, if jpa2/extended scope, LOCK Uni1x1LfJT_Uni1x1RT + // DO NOT lock LSE1x1Rt + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName, t2.id, t2.version, t2.lastName FROM LSE1x1LfJT t0 + // INNER JOIN Uni1x1LfJT_Uni1x1RT t1 ON t0.id = t1.LSE1X1LFJT_ID + // LEFT OUTER JOIN LSE1x1Rt t2 ON t1.UNIRIGHTJT_ID = t2.id + // WHERE (t0.firstName LIKE ? ESCAPE '\') [params=(String) firstName%1112201] + // SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1122201] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1122201] + // SELECT t0.id FROM LSE1x1LfJT t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1112201] + // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? [params=(int) 1112201] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + tableLfName + ".*" + Where + ForUpdate, + Select + tableRtName + ".*" + Where + ForUpdate + ); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t2.id, t2.version, t2.lastName FROM LSE1x1LfJT t0 + // INNER JOIN Uni1x1LfJT_Uni1x1RT t1 ON t0.id = t1.LSE1X1LFJT_ID + // LEFT OUTER JOIN LSE1x1Rt t2 ON t1.UNIRIGHTJT_ID = t2.id WHERE t0.id = ? + // optimize for 1 row [params=(int) 1112202] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t2.id, t2.version, t2.lastName + // FROM LSE1x1LfJT t0, Uni1x1LfJT_Uni1x1RT t1, LSE1x1Rt t2 + // WHERE t0.id = ? AND t0.id = t1.LSE1X1LFJT_ID AND t1.UNIRIGHTJT_ID = t2.id(+) + // [params=(int) 1112202] + assertLockTestSQLs(Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + "\\(\\+\\).*" + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t2.id, t2.version, t2.lastName FROM LSE1x1LfJT t0 + // INNER JOIN Uni1x1LfJT_Uni1x1RT t1 ON t0.id = t1.LSE1X1LFJT_ID + // LEFT OUTER JOIN LSE1x1Rt t2 ON t1.UNIRIGHTJT_ID = t2.id WHERE t0.id = ? + // [params=(int) 1112202] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + + public void namedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { + case db2: + //SELECT t0.id, t0.version, t0.firstName, t2.id, t2.version, t2.lastName FROM LSE1x1LfJT t0 + // INNER JOIN Uni1x1LfJT_Uni1x1RT t1 ON t0.id = t1.LSE1X1LFJT_ID + // LEFT OUTER JOIN LSE1x1Rt t2 ON t1.UNIRIGHTJT_ID = t2.id + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%1112201] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1122201] + // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? [params=(int) 1112201] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + break; + case oracle: // TODO: If jpa2, DO NOT lock LSE1x1RT using "FOR UDPATE OF col" + // SELECT t0.id, t0.version, t0.firstName, t2.id, t2.version, t2.lastName + // FROM LSE1x1LfJT t0, Uni1x1LfJT_Uni1x1RT t1, LSE1x1Rt t2 + // WHERE (t0.firstName LIKE ?) AND t0.id = t1.LSE1X1LFJT_ID + // AND t1.UNIRIGHTJT_ID = t2.id(+) FOR UPDATE [params=(String) firstName%1112201] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1122201] + // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? [params=(int) 1112201] + assertLockTestSQLs(Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + "\\(\\+\\).*" + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock, if jpa2/extended scope, LOCK Uni1x1LfJT_Uni1x1RT + // DO NOT lock LSE1x1Rt + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName, t2.id, t2.version, t2.lastName FROM LSE1x1LfJT t0 + // INNER JOIN Uni1x1LfJT_Uni1x1RT t1 ON t0.id = t1.LSE1X1LFJT_ID + // LEFT OUTER JOIN LSE1x1Rt t2 ON t1.UNIRIGHTJT_ID = t2.id + // WHERE (t0.firstName LIKE ? ESCAPE '\') [params=(String) firstName%1112201] + // SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1122201] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1122201] + // SELECT t0.id FROM LSE1x1LfJT t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1112201] + // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? [params=(int) 1112201] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + tableLfName + ".*" + Where + ForUpdate, + Select + tableRtName + ".*" + Where + ForUpdate + ); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t2.id, t2.version, t2.lastName FROM LSE1x1LfJT t0 + // INNER JOIN Uni1x1LfJT_Uni1x1RT t1 ON t0.id = t1.LSE1X1LFJT_ID + // LEFT OUTER JOIN LSE1x1Rt t2 ON t1.UNIRIGHTJT_ID = t2.id WHERE t0.id = ? + // optimize for 1 row [params=(int) 1112202] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t2.id, t2.version, t2.lastName + // FROM LSE1x1LfJT t0, Uni1x1LfJT_Uni1x1RT t1, LSE1x1Rt t2 + // WHERE t0.id = ? AND t0.id = t1.LSE1X1LFJT_ID AND t1.UNIRIGHTJT_ID = t2.id(+) + // [params=(int) 1112202] + assertLockTestSQLs(Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + "\\(\\+\\).*" + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t2.id, t2.version, t2.lastName FROM LSE1x1LfJT t0 + // INNER JOIN Uni1x1LfJT_Uni1x1RT t1 ON t0.id = t1.LSE1X1LFJT_ID + // LEFT OUTER JOIN LSE1x1Rt t2 ON t1.UNIRIGHTJT_ID = t2.id + // WHERE t0.id = ? [params=(int) 1112202] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + }); + } + + public void testNormalUni1x1JTLazyLock() { + common1x1JTLazyLock("testNormalUni1x1JTLazyLock", 1112101, false); + } + + public void testExtendedUni1x1JTLazyLock() { + common1x1JTLazyLock("testExtendedUni1x1JTLazyLock", 1112111, true); + } + + private void common1x1JTLazyLock(String testName, int idLf0, boolean extended) { + final String tableLfName = "LSE1x1LfJTLzy"; +// final String tableRtName = "LockSEUni1x1RT"; + getLog().info("** " + testName + "()"); + String scope = extended ? "Extended" : "Normal"; + int idRt0 = idLf0 + 10000; // right table + int idLf1 = idLf0 + 1; + int idRt1 = idRt0 + 1; + + // create test entity. + LSE1x1LfJTLzy eLf0 = new LSE1x1LfJTLzy(); + LSE1x1Rt eRt0 = new LSE1x1Rt(); + eLf0.setId(idLf0); + eLf0.setFirstName("firstName " + idLf0); + eLf0.setUniRightJT(eRt0); + eRt0.setId(idRt0); + eRt0.setLastName("lastName " + idRt0); + LSE1x1LfJTLzy eLf1 = new LSE1x1LfJTLzy(); + LSE1x1Rt eRt1 = new LSE1x1Rt(); + eLf1.setId(idLf1); + eLf1.setFirstName("firstName " + idLf1); + eLf1.setUniRightJT(eRt1); + eRt1.setId(idRt1); + eRt1.setLastName("lasttName " + idRt1); + + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(eLf0); + em.persist(eRt0); + em.persist(eLf1); + em.persist(eRt1); + em.getTransaction().commit(); + } finally { + em = null; + eLf0 = eLf1 = null; + eRt0 = eRt1 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + + commonLockTest(testName, LSE1x1LfJTLzy.class, idLf0, extended, + "SELECT c FROM LSE1x1LfJTLzy c WHERE c.firstName LIKE :firstName", "findLSE1x1LfJTLzy" + scope, + new AssertCallback() { + public void findNoLockDbSQL(EntityManager em) { + switch (getDBType(em)) { + case db2: + // SELECT t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 1112101] + assertLockTestSQLs(Select + tableLfName + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? + // [params=(int) 1112101] + case derby: + // SELECT t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? + // [params=(int) 1112101] + default: + assertLockTestSQLs(Select + tableLfName + Where + NoForUpdate); + } + } + + public void findPessimisticForcIncDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? + // optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS + // [params=(int) 1112102] + // SELECT t0.version FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1112102] + assertLockTestSQLs(Select + tableLfName + Where + DB2Lock); + break; + case derby: + // SELECT t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 1112102] + // SELECT t0.version FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 1112102] + case oracle: + // SELECT t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? FOR UPDATE + // [params=(int) 1112102] + // SELECT t0.version FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? FOR UPDATE [params=(int) 1112102] + default: + assertLockTestSQLs(Select + tableLfName + Where + ForUpdate); + } + } + + public void queryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%1112101] + // SELECT t0.version FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? [params=(int) 1112101] + assertLockTestSQLs(Select + tableLfName + Where + DB2Lock); + break; + case derby: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR + // [params=(String) firstName%1112101] + // SELECT t0.version FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? [params=(int) 1112101] + case oracle: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 + // WHERE (t0.firstName LIKE ?) FOR UPDATE [params=(String) firstName%1112101] + // SELECT t0.version FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? [params=(int) 1112101] + default: + assertLockTestSQLs(Select + tableLfName + Where + ForUpdate); + } + } + + public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 1112102] + assertLockTestSQLs(Select + tableLfName + Where + NoDB2Lock); + break; + case derby: + // SELECT t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? + // [params=(int) 1112102] + case oracle: + // SELECT t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? + // [params=(int) 1112102] + default: + assertLockTestSQLs(Select + tableLfName + Where + NoForUpdate); + } + } + + public void namedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%1112101] + // SELECT t0.version FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? [params=(int) 1112101] + assertLockTestSQLs(Select + tableLfName + Where + DB2Lock); + break; + case derby: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR + // [params=(String) firstName%1112101] + // SELECT t0.version FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? [params=(int) 1112101] + case oracle: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 + // WHERE (t0.firstName LIKE ?) FOR UPDATE [params=(String) firstName%1112101] + // SELECT t0.version FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? [params=(int) 1112101] + default: + assertLockTestSQLs(Select + tableLfName + Where + ForUpdate); + } + } + + public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 1112102] + assertLockTestSQLs(Select + tableLfName + Where + NoDB2Lock); + break; + case derby: + // SELECT t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? + // [params=(int) 1112102] + case oracle: + // SELECT t0.version, t0.firstName FROM LSE1x1LfJTLzy t0 WHERE t0.id = ? + // [params=(int) 1112102] + default: + assertLockTestSQLs(Select + tableLfName + Where + NoForUpdate); + } + } + }); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/Test1xmLockScope.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/Test1xmLockScope.java new file mode 100644 index 000000000..00b54e34d --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/Test1xmLockScope.java @@ -0,0 +1,1126 @@ +/* + * 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.lock.extended; + +import javax.persistence.EntityManager; + +/** + * LockScopeTestCase subclass to test entity with: + * - Uni-1xm - lazy fetch (default) + * - Uni-1xm - eager fetch + * - Uni-1xm use join table - lazy fetch (default) + * - Uni-1xm use join table - eager fetch + */ +public class Test1xmLockScope extends LockScopeTestCase { + + public void setUp() { + setUp(LSE1xmLf.class + , LSE1xmLfEgr.class + , LSE1xmLfJT.class + , LSE1xmLfJTEgr.class + , LSE1xmRt.class + , "openjpa.LockManager", "mixed", + "openjpa.jdbc.SynchronizeMappings", "buildSchema(ForeignKeys=true)" + ); + commonSetUp(LSE1xmLf.class + , LSE1xmLfEgr.class + , LSE1xmLfJT.class + , LSE1xmLfJTEgr.class + , LSE1xmRt.class + ); + } + + public void testNormalUni1xmLock() { + common1xmLock("testNormalUni1xmLock", 2111101, false); + } + + public void testExtendedUni1xmLock() { + common1xmLock("testExtendedUni1xmLock", 2111111, true); + } + + private void common1xmLock(String testName, int idLf0, boolean extended) { + final String tableLfName = "LSE1xmLf"; +// final String tableRtName = "LSE1xmRt"; +// final String joinTables = tableLfName + ".*JOIN.*" + tableRtName; + getLog().info("** " + testName + "()"); + String scope = extended ? "Extended" : "Normal"; + int idRt00 = idLf0 + 10000; // right table + int idRt01 = idRt00 + 1; + int idLf1 = idLf0 + 1; + int idRt10 = idLf1 + 10000 + 1; // right table + int idRt11 = idRt10 + 1; + // create test entity. + LSE1xmLf eLf0 = new LSE1xmLf(); + LSE1xmRt eRt00 = new LSE1xmRt(); + LSE1xmRt eRt01 = new LSE1xmRt(); + eLf0.setId(idLf0); + eLf0.setFirstName("firstName " + idLf0); + eLf0.addUnitRight(eRt00); + eLf0.addUnitRight(eRt01); + eRt00.setId(idRt00); + eRt00.setLastName("lastName " + idRt00); + eRt01.setId(idRt01); + eRt01.setLastName("lastName " + idRt01); + + LSE1xmLf eLf1 = new LSE1xmLf(); + LSE1xmRt eRt10 = new LSE1xmRt(); + LSE1xmRt eRt11 = new LSE1xmRt(); + eLf1.setId(idLf1); + eLf1.setFirstName("firstName " + idLf1); + eLf1.addUnitRight(eRt10); + eLf1.addUnitRight(eRt11); + eRt10.setId(idRt10); + eRt10.setLastName("lastName " + idRt10); + eRt11.setId(idRt11); + eRt11.setLastName("lastName " + idRt11); + + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(eRt00); + em.persist(eRt01); + em.persist(eLf0); + em.persist(eRt10); + em.persist(eRt11); + em.persist(eLf1); + em.getTransaction().commit(); + } finally { + em = null; + eLf0 = eLf1 = null; + eRt00 = eRt01 = eRt10 = eRt11 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + + commonLockTest(testName, LSE1xmLf.class, idLf0, extended, + "SELECT c FROM LSE1xmLf c WHERE c.firstName LIKE :firstName", "findLSE1xmLf" + scope, + new AssertCallback() { + public void findNoLockDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSE1xmLf t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 2111101] + assertLockTestSQLs(Select + tableLfName + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName FROM LSE1xmLf t0 WHERE t0.id = ? [params=(int) 2111101] + case derby: + // SELECT t0.version, t0.firstName FROM LSE1xmLf t0 WHERE t0.id = ? [params=(int) 2111101] + default: + assertLockTestSQLs(Select + tableLfName + Where + NoForUpdate); + } + } + + public void findPessimisticForcIncDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSE1xmLf t0 WHERE t0.id = ? + // optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS + // [params=(int) 2111102] + // SELECT t0.version FROM LSE1xmLf t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 2111102] + assertLockTestSQLs(Select + tableLfName + Where + DB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName FROM LSE1xmLf t0 WHERE t0.id = ? FOR UPDATE + // [params=(int) 2111102] + // SELECT t0.version FROM LSE1xmLf t0 WHERE t0.id = ? FOR UPDATE [params=(int) 2111102] + case derby: + // SELECT t0.version, t0.firstName FROM LSE1xmLf t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 2111102] + // SELECT t0.version FROM LSE1xmLf t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 2111102] + default: + assertLockTestSQLs(Select + tableLfName + Where + ForUpdate); + } + } + + public void queryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLf t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%2111101] + // SELECT t0.version FROM LSE1xmLf t0 WHERE t0.id = ? [params=(int) 2111101] + assertLockTestSQLs(Select + tableLfName + Where + DB2Lock); + break; + case oracle: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLf t0 WHERE (t0.firstName LIKE ?) + // FOR UPDATE [params=(String) firstName%2111101] + // SELECT t0.version FROM LSE1xmLf t0 WHERE t0.id = ? [params=(int) 2111101] + case derby: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLf t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR + // [params=(String) firstName%2111101] + // SELECT t0.version FROM LSE1xmLf t0 WHERE t0.id = ? [params=(int) 2111101] + default: + assertLockTestSQLs(Select + tableLfName + Where + ForUpdate); + } + } + + public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSE1xmLf t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 2111102] + assertLockTestSQLs(Select + tableLfName + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName FROM LSE1xmLf t0 WHERE t0.id = ? [params=(int) 2111102] + case derby: + // SELECT t0.version, t0.firstName FROM LSE1xmLf t0 WHERE t0.id = ? [params=(int) 2111102] + default: + assertLockTestSQLs(Select + tableLfName + Where + NoForUpdate); + } + } + + public void namedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLf t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%2111101] + // SELECT t0.version FROM LSE1xmLf t0 WHERE t0.id = ? [params=(int) 2111101] + assertLockTestSQLs(Select + tableLfName + Where + DB2Lock); + break; + case oracle: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLf t0 WHERE (t0.firstName LIKE ?) + // FOR UPDATE [params=(String) firstName%2111101] + // SELECT t0.version FROM LSE1xmLf t0 WHERE t0.id = ? [params=(int) 2111101] + case derby: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLf t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR + // [params=(String) firstName%2111101] + // SELECT t0.version FROM LSE1xmLf t0 WHERE t0.id = ? [params=(int) 2111101] + default: + assertLockTestSQLs(Select + tableLfName + Where + ForUpdate); + } + } + + public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSE1xmLf t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 2111102] + assertLockTestSQLs(Select + tableLfName + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName FROM LSE1xmLf t0 WHERE t0.id = ? [params=(int) 2111102] + case derby: + // SELECT t0.version, t0.firstName FROM LSE1xmLf t0 WHERE t0.id = ? [params=(int) 2111102] + default: + assertLockTestSQLs(Select + tableLfName + Where + NoForUpdate); + } + } + }); + } + + public void testNormalUni1xmEagerLock() { + common1xmEagerLock("testNormalUni1xmEagerLock", 2111201, false); + } + + public void testExtendedUni1xmEagerLock() { + common1xmEagerLock("testExtendedUni1xmEagerLock", 2111211, true); + } + + private void common1xmEagerLock(String testName, int idLf0, boolean extended) { + final String tableLfName = "LSE1xmLfEgr"; + final String tableJTName = "LSE1xmLfEgr_LSE1xmRt"; + final String tableRtName = "LSE1xmRt"; + final String joinTables = tableLfName + ".*JOIN.*" + tableJTName + ".*JOIN.*" + tableRtName; + getLog().info("** " + testName + "()"); + String scope = extended ? "Extended" : "Normal"; + int idRt00 = idLf0 + 10000; // right table + int idRt01 = idRt00 + 1; + int idLf1 = idLf0 + 1; + int idRt10 = idLf1 + 10000 + 1; // right table + int idRt11 = idRt10 + 1; + // create test entity. + LSE1xmLfEgr eLf0 = new LSE1xmLfEgr(); + LSE1xmRt eRt00 = new LSE1xmRt(); + LSE1xmRt eRt01 = new LSE1xmRt(); + eLf0.setId(idLf0); + eLf0.setFirstName("firstName " + idLf0); + eLf0.addUnitRight(eRt00); + eLf0.addUnitRight(eRt01); + eRt00.setId(idRt00); + eRt00.setLastName("lastName " + idRt00); + eRt01.setId(idRt01); + eRt01.setLastName("lastName " + idRt01); + + LSE1xmLfEgr eLf1 = new LSE1xmLfEgr(); + LSE1xmRt eRt10 = new LSE1xmRt(); + LSE1xmRt eRt11 = new LSE1xmRt(); + eLf1.setId(idLf1); + eLf1.setFirstName("firstName " + idLf1); + eLf1.addUnitRight(eRt10); + eLf1.addUnitRight(eRt11); + eRt10.setId(idRt10); + eRt10.setLastName("lastName " + idRt10); + eRt11.setId(idRt11); + eRt11.setLastName("lastName " + idRt11); + + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(eRt00); + em.persist(eRt01); + em.persist(eLf0); + em.persist(eRt10); + em.persist(eRt11); + em.persist(eLf1); + em.getTransaction().commit(); + } finally { + em = null; + eLf0 = eLf1 = null; + eRt00 = eRt01 = eRt10 = eRt11 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + + commonLockTest(testName, LSE1xmLfEgr.class, idLf0, extended, + "SELECT c FROM LSE1xmLfEgr c WHERE c.firstName LIKE :firstName", "findLSE1xmLfEgr" + + scope, + new AssertCallback() { + public void findNoLockDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfEgr t0 LEFT OUTER JOIN LSE1xmLfEgr_LSE1xmRt t1 + // ON t0.id = t1.LSE1XMLFEGR_ID LEFT OUTER JOIN LSE1xmRt t2 + // ON t1.UNIRIGHT_ID = t2.id WHERE t0.id = ? [params=(int) 2111201] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfEgr t0, LSE1xmLfEgr_LSE1xmRt t1, LSE1xmRt t2 + // WHERE t0.id = ? AND t0.id = t1.LSE1XMLFEGR_ID(+) AND t1.UNIRIGHT_ID = t2.id(+) + // [params=(int) 2111201] + assertLockTestSQLs(Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + "\\(\\+\\).*" + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfEgr t0 LEFT OUTER JOIN LSE1xmLfEgr_LSE1xmRt t1 + // ON t0.id = t1.LSE1XMLFEGR_ID LEFT OUTER JOIN LSE1xmRt t2 ON t1.UNIRIGHT_ID = t2.id + // WHERE t0.id = ? [params=(int) 2111201] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + + public void findPessimisticForcIncDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfEgr t0 LEFT OUTER JOIN LSE1xmLfEgr_LSE1xmRt t1 + // ON t0.id = t1.LSE1XMLFEGR_ID LEFT OUTER JOIN LSE1xmRt t2 + // ON t1.UNIRIGHT_ID = t2.id WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 2111202] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 2121204] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 2121203] + // SELECT t0.version FROM LSE1xmLfEgr t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 2111202] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + break; + case oracle: // TODO: if jpa2, DO NOT lock LSE1xmRT using "FOR UPDATE OF col" + // SELECT t0.version, t0.firstName, t1.LSE1XMLFEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfEgr t0, LSE1xmLfEgr_LSE1xmRt t1, LSE1xmRt t2 + // WHERE t0.id = ? AND t0.id = t1.LSE1XMLFEGR_ID(+) AND t1.UNIRIGHT_ID = t2.id(+) + // FOR UPDATE [params=(int) 2111202] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE [params=(int) 2121203] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE [params=(int) 2121204] + // SELECT t0.version FROM LSE1xmLfEgr t0 WHERE t0.id = ? FOR UPDATE [params=(int) 2111202] + assertLockTestSQLs(Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + "\\(\\+\\).*" + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock. If jpa2, DO NOT lock LSE1xmRt, + // if jpa2/extended, LOCK LSE1xmLfEgr_LSE1xmRt + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.version, t0.firstName, t1.LSE1XMLFEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfEgr t0 LEFT OUTER JOIN LSE1xmLfEgr_LSE1xmRt t1 + // ON t0.id = t1.LSE1XMLFEGR_ID LEFT OUTER JOIN LSE1xmRt t2 ON t1.UNIRIGHT_ID = t2.id + // WHERE t0.id = ? [params=(int) 2111202] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 2121203] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 2121203] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 2121204] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 2121204] + // SELECT t0.id FROM LSE1xmLfEgr t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 2111202] + // SELECT t0.version FROM LSE1xmLfEgr t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 2111202] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + tableLfName + Where + ForUpdate, + Select + tableRtName + Where + ForUpdate, + Select + tableRtName + Where + ForUpdate + ); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void queryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: //TODO: **Non-atomic lock. if jpa2, DO NOT lock LSE1xmRt + // if jpa2/extended, LOCK LSE1xmLfEgr_LSE1xmRt + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfEgr t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%2111201] + // SELECT t0.id, t2.id, t2.version, t2.lastName FROM LSE1xmLfEgr t0 + // INNER JOIN LSE1xmLfEgr_LSE1xmRt t1 ON t0.id = t1.LSE1XMLFEGR_ID + // INNER JOIN LSE1xmRt t2 ON t1.UNIRIGHT_ID = t2.id + // WHERE (t0.firstName LIKE ? ESCAPE '\') ORDER BY t0.id ASC + // [params=(String) firstName%2111201] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(int) 2121201] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2121201] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(int) 2121202] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2121202] + // SELECT t0.version FROM LSE1xmLfEgr t0 WHERE t0.id = ? [params=(int) 2111201] + assertLockTestSQLs(Select + tableLfName + Where + DB2Lock, + Select + joinTables + Where + NoDB2Lock, + Select + tableRtName + Where + DB2Lock, + Select + tableRtName + Where + DB2Lock); + break; + case oracle: // TODO: if jpa2, DO NOT lock LSE1xmRT using "FOR UPDATE OF col" + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfEgr t0 WHERE (t0.firstName LIKE ?) + // FOR UPDATE [params=(String) firstName%2111201] + // SELECT t0.id, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfEgr t0, LSE1xmLfEgr_LSE1xmRt t1, LSE1xmRt t2 + // WHERE (t0.firstName LIKE ?) AND t0.id = t1.LSE1XMLFEGR_ID AND t1.UNIRIGHT_ID = t2.id + // ORDER BY t0.id ASC FOR UPDATE [params=(String) firstName%2111201] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2121202] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2121201] + // SELECT t0.version FROM LSE1xmLfEgr t0 WHERE t0.id = ? [params=(int) 2111201] + assertLockTestSQLs(Select + tableLfName + Where + ForUpdate, + Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock. If jpa2, DO NOT lock LSE1xmRt, + // if jpa2/extended, LOCK LSE1xmLfEgr_LSE1xmRt + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfEgr t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR + // [params=(String) firstName%2111201] + // SELECT t0.id, t2.id, t2.version, t2.lastName FROM LSE1xmLfEgr t0 + // INNER JOIN LSE1xmLfEgr_LSE1xmRt t1 ON t0.id = t1.LSE1XMLFEGR_ID + // INNER JOIN LSE1xmRt t2 ON t1.UNIRIGHT_ID = t2.id + // WHERE (t0.firstName LIKE ? ESCAPE '\') ORDER BY t0.id ASC + // [params=(String) firstName%2111201] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 2121202] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2121202] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 2121201] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2121201] + // SELECT t0.version FROM LSE1xmLfEgr t0 WHERE t0.id = ? [params=(int) 2111201] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + tableLfName + Where + ForUpdate, + Select + tableRtName + Where + ForUpdate, + Select + tableRtName + Where + ForUpdate + ); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfEgr t0 LEFT OUTER JOIN LSE1xmLfEgr_LSE1xmRt t1 + // ON t0.id = t1.LSE1XMLFEGR_ID LEFT OUTER JOIN LSE1xmRt t2 + // ON t1.UNIRIGHT_ID = t2.id WHERE t0.id = ? [params=(int) 2111202] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfEgr t0, LSE1xmLfEgr_LSE1xmRt t1, LSE1xmRt t2 + // WHERE t0.id = ? AND t0.id = t1.LSE1XMLFEGR_ID(+) AND t1.UNIRIGHT_ID = t2.id(+) + // [params=(int) 2111202] + assertLockTestSQLs(Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + "\\(\\+\\).*" + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfEgr t0 LEFT OUTER JOIN LSE1xmLfEgr_LSE1xmRt t1 + // ON t0.id = t1.LSE1XMLFEGR_ID LEFT OUTER JOIN LSE1xmRt t2 + // ON t1.UNIRIGHT_ID = t2.id WHERE t0.id = ? [params=(int) 2111202] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + + public void namedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: //TODO: **Non-atomic lock. if jpa2, DO NOT lock LSE1xmRt + // if jpa2/extended, LOCK LSE1xmLfEgr_LSE1xmRt + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfEgr t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%2111201] + // SELECT t0.id, t2.id, t2.version, t2.lastName FROM LSE1xmLfEgr t0 + // INNER JOIN LSE1xmLfEgr_LSE1xmRt t1 ON t0.id = t1.LSE1XMLFEGR_ID + // INNER JOIN LSE1xmRt t2 ON t1.UNIRIGHT_ID = t2.id + // WHERE (t0.firstName LIKE ? ESCAPE '\') ORDER BY t0.id ASC + // [params=(String) firstName%2111201] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(int) 2121201] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2121201] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(int) 2121202] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2121202] + // SELECT t0.version FROM LSE1xmLfEgr t0 WHERE t0.id = ? [params=(int) 2111201] + assertLockTestSQLs(Select + tableLfName + Where + DB2Lock, + Select + joinTables + Where + NoDB2Lock, + Select + tableRtName + Where + DB2Lock, + Select + tableRtName + Where + DB2Lock); + break; + case oracle: // TODO: if jpa2, DO NOT lock LSE1xmRT using "FOR UPDATE OF col" + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfEgr t0 WHERE (t0.firstName LIKE ?) + // FOR UPDATE [params=(String) firstName%2111201] + // SELECT t0.id, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfEgr t0, LSE1xmLfEgr_LSE1xmRt t1, LSE1xmRt t2 + // WHERE (t0.firstName LIKE ?) AND t0.id = t1.LSE1XMLFEGR_ID AND t1.UNIRIGHT_ID = t2.id + // ORDER BY t0.id ASC FOR UPDATE [params=(String) firstName%2111201] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2121202] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2121201] + // SELECT t0.version FROM LSE1xmLfEgr t0 WHERE t0.id = ? [params=(int) 2111201] + assertLockTestSQLs(Select + tableLfName + Where + ForUpdate, + Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock. If jpa2, DO NOT lock LSE1xmRt, + // if jpa2/extended, LOCK LSE1xmLfEgr_LSE1xmRt + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfEgr t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR + // [params=(String) firstName%2111201] + // SELECT t0.id, t2.id, t2.version, t2.lastName FROM LSE1xmLfEgr t0 + // INNER JOIN LSE1xmLfEgr_LSE1xmRt t1 ON t0.id = t1.LSE1XMLFEGR_ID + // INNER JOIN LSE1xmRt t2 ON t1.UNIRIGHT_ID = t2.id + // WHERE (t0.firstName LIKE ? ESCAPE '\') ORDER BY t0.id ASC + // [params=(String) firstName%2111201] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 2121202] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2121202] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 2121201] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2121201] + // SELECT t0.version FROM LSE1xmLfEgr t0 WHERE t0.id = ? [params=(int) 2111201] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + tableLfName + Where + ForUpdate, + Select + tableRtName + Where + ForUpdate, + Select + tableRtName + Where + ForUpdate + ); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfEgr t0 LEFT OUTER JOIN LSE1xmLfEgr_LSE1xmRt t1 + // ON t0.id = t1.LSE1XMLFEGR_ID LEFT OUTER JOIN LSE1xmRt t2 + // ON t1.UNIRIGHT_ID = t2.id WHERE t0.id = ? [params=(int) 2111202] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfEgr t0, LSE1xmLfEgr_LSE1xmRt t1, LSE1xmRt t2 + // WHERE t0.id = ? AND t0.id = t1.LSE1XMLFEGR_ID(+) AND t1.UNIRIGHT_ID = t2.id(+) + // [params=(int) 2111202] + assertLockTestSQLs(Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + "\\(\\+\\).*" + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfEgr t0 LEFT OUTER JOIN LSE1xmLfEgr_LSE1xmRt t1 + // ON t0.id = t1.LSE1XMLFEGR_ID LEFT OUTER JOIN LSE1xmRt t2 + // ON t1.UNIRIGHT_ID = t2.id WHERE t0.id = ? [params=(int) 2111202] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + }); + } + + public void testNormalUni1xmJTLock() { + common1xmJTLock("testNormalUni1xmJTLock", 2112101, false); + } + + public void testExtendedUni1xmJTLock() { + common1xmJTLock("testExtendedUni1xmJTLock", 2112111, true); + } + + private void common1xmJTLock(String testName, int idLf0, boolean extended) { + final String tableLfName = "LSE1xmLfJT"; +// final String tableRtName = "LSE1xmRt"; +// final String joinTables = tableLfName + ".*JOIN.*" + tableRtName; + getLog().info("** " + testName + "()"); + String scope = extended ? "Extended" : "Normal"; + int idRt00 = idLf0 + 10000; // right table + int idRt01 = idRt00 + 1; + int idLf1 = idLf0 + 1; + int idRt10 = idLf1 + 10000 + 1; // right table + int idRt11 = idRt10 + 1; + // create test entity. + LSE1xmLfJT eLf0 = new LSE1xmLfJT(); + LSE1xmRt eRt00 = new LSE1xmRt(); + LSE1xmRt eRt01 = new LSE1xmRt(); + eLf0.setId(idLf0); + eLf0.setFirstName("firstName " + idLf0); + eLf0.addUnitRight(eRt00); + eLf0.addUnitRight(eRt01); + eRt00.setId(idRt00); + eRt00.setLastName("lastName " + idRt00); + eRt01.setId(idRt01); + eRt01.setLastName("lastName " + idRt01); + + LSE1xmLfJT eLf1 = new LSE1xmLfJT(); + LSE1xmRt eRt10 = new LSE1xmRt(); + LSE1xmRt eRt11 = new LSE1xmRt(); + eLf1.setId(idLf1); + eLf1.setFirstName("firstName " + idLf1); + eLf1.addUnitRight(eRt10); + eLf1.addUnitRight(eRt11); + eRt10.setId(idRt10); + eRt10.setLastName("lastName " + idRt10); + eRt11.setId(idRt11); + eRt11.setLastName("lastName " + idRt11); + + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(eRt00); + em.persist(eRt01); + em.persist(eLf0); + em.persist(eRt10); + em.persist(eRt11); + em.persist(eLf1); + em.getTransaction().commit(); + } finally { + em = null; + eLf0 = eLf1 = null; + eRt00 = eRt01 = eRt10 = eRt11 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + + commonLockTest(testName, LSE1xmLfJT.class, idLf0, extended, + "SELECT c FROM LSE1xmLfJT c WHERE c.firstName LIKE :firstName", "findLSE1xmLfJT" + scope, + new AssertCallback() { + public void findNoLockDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSE1xmLfJT t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 2112101] + assertLockTestSQLs(Select + tableLfName + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName FROM LSE1xmLfJT t0 WHERE t0.id = ? [params=(int) 2112101] + case derby: + // SELECT t0.version, t0.firstName FROM LSE1xmLfJT t0 WHERE t0.id = ? [params=(int) 2112101] + default: + assertLockTestSQLs(Select + tableLfName + Where + NoForUpdate); + } + } + + public void findPessimisticForcIncDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSE1xmLfJT t0 WHERE t0.id = ? + // optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS + // [params=(int) 2112102] + // SELECT t0.version FROM LSE1xmLfJT t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 2112102] + assertLockTestSQLs(Select + tableLfName + Where + DB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName FROM LSE1xmLfJT t0 WHERE t0.id = ? FOR UPDATE + // [params=(int) 2112102] + // SELECT t0.version FROM LSE1xmLfJT t0 WHERE t0.id = ? FOR UPDATE [params=(int) 2112102] + case derby: + // SELECT t0.version, t0.firstName FROM LSE1xmLfJT t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 2112102] + // SELECT t0.version FROM LSE1xmLfJT t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 2112102] + default: + assertLockTestSQLs(Select + tableLfName + Where + ForUpdate); + } + } + + public void queryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfJT t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%2112101] + // SELECT t0.version FROM LSE1xmLfJT t0 WHERE t0.id = ? [params=(int) 2112101] + assertLockTestSQLs(Select + tableLfName + Where + DB2Lock); + break; + case oracle: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfJT t0 WHERE (t0.firstName LIKE ?) + // FOR UPDATE [params=(String) firstName%2112101] + // SELECT t0.version FROM LSE1xmLfJT t0 WHERE t0.id = ? [params=(int) 2112101] + case derby: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfJT t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR + // [params=(String) firstName%2112101] + // SELECT t0.version FROM LSE1xmLfJT t0 WHERE t0.id = ? [params=(int) 2112101] + default: + assertLockTestSQLs(Select + tableLfName + Where + ForUpdate); + } + } + + public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSE1xmLfJT t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 2112102] + assertLockTestSQLs(Select + tableLfName + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName FROM LSE1xmLfJT t0 WHERE t0.id = ? [params=(int) 2112102] + case derby: + // SELECT t0.version, t0.firstName FROM LSE1xmLfJT t0 WHERE t0.id = ? [params=(int) 2112102] + default: + assertLockTestSQLs(Select + tableLfName + Where + NoForUpdate); + } + } + + public void namedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfJT t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%2112101] + // SELECT t0.version FROM LSE1xmLfJT t0 WHERE t0.id = ? [params=(int) 2112101] + assertLockTestSQLs(Select + tableLfName + Where + DB2Lock); + break; + case oracle: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfJT t0 WHERE (t0.firstName LIKE ?) + // FOR UPDATE [params=(String) firstName%2112101] + // SELECT t0.version FROM LSE1xmLfJT t0 WHERE t0.id = ? [params=(int) 2112101] + case derby: + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfJT t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR + // [params=(String) firstName%2112101] + // SELECT t0.version FROM LSE1xmLfJT t0 WHERE t0.id = ? [params=(int) 2112101] + default: + assertLockTestSQLs(Select + tableLfName + Where + ForUpdate); + } + } + + public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSE1xmLfJT t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 2112102] + assertLockTestSQLs(Select + tableLfName + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName FROM LSE1xmLfJT t0 WHERE t0.id = ? [params=(int) 2112102] + case derby: + // SELECT t0.version, t0.firstName FROM LSE1xmLfJT t0 WHERE t0.id = ? [params=(int) 2112102] + default: + assertLockTestSQLs(Select + tableLfName + Where + NoForUpdate); + } + } + }); + } + + public void testNormalUni1xmJTEagerLock() { + common1xmJTEagerLock("testNormalUni1xmJTEagerLock", 2112201, false); + } + + public void testExtendedUni1xmJTEagerLock() { + common1xmJTEagerLock("testExtendedUni1xmJTEagerLock", 2112211, true); + } + + private void common1xmJTEagerLock(String testName, int idLf0, boolean extended) { + final String tableLfName = "LSE1xmLfJTEgr"; + final String tableJTName = "LSE1xmLfJTEgr_LSE1xmRt"; + final String tableRtName = "LSE1xmRt"; + final String joinTables = tableLfName + ".*JOIN.*" + tableJTName + ".*JOIN.*" + tableRtName; + getLog().info("** " + testName + "()"); + String scope = extended ? "Extended" : "Normal"; + int idRt00 = idLf0 + 10000; // right table + int idRt01 = idRt00 + 1; + int idLf1 = idLf0 + 1; + int idRt10 = idLf1 + 10000 + 1; // right table + int idRt11 = idRt10 + 1; + // create test entity. + LSE1xmLfJTEgr eLf0 = new LSE1xmLfJTEgr(); + LSE1xmRt eRt00 = new LSE1xmRt(); + LSE1xmRt eRt01 = new LSE1xmRt(); + eLf0.setId(idLf0); + eLf0.setFirstName("firstName " + idLf0); + eLf0.addUnitRight(eRt00); + eLf0.addUnitRight(eRt01); + eRt00.setId(idRt00); + eRt00.setLastName("lastName " + idRt00); + eRt01.setId(idRt01); + eRt01.setLastName("lastName " + idRt01); + + LSE1xmLfJTEgr eLf1 = new LSE1xmLfJTEgr(); + LSE1xmRt eRt10 = new LSE1xmRt(); + LSE1xmRt eRt11 = new LSE1xmRt(); + eLf1.setId(idLf1); + eLf1.setFirstName("firstName " + idLf1); + eLf1.addUnitRight(eRt10); + eLf1.addUnitRight(eRt11); + eRt10.setId(idRt10); + eRt10.setLastName("lastName " + idRt10); + eRt11.setId(idRt11); + eRt11.setLastName("lastName " + idRt11); + + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(eRt00); + em.persist(eRt01); + em.persist(eLf0); + em.persist(eRt10); + em.persist(eRt11); + em.persist(eLf1); + em.getTransaction().commit(); + } finally { + em = null; + eLf0 = eLf1 = null; + eRt00 = eRt01 = eRt10 = eRt11 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + + commonLockTest(testName, LSE1xmLfJTEgr.class, idLf0, extended, + "SELECT c FROM LSE1xmLfJTEgr c WHERE c.firstName LIKE :firstName", "findLSE1xmLfJTEgr" + + scope, + new AssertCallback() { + public void findNoLockDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFJTEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfJTEgr t0 LEFT OUTER JOIN LSE1xmLfJTEgr_LSE1xmRt t1 + // ON t0.id = t1.LSE1XMLFJTEGR_ID LEFT OUTER JOIN LSE1xmRt t2 + // ON t1.UNIRIGHT_ID = t2.id WHERE t0.id = ? [params=(int) 2112201] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFJTEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfJTEgr t0, LSE1xmLfJTEgr_LSE1xmRt t1, LSE1xmRt t2 + // WHERE t0.id = ? AND t0.id = t1.LSE1XMLFJTEGR_ID(+) AND t1.UNIRIGHT_ID = t2.id(+) + // [params=(int) 2112201] + assertLockTestSQLs(Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + "\\(\\+\\).*" + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFJTEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfJTEgr t0 LEFT OUTER JOIN LSE1xmLfJTEgr_LSE1xmRt t1 + // ON t0.id = t1.LSE1XMLFJTEGR_ID LEFT OUTER JOIN LSE1xmRt t2 + // ON t1.UNIRIGHT_ID = t2.id WHERE t0.id = ? [params=(int) 2112201] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + + public void findPessimisticForcIncDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFJTEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfJTEgr t0 LEFT OUTER JOIN LSE1xmLfJTEgr_LSE1xmRt t1 + // ON t0.id = t1.LSE1XMLFJTEGR_ID LEFT OUTER JOIN LSE1xmRt t2 + // ON t1.UNIRIGHT_ID = t2.id WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 2112202] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 2122203] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 2122204] + // SELECT t0.version FROM LSE1xmLfJTEgr t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 2112202] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + break; + case oracle: // TODO: if jpa2, DO NOT lock LSE1xmRT using "FOR UPDATE OF col" + // SELECT t0.version, t0.firstName, t1.LSE1XMLFJTEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfJTEgr t0, LSE1xmLfJTEgr_LSE1xmRt t1, LSE1xmRt t2 + // WHERE t0.id = ? AND t0.id = t1.LSE1XMLFJTEGR_ID(+) AND t1.UNIRIGHT_ID = t2.id(+) + // FOR UPDATE [params=(int) 2112202] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE [params=(int) 2122203] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE [params=(int) 2122204] + // SELECT t0.version FROM LSE1xmLfJTEgr t0 WHERE t0.id = ? FOR UPDATE [params=(int) 2112202] + assertLockTestSQLs(Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + "\\(\\+\\).*" + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock. If jpa2, DO NOT lock LSE1xmRt, + // if jpa2/extended, LOCK LSE1xmLfJTEgr_LSE1xmRt + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.version, t0.firstName, t1.LSE1XMLFJTEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfJTEgr t0 LEFT OUTER JOIN LSE1xmLfJTEgr_LSE1xmRt t1 + // ON t0.id = t1.LSE1XMLFJTEGR_ID LEFT OUTER JOIN LSE1xmRt t2 + // ON t1.UNIRIGHT_ID = t2.id WHERE t0.id = ? [params=(int) 2112202] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 2122203] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 2122203] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 2122204] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 2122204] + // SELECT t0.id FROM LSE1xmLfJTEgr t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 2112202] + // SELECT t0.version FROM LSE1xmLfJTEgr t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 2112202] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + tableLfName + Where + ForUpdate, + Select + tableRtName + Where + ForUpdate, + Select + tableRtName + Where + ForUpdate + ); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void queryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: //TODO: **Non-atomic lock. if jpa2, DO NOT lock LSE1xmRt + // if jpa2/extended, LOCK LSE1xmLfJTEgr_LSE1xmRt + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfJTEgr t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%2112201] + // SELECT t0.id, t2.id, t2.version, t2.lastName FROM LSE1xmLfJTEgr t0 + // INNER JOIN LSE1xmLfJTEgr_LSE1xmRt t1 ON t0.id = t1.LSE1XMLFJTEGR_ID + // INNER JOIN LSE1xmRt t2 ON t1.UNIRIGHT_ID = t2.id + // WHERE (t0.firstName LIKE ? ESCAPE '\') ORDER BY t0.id ASC + // [params=(String) firstName%2112201] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(int) 2122201] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2122201] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(int) 2122202] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2122202] + // SELECT t0.version FROM LSE1xmLfJTEgr t0 WHERE t0.id = ? [params=(int) 2112201] + assertLockTestSQLs(Select + tableLfName + Where + DB2Lock, + Select + joinTables + Where + NoDB2Lock, + Select + tableRtName + Where + DB2Lock, + Select + tableRtName + Where + DB2Lock); + break; + case oracle: // TODO: if jpa2, DO NOT lock LSE1xmRT using "FOR UPDATE OF col" + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfJTEgr t0 WHERE (t0.firstName LIKE ?) + // FOR UPDATE [params=(String) firstName%2112201] + // SELECT t0.id, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfJTEgr t0, LSE1xmLfJTEgr_LSE1xmRt t1, LSE1xmRt t2 + // WHERE (t0.firstName LIKE ?) AND t0.id = t1.LSE1XMLFJTEGR_ID + // AND t1.UNIRIGHT_ID = t2.id ORDER BY t0.id ASC FOR UPDATE + // [params=(String) firstName%2112201] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2122201] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2122202] + // SELECT t0.version FROM LSE1xmLfJTEgr t0 WHERE t0.id = ? [params=(int) 2112201] + assertLockTestSQLs(Select + tableLfName + Where + ForUpdate, + Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock. If jpa2, DO NOT lock LSE1xmRt, + // if jpa2/extended, LOCK LSE1xmLfEgr_LSE1xmRt + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfJTEgr t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR + // [params=(String) firstName%2112201] + // SELECT t0.id, t2.id, t2.version, t2.lastName FROM LSE1xmLfJTEgr t0 + // NNER JOIN LSE1xmLfJTEgr_LSE1xmRt t1 ON t0.id = t1.LSE1XMLFJTEGR_ID + // INNER JOIN LSE1xmRt t2 ON t1.UNIRIGHT_ID = t2.id + // WHERE (t0.firstName LIKE ? ESCAPE '\') ORDER BY t0.id ASC + // [params=(String) firstName%2112201] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 2122202] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2122202] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 2122201] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2122201] + // SELECT t0.version FROM LSE1xmLfJTEgr t0 WHERE t0.id = ? [params=(int) 2112201] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + tableLfName + Where + ForUpdate, + Select + tableRtName + Where + ForUpdate, + Select + tableRtName + Where + ForUpdate + ); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFJTEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfJTEgr t0 LEFT OUTER JOIN LSE1xmLfJTEgr_LSE1xmRt t1 + // ON t0.id = t1.LSE1XMLFJTEGR_ID LEFT OUTER JOIN LSE1xmRt t2 + // ON t1.UNIRIGHT_ID = t2.id WHERE t0.id = ? [params=(int) 2112202] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFJTEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfJTEgr t0, LSE1xmLfJTEgr_LSE1xmRt t1, LSE1xmRt t2 + // WHERE t0.id = ? AND t0.id = t1.LSE1XMLFJTEGR_ID(+) AND t1.UNIRIGHT_ID = t2.id(+) + // [params=(int) 2112202] + assertLockTestSQLs(Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + "\\(\\+\\).*" + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFJTEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfJTEgr t0 LEFT OUTER JOIN LSE1xmLfJTEgr_LSE1xmRt t1 + // ON t0.id = t1.LSE1XMLFJTEGR_ID LEFT OUTER JOIN LSE1xmRt t2 + // ON t1.UNIRIGHT_ID = t2.id WHERE t0.id = ? [params=(int) 2112202] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + + public void namedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: //TODO: **Non-atomic lock. if jpa2, DO NOT lock LSE1xmRt + // if jpa2/extended, LOCK LSE1xmLfJTEgr_LSE1xmRt + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfJTEgr t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%2112201] + // SELECT t0.id, t2.id, t2.version, t2.lastName FROM LSE1xmLfJTEgr t0 + // INNER JOIN LSE1xmLfJTEgr_LSE1xmRt t1 ON t0.id = t1.LSE1XMLFJTEGR_ID + // INNER JOIN LSE1xmRt t2 ON t1.UNIRIGHT_ID = t2.id + // WHERE (t0.firstName LIKE ? ESCAPE '\') ORDER BY t0.id ASC + // [params=(String) firstName%2112201] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(int) 2122201] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2122201] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(int) 2122202] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2122202] + // SELECT t0.version FROM LSE1xmLfJTEgr t0 WHERE t0.id = ? [params=(int) 2112201] + assertLockTestSQLs(Select + tableLfName + Where + DB2Lock, + Select + joinTables + Where + NoDB2Lock, + Select + tableRtName + Where + DB2Lock, + Select + tableRtName + Where + DB2Lock); + break; + case oracle: // TODO: if jpa2, DO NOT lock LSE1xmRT using "FOR UPDATE OF col" + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfJTEgr t0 WHERE (t0.firstName LIKE ?) + // FOR UPDATE [params=(String) firstName%2112201] + // SELECT t0.id, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfJTEgr t0, LSE1xmLfJTEgr_LSE1xmRt t1, LSE1xmRt t2 + // WHERE (t0.firstName LIKE ?) AND t0.id = t1.LSE1XMLFJTEGR_ID + // AND t1.UNIRIGHT_ID = t2.id ORDER BY t0.id ASC FOR UPDATE + // [params=(String) firstName%2112201] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2122201] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2122202] + // SELECT t0.version FROM LSE1xmLfJTEgr t0 WHERE t0.id = ? [params=(int) 2112201] + assertLockTestSQLs(Select + tableLfName + Where + ForUpdate, + Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock. If jpa2, DO NOT lock LSE1xmRt, + // if jpa2/extended, LOCK LSE1xmLfEgr_LSE1xmRt + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName FROM LSE1xmLfJTEgr t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR + // params=(String) firstName%2112201] + // SELECT t0.id, t2.id, t2.version, t2.lastName FROM LSE1xmLfJTEgr t0 + // INNER JOIN LSE1xmLfJTEgr_LSE1xmRt t1 ON t0.id = t1.LSE1XMLFJTEGR_ID + // INNER JOIN LSE1xmRt t2 ON t1.UNIRIGHT_ID = t2.id + // WHERE (t0.firstName LIKE ? ESCAPE '\') ORDER BY t0.id ASC + // [params=(String) firstName%2112201] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 2122202] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2122202] + // SELECT t0.id FROM LSE1xmRt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 2122201] + // SELECT t0.version FROM LSE1xmRt t0 WHERE t0.id = ? [params=(int) 2122201] + // SELECT t0.version FROM LSE1xmLfJTEgr t0 WHERE t0.id = ? [params=(int) 2112201] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + tableLfName + Where + ForUpdate, + Select + tableRtName + Where + ForUpdate, + Select + tableRtName + Where + ForUpdate + ); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFJTEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfJTEgr t0 LEFT OUTER JOIN LSE1xmLfJTEgr_LSE1xmRt t1 + // ON t0.id = t1.LSE1XMLFJTEGR_ID LEFT OUTER JOIN LSE1xmRt t2 + // ON t1.UNIRIGHT_ID = t2.id WHERE t0.id = ? [params=(int) 2112202] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFJTEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfJTEgr t0, LSE1xmLfJTEgr_LSE1xmRt t1, LSE1xmRt t2 + // WHERE t0.id = ? AND t0.id = t1.LSE1XMLFJTEGR_ID(+) AND t1.UNIRIGHT_ID = t2.id(+) + // [params=(int) 2112202] + assertLockTestSQLs(Select + tableLfName + ".*" + tableJTName + ".*" + tableRtName + Where + + "\\(\\+\\).*" + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t1.LSE1XMLFJTEGR_ID, t2.id, t2.version, t2.lastName + // FROM LSE1xmLfJTEgr t0 LEFT OUTER JOIN LSE1xmLfJTEgr_LSE1xmRt t1 + // ON t0.id = t1.LSE1XMLFJTEGR_ID LEFT OUTER JOIN LSE1xmRt t2 + // ON t1.UNIRIGHT_ID = t2.id WHERE t0.id = ? [params=(int) 2112202] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + }); + } +} diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/TestBasicLockScope.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/TestBasicLockScope.java new file mode 100644 index 000000000..2cce55bbb --- /dev/null +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/TestBasicLockScope.java @@ -0,0 +1,1225 @@ +/* + * 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.lock.extended; + +import javax.persistence.EntityManager; + +/** + * LockScopeTestCase subclass to test entities: + * - with Basic attributes + * - uses secondary table + * - uses inheritance in single table + * - uses inheritance and join table + * - uses element collection - lazy fetch (default) + * - uses element collection - eager fetch + */ +public class TestBasicLockScope extends LockScopeTestCase { + + public void setUp() { + setUp(LSEBase.class + , LSESecTbl.class + , LSESngTblCon.class + , LSESngTblAbs.class + , LSEJoinCon.class + , LSEJoinAbs.class + , LSEEleCol.class + , LSEEleColEgr.class + , "openjpa.LockManager", "mixed", + "openjpa.jdbc.SynchronizeMappings", "buildSchema(ForeignKeys=true)" + ); + commonSetUp(LSEBase.class + , LSESecTbl.class + , LSESngTblCon.class + , LSESngTblAbs.class + , LSEJoinCon.class + , LSEJoinAbs.class + , LSEEleCol.class + , LSEEleColEgr.class + ); + } + + public void testNormalBasicLock() { + commonBasicLock("testNormalBasicLock", 000, false); + } + + public void testExtendedBasicLock() { + commonBasicLock("testExtendedBasicLock", 010, true); + } + + private void commonBasicLock(String testName, int id0, boolean extended) { + final String tableName = "LSEBase"; + getLog().info("** " + testName + "()"); + String scope = extended ? "Extended" : "Normal"; + int id1 = id0 + 1; + + // create test entity. + LSEBase e0 = new LSEBase(); + e0.setId(id0); + e0.setFirstName("firstName " + id0); + e0.setLastName("lastName " + id0); + LSEBase e1 = new LSEBase(); + e1.setId(id1); + e1.setFirstName("firstName " + id1); + e1.setLastName("lastName " + id1); + + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(e0); + em.persist(e1); + em.getTransaction().commit(); + } finally { + em = null; + e0 = e1 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + + commonLockTest(testName, LSEBase.class, id0, extended, + "SELECT c FROM LSEBase c WHERE c.firstName LIKE :firstName", "findLSEBase" + scope, + new AssertCallback() { + public void findNoLockDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 0] + assertLockTestSQLs(Select + tableName + Where + NoDB2Lock); + break; + case derby: + // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ? + // [params=(int) 0] + case oracle: + // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ? + // [params=(int) 0] + default: + assertLockTestSQLs(Select + tableName + Where + NoForUpdate); + } + } + + public void findPessimisticForcIncDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ? + // optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1] + // SELECT t0.version FROM LSEBase t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1] + assertLockTestSQLs(Select + tableName + Where + DB2Lock); + break; + case derby: + // SELECT t0.version, t0.firstName, t0.lastName FROM + // LSEBase t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1] + case oracle: + // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ? FOR UPDATE + // [params=(int) 1] + // SELECT t0.version FROM LSEBase t0 WHERE t0.id = ? FOR UPDATE [params=(int) 1] + default: + assertLockTestSQLs(Select + tableName + Where + ForUpdate); + } + } + + public void queryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName, t0.lastName FROM LSEBase t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%0] + // SELECT t0.version FROM LSEBase t0 WHERE t0.id = ? [params=(int) 0] + assertLockTestSQLs(Select + tableName + Where + DB2Lock); + break; + case derby: + // SELECT t0.id, t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE (t0.firstName + // LIKE ? ESCAPE '\') FOR UPDATE WITH RR [params=(String) firstName%0] + case oracle: + // SELECT t0.id, t0.version, t0.firstName, t0.lastName FROM LSEBase t0 + // WHERE (t0.firstName LIKE ?) FOR UPDATE [params=(String) firstName%0] + // SELECT t0.version FROM LSEBase t0 WHERE t0.id = ? [params=(int) 0] + default: + assertLockTestSQLs(Select + tableName + Where + ForUpdate); + } + } + + public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 1] + assertLockTestSQLs(Select + tableName + Where + NoDB2Lock); + break; + case derby: + // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ? + // [params=(int) 1] + case oracle: + // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ? + // [params=(int) 1] + default: + assertLockTestSQLs(Select + tableName + Where + NoForUpdate); + } + } + + public void namedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName, t0.lastName FROM LSEBase t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%0] + // SELECT t0.version FROM LSEBase t0 WHERE t0.id = ? [params=(int) 0] + assertLockTestSQLs(Select + tableName + Where + DB2Lock); + break; + case derby: + // SELECT t0.id, t0.version, t0.firstName, t0.lastName FROM LSEBase t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR + case oracle: + // SELECT t0.id, t0.version, t0.firstName, t0.lastName FROM LSEBase t0 + // WHERE (t0.firstName LIKE ?) FOR UPDATE [params=(String) firstName%0] + // SELECT t0.version FROM LSEBase t0 WHERE t0.id = ? [params=(int) 0] + default: + assertLockTestSQLs(Select + tableName + Where + ForUpdate); + } + } + + public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 1] + assertLockTestSQLs(Select + tableName + Where + NoDB2Lock); + break; + case derby: + // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ? + case oracle: + // SELECT t0.version, t0.firstName, t0.lastName FROM LSEBase t0 WHERE t0.id = ? + // [params=(int) 1] + default: + assertLockTestSQLs(Select + tableName + Where + NoForUpdate); + } + } + }); + } + + public void testNormalSecTableLock() { + commonSecTableLock("testNormalSecTableLock", 100, false); + } + + public void testExtendedSecTableLock() { + commonSecTableLock("testExtendedSecTableLock", 110, true); + } + + private void commonSecTableLock(String testName, int id0, boolean extended) { + final String table1Name = "LSESecTbl"; + final String table2Name = "LSESecTblDtl"; + final String joinTables = table1Name + ".*JOIN.*" + table2Name; + getLog().info("** " + testName + "()"); + String scope = extended ? "Extended" : "Normal"; + int id1 = id0 + 1; + + // create test entity. + LSESecTbl e0 = new LSESecTbl(); + e0.setId(id0); + e0.setFirstName("firstName " + id0); + e0.setLastName("lastName " + id0); + LSESecTbl e1 = new LSESecTbl(); + e1.setId(id1); + e1.setFirstName("firstName " + id1); + e1.setLastName("lastName " + id1); + + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(e0); + em.persist(e1); + em.getTransaction().commit(); + } finally { + em = null; + e0 = e1 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + + commonLockTest(testName, LSESecTbl.class, id0, extended, + "SELECT c FROM LSESecTbl c WHERE c.firstName LIKE :firstName", "findLSESecTbl" + scope, + new AssertCallback() { + public void findNoLockDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0 + // INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID WHERE t0.id = ? + // optimize for 1 row [params=(int) 100] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0, LSESecTblDtl t1 + // WHERE t0.id = ? AND t0.id = t1.LSESECTBL_ID [params=(int) 100] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0 + // INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID WHERE t0.id = ? + // [params=(int) 100] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + + public void findPessimisticForcIncDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0 + // INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID WHERE t0.id = ? + // optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 101] + // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 101] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0, LSESecTblDtl t1 + // WHERE t0.id = ? AND t0.id = t1.LSESECTBL_ID FOR UPDATE [params=(int) 101] + // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ? FOR UPDATE [params=(int) 101] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock, SecTblDtl NOT locked ********* + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0 + // INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID WHERE t0.id = ? + // [params=(int) 101] + // SELECT t0.id FROM LSESecTbl t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 101] + // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 101] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + table1Name + ".*" + Where + ForUpdate); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void queryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0 + // INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%100] + // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ? [params=(int) 100] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + break; + case oracle: + // SELECT t0.id, t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0, LSESecTblDtl t1 + // WHERE (t0.firstName LIKE ?) AND t0.id = t1.LSESECTBL_ID FOR UPDATE + // [params=(String) firstName%100] + // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ? [params=(int) 100] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock, SecTblDtl NOT locked ********* + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0 + // INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID + // WHERE (t0.firstName LIKE ? ESCAPE '\') [params=(String) firstName%100] + // SELECT t0.id FROM LSESecTbl t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 100] + // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ? [params=(int) 100] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + table1Name + ".*" + Where + ForUpdate); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0 + // INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID WHERE t0.id = ? + // optimize for 1 row [params=(int) 101] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0, LSESecTblDtl t1 + // WHERE t0.id = ? AND t0.id = t1.LSESECTBL_ID [params=(int) 101] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0 + // INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID WHERE t0.id = ? + // [params=(int) 101] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + + public void namedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0 + // INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%100] + // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ? [params=(int) 100] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + break; + case oracle: + // SELECT t0.id, t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0, LSESecTblDtl t1 + // WHERE (t0.firstName LIKE ?) AND t0.id = t1.LSESECTBL_ID FOR UPDATE + // [params=(String) firstName%100] + // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ? [params=(int) 100] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock, SecTblDtl NOT locked ********* + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0 + // INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID + // WHERE (t0.firstName LIKE ? ESCAPE '\') [params=(String) firstName%100] + // SELECT t0.id FROM LSESecTbl t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 100] + // SELECT t0.version FROM LSESecTbl t0 WHERE t0.id = ? [params=(int) 100] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + table1Name + ".*" + Where + ForUpdate); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0 + // INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID WHERE t0.id = ? + // optimize for 1 row [params=(int) 101] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0, LSESecTblDtl t1 + // WHERE t0.id = ? AND t0.id = t1.LSESECTBL_ID [params=(int) 101] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t1.lastName FROM LSESecTbl t0 + // INNER JOIN LSESecTblDtl t1 ON t0.id = t1.LSESECTBL_ID WHERE t0.id = ? + // [params=(int) 101] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + }); + } + + public void testNormalSingleTableLock() { + commonSingleTableLock("testNormalSingleTableLock", 200, false); + } + + public void testExtendedlSingleTableLock() { + commonSingleTableLock("testExtendedlSingleTableLock", 210, true); + } + + private void commonSingleTableLock(String testName, int id0, boolean extended) { + final String tableName = "LSESngTblAbs"; + getLog().info("** " + testName + "()"); + String scope = extended ? "Extended" : "Normal"; + int id1 = id0 + 1; + + // create test entity. + LSESngTblCon e0 = new LSESngTblCon(); + e0.setId(id0); + e0.setFirstName("firstName " + id0); + e0.setLastName("lastName " + id0); + LSESngTblCon e1 = new LSESngTblCon(); + e1.setId(id1); + e1.setFirstName("firstName " + id1); + e1.setLastName("lastName " + id1); + + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(e0); + em.persist(e1); + em.getTransaction().commit(); + } finally { + em = null; + e0 = e1 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + + commonLockTest(testName, LSESngTblCon.class, id0, extended, + "SELECT c FROM LSESngTblAbs c WHERE c.firstName LIKE :firstName", + "findLSESngTblCon" + scope, new AssertCallback() { + + public void findNoLockDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE t0.DTYPE = ? AND t0.id = ? + // optimize for 1 row [params=(String) LSESngTblCon, (int) 200] + assertLockTestSQLs(Select + tableName + Where + NoDB2Lock); + break; + case derby: + // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE t0.DTYPE = ? AND t0.id = ? [params=(String) LSESngTblCon, (int) 200] + case oracle: + // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE t0.DTYPE = ? AND t0.id = ? [params=(String) LSESngTblCon, (int) 200] + default: + assertLockTestSQLs(Select + tableName + Where + NoForUpdate); + } + } + + public void findPessimisticForcIncDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE t0.DTYPE = ? AND t0.id = ? + // optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS + // [params=(String) LSESngTblCon, (int) 201] + // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 201] + assertLockTestSQLs(Select + tableName + Where + DB2Lock); + break; + case derby: + // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE t0.DTYPE = ? AND t0.id = ? FOR UPDATE WITH RR + // [params=(String) LSESngTblCon, (int) 201] + // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 201] + case oracle: + // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE t0.DTYPE = ? AND t0.id = ? FOR UPDATE + // [params=(String) LSESngTblCon, (int) 201] + // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ? FOR UPDATE [params=(int) 201] + default: + assertLockTestSQLs(Select + tableName + Where + ForUpdate); + } + } + + public void queryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%200] + // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ? [params=(int) 200] + assertLockTestSQLs(Select + tableName + Where + DB2Lock); + break; + case derby: + // SELECT t0.id, t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR + // [params=(String) firstName%200] + // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ? [params=(int) 200] + case oracle: + // SELECT t0.id, t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE (t0.firstName LIKE ?) FOR UPDATE [params=(String) firstName%200] + // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ? [params=(int) 200] + default: + assertLockTestSQLs(Select + tableName + Where + ForUpdate); + } + } + + public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE t0.DTYPE = ? AND t0.id = ? + // optimize for 1 row [params=(String) LSESngTblCon, (int) 201] + assertLockTestSQLs(Select + tableName + Where + NoDB2Lock); + break; + case derby: + // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE t0.DTYPE = ? AND t0.id = ? [params=(String) LSESngTblCon, (int) 201] + case oracle: + // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE t0.DTYPE = ? AND t0.id = ? [params=(String) LSESngTblCon, (int) 201] + default: + assertLockTestSQLs(Select + tableName + Where + NoForUpdate); + } + } + + public void namedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') AND t0.DTYPE = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%200, (String) LSESngTblCon] + // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ? [params=(int) 200] + assertLockTestSQLs(Select + tableName + Where + DB2Lock); + break; + case derby: + // SELECT t0.id, t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') AND t0.DTYPE = ? FOR UPDATE WITH RR + // [params=(String) firstName%200, (String) LSESngTblCon] + // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ? [params=(int) 200] + case oracle: + // SELECT t0.id, t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE (t0.firstName LIKE ?) AND t0.DTYPE = ? FOR UPDATE + // [params=(String) firstName%200, (String) LSESngTblCon] + // SELECT t0.version FROM LSESngTblAbs t0 WHERE t0.id = ? [params=(int) 200] + default: + assertLockTestSQLs(Select + tableName + Where + ForUpdate); + } + } + + public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE t0.DTYPE = ? AND t0.id = ? + // optimize for 1 row [params=(String) LSESngTblCon, (int) 201] + assertLockTestSQLs(Select + tableName + Where + NoDB2Lock); + break; + case derby: + // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE t0.DTYPE = ? AND t0.id = ? [params=(String) LSESngTblCon, (int) 201] + case oracle: + // SELECT t0.DTYPE, t0.version, t0.firstName, t0.lastName FROM LSESngTblAbs t0 + // WHERE t0.DTYPE = ? AND t0.id = ? [params=(String) LSESngTblCon, (int) 201] + default: + assertLockTestSQLs(Select + tableName + Where + NoForUpdate); + } + } + }); + } + + public void testNormalJoinedLock() { + commonJoinedLock("testNormalJoinedLock", 400, false); + } + + public void testExtendedJoinedLock() { + commonJoinedLock("testExtendedJoinedLock", 410, true); + } + + private void commonJoinedLock(String testName, int id0, boolean extended) { + final String table1Name = "LSEJoinCon"; + final String table2Name = "LSEJoinAbs"; + final String joinTables = table1Name + ".*JOIN.*" + table2Name; + getLog().info("** " + testName + "()"); + String scope = extended ? "Extended" : "Normal"; + int id1 = id0 + 1; + + // create test entity. + LSEJoinCon e0 = new LSEJoinCon(); + e0.setId(id0); + e0.setFirstName("firstName " + id0); + e0.setLastName("lastName " + id0); + LSEJoinCon e1 = new LSEJoinCon(); + e1.setId(id1); + e1.setFirstName("firstName " + id1); + e1.setLastName("lastName " + id1); + + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(e0); + em.persist(e1); + em.getTransaction().commit(); + } finally { + em = null; + e0 = e1 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + + commonLockTest(testName, LSEJoinCon.class, id0, extended, + "SELECT c FROM LSEJoinCon c WHERE c.firstName LIKE :firstName", "findLSEJoinCon" + + scope, new AssertCallback() { + + public void findNoLockDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0 + // INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE t0.id = ? + // optimize for 1 row [params=(int) 400] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0, LSEJoinAbs t1 + // WHERE t0.id = ? AND t0.id = t1.id [params=(int) 400] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + NoForUpdate); + break; + case derby: + // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0 + // INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE t0.id = ? [params=(int) 400] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + + public void findPessimisticForcIncDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0 + // INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE t0.id = ? + // optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS[params=(int) 401] + // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 401] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + break; + case oracle: + // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0, LSEJoinAbs t1 + // WHERE t0.id = ? AND t0.id = t1.id FOR UPDATE [params=(int) 401] + // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ? FOR UPDATE [params=(int) 401] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock, LSEJoinCon NOT locked ********* + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0 + // INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE t0.id = ? [params=(int) 401] + // SELECT t0.id FROM LSEJoinAbs t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 401] + // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 401] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + table2Name + ".*" + Where + ForUpdate); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void queryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t1.id, t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0 + // INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id + // WHERE (t1.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%400] + // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ? [params=(int) 400] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + break; + case oracle: + // SELECT t1.id, t0.id, t1.version, t1.firstName, t0.lastName + // FROM LSEJoinCon t0, LSEJoinAbs t1 WHERE (t1.firstName LIKE ?) AND t0.id = t1.id + // FOR UPDATE [params=(String) firstName%400] + // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ? [params=(int) 400] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock, LSEJoinCon NOT locked ********* + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t1.id, t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0 + // INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE (t1.firstName LIKE ? ESCAPE '\') + // [params=(String) firstName%400] + // SELECT t0.id FROM LSEJoinAbs t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 400] + // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ? [params=(int) 400] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + table2Name + ".*" + Where + ForUpdate); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0 + // INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE t0.id = ? + // optimize for 1 row [params=(int) 401] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0, LSEJoinAbs t1 + // WHERE t0.id = ? AND t0.id = t1.id [params=(int) 401] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + NoForUpdate); + break; + case derby: + // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0 + // INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE t0.id = ? [params=(int) 401] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + + public void namedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t1.id, t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0 + // INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id + // WHERE (t1.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%400] + // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ? [params=(int) 400] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + break; + case oracle: + // SELECT t1.id, t0.id, t1.version, t1.firstName, t0.lastName + // FROM LSEJoinCon t0, LSEJoinAbs t1 WHERE (t1.firstName LIKE ?) AND t0.id = t1.id + // FOR UPDATE [params=(String) firstName%400] + // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ? [params=(int) 400] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + ForUpdate); + break; + case derby: //TODO: **Non-atomic lock, LSEJoinCon NOT locked ********* + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t1.id, t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0 + // INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE (t1.firstName LIKE ? ESCAPE '\') + // [params=(String) firstName%400] + // SELECT t0.id FROM LSEJoinAbs t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 400] + // SELECT t0.version FROM LSEJoinAbs t0 WHERE t0.id = ? [params=(int) 400] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + table2Name + ".*" + Where + ForUpdate); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0 + // INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE t0.id = ? + // optimize for 1 row [params=(int) 401] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0, LSEJoinAbs t1 + // WHERE t0.id = ? AND t0.id = t1.id [params=(int) 401] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + NoForUpdate); + break; + case derby: + // SELECT t0.id, t1.version, t1.firstName, t0.lastName FROM LSEJoinCon t0 + // INNER JOIN LSEJoinAbs t1 ON t0.id = t1.id WHERE t0.id = ? [params=(int) 401] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + }); + } + + public void testNormalElementCollectionLock() { + commonElementCollectionLock("testNormalElementCollectionLock", 500, false); + } + + public void testExtendedElementCollectionLock() { + commonElementCollectionLock("testExtendedElementCollectionLock", 510, true); + } + + private void commonElementCollectionLock(String testName, int id0, boolean extended) { + final String tableName ="LSEEleCol"; + getLog().info("** " + testName + "()"); + String scope = extended ? "Extended" : "Normal"; + int id1 = id0 + 1; + + // create test entity. + LSEEleCol e0 = new LSEEleCol(); + e0.setId(id0); + e0.setFirstName("firstName lazy " + id0); + e0.addCollection(id0 + "String1"); + e0.addCollection(id0 + "String2"); + LSEEleCol e1 = new LSEEleCol(); + e1.setId(id1); + e1.setFirstName("lazy " + id1); + e1.addCollection(id1 + "String1"); + e1.addCollection(id1 + "String2"); + + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(e0); + em.persist(e1); + em.getTransaction().commit(); + } finally { + em = null; + e0 = e1 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + + commonLockTest(testName, LSEEleCol.class, id0, extended, + "SELECT c FROM LSEEleCol c WHERE c.firstName LIKE :firstName", "findLSEEleCol" + scope, + new AssertCallback() { + + public void findNoLockDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 500] + assertLockTestSQLs(Select + tableName + Where + NoDB2Lock); + break; + case derby: + // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 500] + case oracle: + // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 500] + default: + assertLockTestSQLs(Select + tableName + Where + NoForUpdate); + } + } + + public void findPessimisticForcIncDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? + // optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS + // [params=(int) 501] + // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 501] + assertLockTestSQLs(Select + tableName + Where + DB2Lock); + break; + case derby: + // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 501] + // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 501] + case oracle: + // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? FOR UPDATE + // [params=(int) 501] + // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ? FOR UPDATE [params=(int) 501] + default: + assertLockTestSQLs(Select + tableName + Where + ForUpdate); + } + } + + public void queryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName FROM LSEEleCol t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%500] + // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 500] + assertLockTestSQLs(Select + tableName + Where + DB2Lock); + break; + case derby: + // SELECT t0.id, t0.version, t0.firstName FROM LSEEleCol t0 WHERE + // (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR [params=(String) firstName%500] + // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 500] + case oracle: + // SELECT t0.id, t0.version, t0.firstName FROM LSEEleCol t0 WHERE (t0.firstName LIKE ?) + // FOR UPDATE [params=(String) firstName%500] + // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 500] + default: + assertLockTestSQLs(Select + tableName + Where + ForUpdate); + } + } + + public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 501] + assertLockTestSQLs(Select + tableName + Where + NoDB2Lock); + break; + case derby: + // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 501] + case oracle: + // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 501] + default: + assertLockTestSQLs(Select + tableName + Where + NoForUpdate); + } + } + + public void namedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.id, t0.version, t0.firstName FROM LSEEleCol t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%500] + // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 500] + assertLockTestSQLs(Select + tableName + Where + DB2Lock); + break; + case derby: + // SELECT t0.id, t0.version, t0.firstName FROM LSEEleCol t0 WHERE + // (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR [params=(String) firstName%500] + // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 500] + case oracle: + // SELECT t0.id, t0.version, t0.firstName FROM LSEEleCol t0 WHERE (t0.firstName LIKE ?) + // FOR UPDATE [params=(String) firstName%500] + // SELECT t0.version FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 500] + default: + assertLockTestSQLs(Select + tableName + Where + ForUpdate); + } + } + + public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? + // optimize for 1 row [params=(int) 501] + assertLockTestSQLs(Select + tableName + Where + NoDB2Lock); + break; + case derby: + // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 501] + case oracle: + // SELECT t0.version, t0.firstName FROM LSEEleCol t0 WHERE t0.id = ? [params=(int) 501] + default: + assertLockTestSQLs(Select + tableName + Where + NoForUpdate); + } + } + }); + } + + public void testNormalElementCollectionEagerLock() { + commonElementCollectionEagerLock("testNormalElementCollectionEagerLock", 600, false); + } + + public void testExtendedElementCollectionEagerLock() { + commonElementCollectionEagerLock("testExtendedElementCollectionEagerLock", 610, true); + } + + private void commonElementCollectionEagerLock(String testName, int id0, boolean extended) { + final String table1Name = "LSEEleColEgr"; + final String table2Name = "LSEEleColEgr_collection"; +// final String table2Name_oracle = table2Name;//.toUpperCase().substring(0, Math.min(table2Name.length(), 30)); + final String joinTables = table1Name + ".*JOIN.*" + table2Name; + getLog().info("** " + testName + "()"); + String scope = extended ? "Extended" : "Normal"; + int id1 = id0 + 1; + + // create test entity. + LSEEleColEgr e0 = new LSEEleColEgr(); + e0.setId(id0); + e0.setFirstName("firstName eager " + id0); + e0.addCollection(id0 + "String1"); + e0.addCollection(id0 + "String2"); + LSEEleColEgr e1 = new LSEEleColEgr(); + e1.setId(id1); + e1.setFirstName("firstName eager " + id1); + e1.addCollection(id1 + "String1"); + e1.addCollection(id1 + "String2"); + + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + em.persist(e0); + em.persist(e1); + em.getTransaction().commit(); + } finally { + em = null; + e0 = e1 = null; + if (em != null && em.isOpen()) { + em.close(); + } + } + + commonLockTest(testName, LSEEleColEgr.class, id0, extended, + "SELECT c FROM LSEEleColEgr c WHERE c.firstName LIKE :firstName", + "findLSEEleColEgr" + scope, new AssertCallback() { + + public void findNoLockDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element FROM LSEEleColEgr t0 + // LEFT OUTER JOIN LSEEleColEgr_collection t1 ON t0.id = t1.LSEELECOLEGR_ID + // WHERE t0.id = ? [params=(int) 600] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element + // FROM LSEEleColEgr t0, LSEEleColEgr_collection t1 + // WHERE t0.id = ? AND t0.id = t1.LSEELECOLEGR_ID(+) [params=(int) 600] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + "\\(\\+\\).*" + + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element FROM LSEEleColEgr t0 + // LEFT OUTER JOIN LSEEleColEgr_collection t1 ON t0.id = t1.LSEELECOLEGR_ID + // WHERE t0.id = ? [params=(int) 600] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + + public void findPessimisticForcIncDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element FROM LSEEleColEgr t0 + // LEFT OUTER JOIN LSEEleColEgr_collection t1 ON t0.id = t1.LSEELECOLEGR_ID + // WHERE t0.id = ? FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 601] + // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 601] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element + // FROM LSEEleColEgr t0, LSEEleColEgr_collection t1 + // WHERE t0.id = ? AND t0.id = t1.LSEELECOLEGR_ID(+) FOR UPDATE [params=(int) 601] + // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ? FOR UPDATE [params=(int) 601] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + "\\(\\+\\).*" + + NoForUpdate); + break; + case derby: // **Non-atomic lock, No need to lock LSEEleColEgr_collection ********* + // TODO: Can do the same as query below, if extended scope. i.e. select LSEEleColEgr + // with lock and fetch element collection without lock. + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element FROM LSEEleColEgr t0 + // LEFT OUTER JOIN LSEEleColEgr_collection t1 ON t0.id = t1.LSEELECOLEGR_ID + // WHERE t0.id = ? [params=(int) 601] + // SELECT t0.id FROM LSEEleColEgr t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 601] + // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ? FOR UPDATE WITH RR + // [params=(int) 601] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + table1Name + ".*" + Where + ForUpdate); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void queryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: // **Non-atomic lock, No need to lock LSEEleColEgr_collection ********* + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName FROM LSEEleColEgr t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%600] + // SELECT t0.id, t1.element FROM LSEEleColEgr t0 INNER JOIN LSEEleColEgr_collection t1 + // ON t0.id = t1.LSEELECOLEGR_ID WHERE (t0.firstName LIKE ? ESCAPE '\') + // ORDER BY t0.id ASC [params=(String) firstName%600] + // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ? [params=(int) 600] + assertLockTestSQLs(Select + "LSEEleColEgr.*" + Where + DB2Lock, + Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.id, t0.version, t0.firstName FROM LSEEleColEgr t0 WHERE (t0.firstName LIKE ?) + // FOR UPDATE [params=(String) firstName%600] + // SELECT t0.id, t1.element FROM LSEEleColEgr t0, LSEEleColEgr_collection t1 + // WHERE (t0.firstName LIKE ?) AND t0.id = t1.LSEELECOLEGR_ID ORDER BY t0.id ASC + // FOR UPDATE [params=(String) firstName%600] + // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ? [params=(int) 600] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + ForUpdate); + break; + case derby: //**Non-atomic lock, No need to lock LSEEleColEgr_Collection ********* + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName FROM LSEEleColEgr t0 WHERE + // (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR [params=(String) firstName%600] + // SELECT t0.id, t1.element FROM LSEEleColEgr t0 INNER JOIN LSEEleColEgr_collection t1 + // ON t0.id = t1.LSEELECOLEGR_ID WHERE (t0.firstName LIKE ? ESCAPE '\') + // ORDER BY t0.id ASC [params=(String) firstName%600] + // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ? [params=(int) 600] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + table1Name + ".*" + Where + ForUpdate); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void findNoLockAfterQueryPessimisticReadDbSQL(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element FROM LSEEleColEgr t0 + // LEFT OUTER JOIN LSEEleColEgr_collection t1 ON t0.id = t1.LSEELECOLEGR_ID + // WHERE t0.id = ? [params=(int) 601] + assertLockTestSQLs(Select + "LSEEleColEgr.*" + Where + DB2Lock, + Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element + // FROM LSEEleColEgr t0, LSEEleColEgr_collection t1 + // WHERE t0.id = ? AND t0.id = t1.LSEELECOLEGR_ID(+) [params=(int) 601] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + "\\(\\+\\).*" + + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element FROM LSEEleColEgr t0 + // LEFT OUTER JOIN LSEEleColEgr_collection t1 ON t0.id = t1.LSEELECOLEGR_ID + // WHERE t0.id = ? [params=(int) 601] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + + public void namedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { + case db2: // **Non-atomic lock, No need to lock LSEEleColEgr_collection ********* + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName FROM LSEEleColEgr t0 + // WHERE (t0.firstName LIKE ? ESCAPE '\') + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%600] + // SELECT t0.id, t1.element FROM LSEEleColEgr t0 INNER JOIN LSEEleColEgr_collection t1 + // ON t0.id = t1.LSEELECOLEGR_ID WHERE (t0.firstName LIKE ? ESCAPE '\') + // ORDER BY t0.id ASC [params=(String) firstName%600] + // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ? [params=(int) 600] + assertLockTestSQLs(Select + "LSEEleColEgr.*" + Where + DB2Lock, + Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.id, t0.version, t0.firstName FROM LSEEleColEgr t0 WHERE (t0.firstName LIKE ?) + // FOR UPDATE [params=(String) firstName%600] + // SELECT t0.id, t1.element FROM LSEEleColEgr t0, LSEEleColEgr_collection t1 + // WHERE (t0.firstName LIKE ?) AND t0.id = t1.LSEELECOLEGR_ID ORDER BY t0.id ASC + // FOR UPDATE [params=(String) firstName%600] + // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ? [params=(int) 600] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + ForUpdate); + break; + case derby: // **Non-atomic lock, No need to lock LSEEleColEgr_collection ********* + // The database is unable to lock this query. Each object matching the query will be + // locked individually after it is loaded; however, it is technically possible that + // another transaction could modify the data before the lock is obtained. + // SELECT t0.id, t0.version, t0.firstName FROM LSEEleColEgr t0 WHERE + // (t0.firstName LIKE ? ESCAPE '\') FOR UPDATE WITH RR [params=(String) firstName%600] + // SELECT t0.id, t1.element FROM LSEEleColEgr t0 INNER JOIN LSEEleColEgr_collection t1 + // ON t0.id = t1.LSEELECOLEGR_ID WHERE (t0.firstName LIKE ? ESCAPE '\') + // ORDER BY t0.id ASC [params=(String) firstName%600] + // SELECT t0.version FROM LSEEleColEgr t0 WHERE t0.id = ? [params=(int) 600] + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, + Select + table1Name + ".*" + Where + ForUpdate); + break; + default: + assertLockTestSQLs(Select + joinTables + Where + ForUpdate); + } + } + + public void findNoLockAfterNamedQueryPessimisticWriteDbSql(EntityManager em) { + switch (getDBType(em)) { // **Check + case db2: + // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element FROM LSEEleColEgr t0 + // LEFT OUTER JOIN LSEEleColEgr_collection t1 ON t0.id = t1.LSEELECOLEGR_ID + // WHERE t0.id = ? [params=(int) 601] + assertLockTestSQLs(Select + joinTables + Where + NoDB2Lock); + break; + case oracle: + // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element + // FROM LSEEleColEgr t0, LSEEleColEgr_collection t1 + // WHERE t0.id = ? AND t0.id = t1.LSEELECOLEGR_ID(+) [params=(int) 601] + assertLockTestSQLs(Select + table1Name + ".*" + table2Name + Where + "\\(\\+\\).*" + + NoForUpdate); + break; + case derby: + // SELECT t0.version, t0.firstName, t1.LSEELECOLEGR_ID, t1.element FROM LSEEleColEgr t0 + // LEFT OUTER JOIN LSEEleColEgr_collection t1 ON t0.id = t1.LSEELECOLEGR_ID + // WHERE t0.id = ? [params=(int) 601] + default: + assertLockTestSQLs(Select + joinTables + Where + NoForUpdate); + } + } + }); + } +} 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 218356a51..509f43886 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 @@ -61,8 +61,6 @@ import javax.persistence.FlushModeType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; -import javax.persistence.Access; -import javax.persistence.AccessType; import javax.persistence.Id; import javax.persistence.IdClass; import javax.persistence.Lob; @@ -1772,7 +1770,9 @@ public class AnnotationPersistenceMetaDataParser meta.setLanguage(JPQLParser.LANG_JPQL); for (QueryHint hint : query.hints()) meta.addHint(hint.name(), hint.value()); - + if (query.lockMode() != null) { + meta.addHint("openjpa.FetchPlan.ReadLockMode", query.lockMode()); + } meta.setSource(getSourceFile(), (el instanceof Class) ? el : null, SourceTracker.SRC_ANNOTATIONS); if (isMetaDataMode()) diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java index 228c2f534..089c330cf 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlan.java @@ -20,9 +20,9 @@ package org.apache.openjpa.persistence; import java.util.Collection; import java.util.Map; -import java.util.Set; import javax.persistence.LockModeType; +import javax.persistence.PessimisticLockScope; import org.apache.openjpa.kernel.DataCacheRetrieveMode; import org.apache.openjpa.kernel.DataCacheStoreMode; @@ -321,6 +321,16 @@ public interface FetchPlan { */ public FetchPlan setLockTimeout(int timeout); + /** + * The lock scope to use for locking loaded objects. + */ + public PessimisticLockScope getLockScope(); + + /** + * The lock scope to use for locking loaded objects. + */ + public FetchPlan setLockScope(PessimisticLockScope scope); + /** * The number of milliseconds to wait for a query, or -1 for no * limit. diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanHintHandler.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanHintHandler.java index 7b3417445..a7f50c316 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanHintHandler.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanHintHandler.java @@ -59,6 +59,7 @@ public class FetchPlanHintHandler extends AbstractHintHandler { } // Initialize javax.persistence to openjpa.FetchPlan hint mapping. javaxHintsMap.put(JPAProperties.LOCK_TIMEOUT, PREFIX_FETCHPLAN + "LockTimeout"); + javaxHintsMap.put(JPAProperties.LOCK_SCOPE, PREFIX_FETCHPLAN + "LockScope"); javaxHintsMap.put(JPAProperties.QUERY_TIMEOUT, PREFIX_FETCHPLAN + "QueryTimeout"); // Initialize hint precedence order mapping from list. String[][] precedenceMapList = { @@ -66,6 +67,10 @@ public class FetchPlanHintHandler extends AbstractHintHandler { PREFIX_FETCHPLAN + "LockTimeout", PREFIX_OPENJPA + "LockTimeout" }, + { JPAProperties.LOCK_SCOPE, + PREFIX_FETCHPLAN + "LockScope", + PREFIX_OPENJPA + "LockScope" }, + { JPAProperties.QUERY_TIMEOUT, PREFIX_FETCHPLAN + "QueryTimeout", PREFIX_OPENJPA + "QueryTimeout" }, diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanImpl.java index 3d4f0d438..b08e2e001 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanImpl.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/FetchPlanImpl.java @@ -25,6 +25,7 @@ import java.util.Iterator; import java.util.Map; import javax.persistence.LockModeType; +import javax.persistence.PessimisticLockScope; import org.apache.openjpa.kernel.DataCacheRetrieveMode; import org.apache.openjpa.kernel.DataCacheStoreMode; @@ -237,6 +238,15 @@ public class FetchPlanImpl return this; } + public PessimisticLockScope getLockScope() { + return LockScopesHelper.fromLockScope(_fetch.getLockScope()); + } + + public FetchPlan setLockScope(PessimisticLockScope scope) { + _fetch.setLockScope(LockScopesHelper.toLockScope(scope)); + return this; + } + public int getQueryTimeout() { return _fetch.getQueryTimeout(); } diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/LockScopesHelper.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/LockScopesHelper.java new file mode 100644 index 000000000..78309e994 --- /dev/null +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/LockScopesHelper.java @@ -0,0 +1,49 @@ +/* + * 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; + +import javax.persistence.PessimisticLockScope; + +import org.apache.openjpa.kernel.LockScopes; + +/** + * Helper methods translate between JPA-defined pessimistic lock scope and + * OpenJPA internal lock scope levels. + * + * @since 2.0.0 + */ +public class LockScopesHelper { + /** + * Translates javax.persistence LockModeType to internal lock level. + */ + public static int toLockScope(PessimisticLockScope scope) { + if (scope == null || scope == PessimisticLockScope.NORMAL) + return LockScopes.LOCKSCOPE_NORMAL; + return LockScopes.LOCKSCOPE_EXTENDED; + } + + /** + * Translates internal lock level to javax.persistence LockModeType. + */ + public static PessimisticLockScope fromLockScope(int level) { + if (level < LockScopes.LOCKSCOPE_EXTENDED) + return PessimisticLockScope.NORMAL; + return PessimisticLockScope.EXTENDED; + } +} 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 ae21aabbc..1a5ce88a5 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 @@ -31,15 +31,14 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.Stack; + import javax.persistence.CascadeType; import javax.persistence.GenerationType; +import javax.persistence.LockModeType; import static javax.persistence.CascadeType.*; import org.apache.commons.lang.StringUtils; -import org.xml.sax.Attributes; -import org.xml.sax.Locator; -import org.xml.sax.SAXException; import org.apache.openjpa.conf.OpenJPAConfiguration; import org.apache.openjpa.enhance.PersistenceCapable; import org.apache.openjpa.event.BeanLifecycleCallbacks; @@ -61,7 +60,6 @@ import org.apache.openjpa.meta.FieldMetaData; import org.apache.openjpa.meta.JavaTypes; import org.apache.openjpa.meta.LifecycleMetaData; import org.apache.openjpa.meta.MetaDataContext; -import org.apache.openjpa.meta.MetaDataDefaults; import org.apache.openjpa.meta.MetaDataFactory; import static org.apache.openjpa.meta.MetaDataModes.*; import org.apache.openjpa.meta.MetaDataRepository; @@ -73,6 +71,9 @@ import static org.apache.openjpa.persistence.MetaDataTag.*; import static org.apache.openjpa.persistence.PersistenceStrategy.*; import org.apache.openjpa.util.ImplHelper; import org.apache.openjpa.util.MetaDataException; +import org.xml.sax.Attributes; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; import serp.util.Numbers; @@ -1106,7 +1107,7 @@ public class XMLPersistenceMetaDataParser throws SAXException { FieldMetaData fmd = (FieldMetaData) currentElement(); int typeCode = fmd.isElementCollection() ? fmd.getElement().getDeclaredTypeCode() : fmd.getDeclaredTypeCode(); - Class type = fmd.isElementCollection() ? fmd.getElement().getDeclaredType() : fmd.getDeclaredType(); + Class type = fmd.isElementCollection() ? fmd.getElement().getDeclaredType() : fmd.getDeclaredType(); if (typeCode != JavaTypes.STRING && type != char[].class && type != Character[].class @@ -1651,12 +1652,10 @@ public class XMLPersistenceMetaDataParser meta.setDefiningType(_cls); meta.setQueryString(attrs.getValue("query")); meta.setLanguage(JPQLParser.LANG_JPQL); - /** TODO: Uncomment when orm.xsd defines lockmode - LockModeType lockMode = - LockModeType.valueOf(attrs.getValue("lockMode")); - meta.addHint("openjpa.FetchPlan.ReadLockMode", - JPA2LockLevels.toLockLevel(lockMode)); - **/ + String lockModeStr = attrs.getValue("lock-mode"); + if (lockModeStr != null) { + meta.addHint("openjpa.FetchPlan.ReadLockMode", LockModeType.valueOf(lockModeStr)); + } Locator locator = getLocation().getLocator(); if (locator != null) { meta.setLineNumber(Numbers.valueOf(locator.getLineNumber()));