From 3f85fb95cd7ba498eca4d95314a419e05411f1b8 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Sun, 15 Jul 2012 15:08:12 +0200 Subject: [PATCH] [#1547] Support "optimistic locking" in UpdatableRecord.storeLocked() - Added UpdatableRecord.deleteLocked() --- .../org/jooq/test/_/testcases/CRUDTests.java | 20 ++++++++- jOOQ/src/main/java/org/jooq/TableRecord.java | 42 ++++++++++++++++++- .../main/java/org/jooq/UpdatableRecord.java | 42 +++++++++++++++++-- .../java/org/jooq/impl/TableRecordImpl.java | 20 ++++++++- .../org/jooq/impl/UpdatableRecordImpl.java | 7 ++++ 5 files changed, 122 insertions(+), 9 deletions(-) diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/CRUDTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/CRUDTests.java index 7912f7550f..4770f6370d 100644 --- a/jOOQ-test/src/org/jooq/test/_/testcases/CRUDTests.java +++ b/jOOQ-test/src/org/jooq/test/_/testcases/CRUDTests.java @@ -633,7 +633,7 @@ extends BaseTest> extends Record { * Store this record back to the database assuming an optimistic lock. *

* This performs the same action as {@link #storeUsing(TableField...)}, - * except that if an UPDATE is performed, this record will be - * compared with the latest state in the database. + * except that if an UPDATE is performed, this record will + * first be compared with the latest state in the database. *

* Note that in order to compare this record with the latest state, the * database record will be locked pessimistically using a @@ -165,6 +165,44 @@ public interface TableRecord> extends Record { */ int deleteUsing(TableField... keys) throws DataAccessException; + /** + * Deletes this record from the database assuming an optimistic lock. + *

+ * This performs the same action as {@link #deleteUsing(TableField...)}, + * except that this record will first be compared with the latest state in + * the database. + *

+ * Note that in order to compare this record with the latest state, the + * database record will be locked pessimistically using a + * SELECT .. FOR UPDATE statement. Not all databases support + * the FOR UPDATE clause natively. Namely, the following + * databases will show slightly different behaviour: + *

+ *

+ * See {@link LockProvider#setForUpdate(boolean)} for more details + *

+ * Unlike {@link #deleteUsing(TableField...)}, this will fail if several + * records are concerned. + * + * @param keys The key fields for the DELETE statement's + * WHERE clause. + * @return The number of deleted records. + * @throws DataAccessException if something went wrong executing the query + * @throws DataChangedException if the record has already been changed in + * the database + * @see #deleteUsing(TableField...) + * @see LockProvider#setForUpdate(boolean) + */ + int deleteLockedUsing(TableField... keys) throws DataAccessException, DataChangedException; + /** * Refresh this record from the database, based on the value of the provided * keys. diff --git a/jOOQ/src/main/java/org/jooq/UpdatableRecord.java b/jOOQ/src/main/java/org/jooq/UpdatableRecord.java index ea3f49a901..249c69ee8d 100644 --- a/jOOQ/src/main/java/org/jooq/UpdatableRecord.java +++ b/jOOQ/src/main/java/org/jooq/UpdatableRecord.java @@ -140,8 +140,8 @@ public interface UpdatableRecord> extends Updatable * Store this record back to the database assuming an optimistic lock. *

* This performs the same action as {@link #store()}, except that if an - * UPDATE is performed, this record will be compared with the - * latest state in the database. + * UPDATE is performed, this record will first be compared with + * the latest state in the database. *

* Note that in order to compare this record with the latest state, the * database record will be locked pessimistically using a @@ -163,8 +163,8 @@ public interface UpdatableRecord> extends Updatable * @return 1 if the record was stored to the database. 0 * if storing was not necessary. * @throws DataAccessException if something went wrong executing the query - * @throws DataChangedException if the record has already been changed in - * the database + * @throws DataChangedException if the record has already been + * changed/deleted in the database * @see #store() * @see #storeLockedUsing(TableField...) * @see LockProvider#setForUpdate(boolean) @@ -189,6 +189,40 @@ public interface UpdatableRecord> extends Updatable */ int delete() throws DataAccessException; + /** + * Deletes this record from the database assuming an optimistic lock. + *

+ * This performs the same action as {@link #delete()}, except that this + * record will first be compared with the latest state in the database. + *

+ * Note that in order to compare this record with the latest state, the + * database record will be locked pessimistically using a + * SELECT .. FOR UPDATE statement. Not all databases support + * the FOR UPDATE clause natively. Namely, the following + * databases will show slightly different behaviour: + *

+ *

+ * See {@link LockProvider#setForUpdate(boolean)} for more details + * + * @return 1 if the record was deleted from the database. + * 0 if deletion was not necessary. + * @throws DataAccessException if something went wrong executing the query + * @throws DataChangedException if the record has already been + * changed/deleted in the database + * @see #delete() + * @see #deleteUsing(TableField...) + * @see LockProvider#setForUpdate(boolean) + */ + int deleteLocked() throws DataAccessException, DataChangedException; + /** * Refresh this record from the database, based on the value of the primary * key or main unique key. diff --git a/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java b/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java index 497ae6e271..3b472856c3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java @@ -101,7 +101,7 @@ public class TableRecordImpl> extends TypeRecord[] keys, boolean checkLocked) { + private final int storeUsing0(TableField[] keys, boolean checkIfChanged) { boolean executeUpdate = false; for (TableField field : keys) { @@ -121,7 +121,7 @@ public class TableRecordImpl> extends TypeRecord> extends TypeRecord... keys) { + return deleteUsing0(keys, false); + } + + @Override + public final int deleteLockedUsing(TableField... keys) { + return deleteUsing0(keys, true); + } + + private int deleteUsing0(TableField[] keys, boolean checkIfChanged) { try { DeleteQuery delete = create().deleteQuery(getTable()); @@ -244,6 +253,13 @@ public class TableRecordImpl> extends TypeRecord> extends TableReco return deleteUsing(getMainKey().getFieldsArray()); } + @Override + public final int deleteLocked() throws DataAccessException, DataChangedException { + return deleteLockedUsing(getMainKey().getFieldsArray()); + } + @Override public final void refresh() { refreshUsing(getMainKey().getFieldsArray());