Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public class DLockConfig {
public KeyLock keyLock(DataSource dataSource) {
return new JDBCKeyLockBuilder()
.dataSource(dataSource)
.databaseType(DatabaseType.H2) // or ORACLE
.databaseType(DatabaseType.H2) // or ORACLE, POSTGRESQL
.createDatabase(true) // Automatically creates the DLCK table
.build();
}
Expand Down Expand Up @@ -199,7 +199,7 @@ When using the `KeyLock` API, keep the following constraints in mind:

* [**dlock-api**](./dlock-api): Core interfaces (`KeyLock`, `LockHandle`).
* [**dlock-core**](./dlock-core): Base implementation logic (expiration policies, utilities).
* [**dlock-jdbc**](./dlock-jdbc): JDBC implementation (H2, Oracle support).
* [**dlock-jdbc**](./dlock-jdbc): JDBC implementation (H2, Oracle, PostgreSQL support).
* [**dlock-spring**](./dlock-spring): Spring integration (`@Lock` aspect).

```mermaid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ public JDBCKeyLockBuilder databaseType(DatabaseType databaseType) {
}

public JDBCKeyLockBuilder lockTableName(String lockTableName) {
if (lockTableName == null || !lockTableName.matches("^[a-zA-Z0-9_]+$")) {
throw new IllegalArgumentException("Table name must only contain alphanumeric characters and underscores");
}
this.lockTableName = lockTableName;
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ public class JDBCLockRepository implements LockRepository {
private final String findByHandleSQL;
private final String findByKeySQL;
private final String removeByHandleSQL;
private final int insertParamsCount;

public JDBCLockRepository(ScriptResolver scriptResolver, DataSource dataSource) {
this.dataSource = dataSource;
this.insertSQL = scriptResolver.resolveScript("lock.insert");
this.findByHandleSQL = scriptResolver.resolveScript("lock.findByHandle");
this.findByKeySQL = scriptResolver.resolveScript("lock.findByKey");
this.removeByHandleSQL = scriptResolver.resolveScript("lock.removeByHandle");
this.insertParamsCount = countOccurrences(insertSQL, '?');
}

@Override
Expand Down Expand Up @@ -134,12 +136,19 @@ private boolean executeInsert(Connection connection, WriteLockRecord lockRecord)
ps.setString(2, lockRecord.lockHandleId());

ps.setLong(3, lockRecord.expirationSeconds());
ps.setString(4, lockRecord.lockKey());

if (insertParamsCount == 4) {
ps.setString(4, lockRecord.lockKey());
}

return ps.executeUpdate() == 1;
}
}

private int countOccurrences(String str, char ch) {
return (int) str.chars().filter(c -> c == ch).count();
}

/** Delete SQL PreparedStatement. */
private boolean executeRemove(Connection connection, String lockHandleId) throws SQLException {
try (PreparedStatement ps = connection.prepareStatement(removeByHandleSQL)) {
Expand Down
8 changes: 4 additions & 4 deletions dlock-jdbc/src/main/resources/db/POSTGRESQL-sql.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
lock.findByKey=SELECT "LCK_KEY", "LCK_HNDL_ID", "CREATED_TIME", "EXPIRE_SEC", CURRENT_TIMESTAMP FROM "@@tableName@@" WHERE "LCK_KEY" = ?
lock.findByHandle=SELECT "LCK_KEY", "LCK_HNDL_ID", "CREATED_TIME", "EXPIRE_SEC", CURRENT_TIMESTAMP FROM "@@tableName@@" WHERE "LCK_HNDL_ID" = ?
lock.insert=INSERT INTO "@@tableName@@" ("LCK_KEY", "LCK_HNDL_ID", "CREATED_TIME", "EXPIRE_SEC") SELECT ?, ?, CURRENT_TIMESTAMP, ? WHERE NOT EXISTS (SELECT 1 FROM "@@tableName@@" WHERE "LCK_KEY" = ?)
lock.removeByHandle=DELETE FROM "@@tableName@@" WHERE "LCK_HNDL_ID" = ?
lock.findByKey=SELECT "LCK_KEY", "LCK_HNDL_ID", "CREATED_TIME", "EXPIRE_SEC", CURRENT_TIMESTAMP FROM "@@tableName@@" WHERE "LCK_KEY" = ?
lock.findByHandle=SELECT "LCK_KEY", "LCK_HNDL_ID", "CREATED_TIME", "EXPIRE_SEC", CURRENT_TIMESTAMP FROM "@@tableName@@" WHERE "LCK_HNDL_ID" = ?
lock.insert=INSERT INTO "@@tableName@@" ("LCK_KEY", "LCK_HNDL_ID", "CREATED_TIME", "EXPIRE_SEC") VALUES (?, ?, CURRENT_TIMESTAMP, ?) ON CONFLICT ("LCK_KEY") DO NOTHING
lock.removeByHandle=DELETE FROM "@@tableName@@" WHERE "LCK_HNDL_ID" = ?
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.dlock.jdbc.builder

import spock.lang.Specification
import spock.lang.Unroll

class JDBCKeyLockBuilderTest extends Specification {

@Unroll
def "should accept valid lockTableName: #tableName"() {
given:
def builder = new JDBCKeyLockBuilder()

when:
builder.lockTableName(tableName)

then:
noExceptionThrown()

where:
tableName << ["DLCK", "MyTable_1", "My_Table"]
}

@Unroll
def "should reject invalid lockTableName: #tableName"() {
given:
def builder = new JDBCKeyLockBuilder()

when:
builder.lockTableName(tableName)

then:
thrown(IllegalArgumentException)

where:
tableName << ["My-Table", "My.Table", "My Table", "DROP TABLE", ""]
}

def "should reject null lockTableName"() {
given:
def builder = new JDBCKeyLockBuilder()

when:
builder.lockTableName(null)

then:
thrown(IllegalArgumentException)
}
}
2 changes: 1 addition & 1 deletion dlock-spring/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class DLockConfig {
public KeyLock keyLock(DataSource dataSource) {
return new JDBCKeyLockBuilder()
.dataSource(dataSource)
.databaseType(DatabaseType.H2)
.databaseType(DatabaseType.H2) // or POSTGRESQL, ORACLE
.build();
}
}
Expand Down