This is an automated email from the ASF dual-hosted git repository.
hsluoyz pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/casbin-jcasbin-jdbc-adapter.git
The following commit(s) were added to refs/heads/master by this push:
new 1a4b5da feat(close-connections): Add try-with-resources for
connections (#94)
1a4b5da is described below
commit 1a4b5dab84a5aab2bd8ef9c8aa87dd59692ba051
Author: Nipun Sharma <[email protected]>
AuthorDate: Sun Aug 2 20:05:42 2026 +0200
feat(close-connections): Add try-with-resources for connections (#94)
---
src/main/java/org/casbin/adapter/JDBCAdapter.java | 8 +-
.../java/org/casbin/adapter/JDBCBaseAdapter.java | 311 ++++++++++-----------
2 files changed, 153 insertions(+), 166 deletions(-)
diff --git a/src/main/java/org/casbin/adapter/JDBCAdapter.java
b/src/main/java/org/casbin/adapter/JDBCAdapter.java
index ba8847b..38705c2 100644
--- a/src/main/java/org/casbin/adapter/JDBCAdapter.java
+++ b/src/main/java/org/casbin/adapter/JDBCAdapter.java
@@ -124,11 +124,9 @@ public class JDBCAdapter extends JDBCBaseAdapter
implements FilteredAdapter {
*/
private void loadFilteredPolicyFile(Model model, Filter filter,
Helper.loadPolicyLineHandler<String, Model> handler) throws
CasbinAdapterException {
Failsafe.with(retryPolicy).run(ctx -> {
- if (ctx.isRetry()) {
- retry(ctx);
- }
- try (Statement stmt = conn.createStatement();
- ResultSet rSet = stmt.executeQuery(renderActualSql("SELECT *
FROM casbin_rule"))) {
+ try (Connection conn = dataSource.getConnection();
+ Statement stmt = conn.createStatement();
+ ResultSet rSet = stmt.executeQuery(renderActualSql("SELECT *
FROM casbin_rule"))) {
ResultSetMetaData rData = rSet.getMetaData();
while (rSet.next()) {
CasbinRule line = new CasbinRule();
diff --git a/src/main/java/org/casbin/adapter/JDBCBaseAdapter.java
b/src/main/java/org/casbin/adapter/JDBCBaseAdapter.java
index 5394133..9b828ea 100644
--- a/src/main/java/org/casbin/adapter/JDBCBaseAdapter.java
+++ b/src/main/java/org/casbin/adapter/JDBCBaseAdapter.java
@@ -14,7 +14,6 @@
package org.casbin.adapter;
-import dev.failsafe.ExecutionContext;
import dev.failsafe.Failsafe;
import dev.failsafe.RetryPolicy;
import org.apache.commons.collections4.CollectionUtils;
@@ -49,6 +48,10 @@ class CasbinRule {
/**
* JDBCAdapter is the JDBC adapter for jCasbin.
* It can load policy from JDBC supported database or save policy to it.
+ *
+ * <p>Connections are obtained from the DataSource per operation and released
immediately
+ * via try-with-resources. This enables connection pooling when a pooled
DataSource
+ * (e.g., HikariCP, Apache DBCP) is provided.</p>
*/
abstract class JDBCBaseAdapter implements Adapter, BatchAdapter,
UpdatableAdapter {
protected static final String DEFAULT_TABLE_NAME = "casbin_rule";
@@ -59,7 +62,6 @@ abstract class JDBCBaseAdapter implements Adapter,
BatchAdapter, UpdatableAdapte
protected String tableName;
protected boolean removePolicyFailed;
private final int batchSize = 1000;
- protected Connection conn;
protected RetryPolicy<Object> retryPolicy;
/**
@@ -96,55 +98,55 @@ abstract class JDBCBaseAdapter implements Adapter,
BatchAdapter, UpdatableAdapte
.withDelay(Duration.ofSeconds(1))
.withMaxRetries(_DEFAULT_CONNECTION_TRIES)
.build();
- conn = dataSource.getConnection();
if (autoCreateTable) {
migrate();
}
}
protected void migrate() throws SQLException {
- Statement stmt = conn.createStatement();
- String sql = renderActualSql("CREATE TABLE IF NOT EXISTS
casbin_rule(id int NOT NULL PRIMARY KEY auto_increment, ptype VARCHAR(100) NOT
NULL, v0 VARCHAR(100), v1 VARCHAR(100), v2 VARCHAR(100), v3 VARCHAR(100), v4
VARCHAR(100), v5 VARCHAR(100))");
- String productName = conn.getMetaData().getDatabaseProductName();
-
- switch (productName) {
- case "MySQL":
- String hasTableSql = renderActualSql("SHOW TABLES LIKE
'casbin_rule';");
- ResultSet rs = stmt.executeQuery(hasTableSql);
- if (rs.next()) {
- return;
- }
- break;
- case "Oracle":
- sql = renderActualSql("declare begin execute immediate 'CREATE
TABLE CASBIN_RULE(id NUMBER(5, 0) not NULL primary key, ptype VARCHAR(100) not
NULL, v0 VARCHAR(100), v1 VARCHAR(100), v2 VARCHAR(100), v3 VARCHAR(100), v4
VARCHAR(100), v5 VARCHAR(100))'; " +
+ try (Connection conn = dataSource.getConnection();
+ Statement stmt = conn.createStatement()) {
+ String sql = renderActualSql("CREATE TABLE IF NOT EXISTS
casbin_rule(id int NOT NULL PRIMARY KEY auto_increment, ptype VARCHAR(100) NOT
NULL, v0 VARCHAR(100), v1 VARCHAR(100), v2 VARCHAR(100), v3 VARCHAR(100), v4
VARCHAR(100), v5 VARCHAR(100))");
+ String productName = conn.getMetaData().getDatabaseProductName();
+
+ switch (productName) {
+ case "MySQL":
+ String hasTableSql = renderActualSql("SHOW TABLES LIKE
'casbin_rule';");
+ ResultSet rs = stmt.executeQuery(hasTableSql);
+ if (rs.next()) {
+ return;
+ }
+ break;
+ case "Oracle":
+ sql = renderActualSql("declare begin execute immediate
'CREATE TABLE CASBIN_RULE(id NUMBER(5, 0) not NULL primary key, ptype
VARCHAR(100) not NULL, v0 VARCHAR(100), v1 VARCHAR(100), v2 VARCHAR(100), v3
VARCHAR(100), v4 VARCHAR(100), v5 VARCHAR(100))'; " +
"exception when others then " +
"if SQLCODE = -955 then " +
"null; " +
"else raise; " +
"end if; " +
"end;");
- break;
- case "Microsoft SQL Server":
- sql = renderActualSql("IF NOT EXISTS (SELECT * FROM sysobjects
WHERE name='casbin_rule' and xtype='U') CREATE TABLE casbin_rule(id int NOT
NULL primary key identity(1, 1), ptype VARCHAR(100) NOT NULL, v0 VARCHAR(100),
v1 VARCHAR(100), v2 VARCHAR(100), v3 VARCHAR(100), v4 VARCHAR(100), v5
VARCHAR(100))");
- break;
- case "PostgreSQL":
- sql = renderActualSql("do $$ " +
+ break;
+ case "Microsoft SQL Server":
+ sql = renderActualSql("IF NOT EXISTS (SELECT * FROM
sysobjects WHERE name='casbin_rule' and xtype='U') CREATE TABLE casbin_rule(id
int NOT NULL primary key identity(1, 1), ptype VARCHAR(100) NOT NULL, v0
VARCHAR(100), v1 VARCHAR(100), v2 VARCHAR(100), v3 VARCHAR(100), v4
VARCHAR(100), v5 VARCHAR(100))");
+ break;
+ case "PostgreSQL":
+ sql = renderActualSql("do $$ " +
"BEGIN " +
"IF (select count(*) from information_schema.tables
where table_name = 'casbin_rule') = 0 " +
"THEN " +
- "CREATE SEQUENCE IF NOT EXISTS CASBIN_SEQUENCE START
1; "+
+ "CREATE SEQUENCE IF NOT EXISTS CASBIN_SEQUENCE START
1; " +
"END IF; " +
"END; " +
"$$;");
- break;
- case "H2":
- sql = renderActualSql("CREATE TABLE IF NOT EXISTS
casbin_rule(id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY, ptype VARCHAR(100)
NOT NULL, v0 VARCHAR(100), v1 VARCHAR(100), v2 VARCHAR(100), v3 VARCHAR(100),
v4 VARCHAR(100), v5 VARCHAR(100))");
- break;
- }
+ break;
+ case "H2":
+ sql = renderActualSql("CREATE TABLE IF NOT EXISTS
casbin_rule(id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY, ptype VARCHAR(100)
NOT NULL, v0 VARCHAR(100), v1 VARCHAR(100), v2 VARCHAR(100), v3 VARCHAR(100),
v4 VARCHAR(100), v5 VARCHAR(100))");
+ break;
+ }
- stmt.executeUpdate(sql);
- if ("Oracle".equals(productName)) {
- sql = renderActualSql("declare " +
+ stmt.executeUpdate(sql);
+ if ("Oracle".equals(productName)) {
+ sql = renderActualSql("declare " +
"V_NUM number;" +
"BEGIN " +
"V_NUM := 0; " +
@@ -154,8 +156,8 @@ abstract class JDBCBaseAdapter implements Adapter,
BatchAdapter, UpdatableAdapte
"else " +
"execute immediate 'CREATE SEQUENCE casbin_sequence
increment by 1 start with 1 nomaxvalue nocycle nocache';" +
"end if;END;");
- stmt.executeUpdate(sql);
- sql = renderActualSql("declare " +
+ stmt.executeUpdate(sql);
+ sql = renderActualSql("declare " +
"V_NUM number;" +
"BEGIN " +
"V_NUM := 0;" +
@@ -171,10 +173,11 @@ abstract class JDBCBaseAdapter implements Adapter,
BatchAdapter, UpdatableAdapte
" end;';" +
"end if;" +
"END;");
- stmt.executeUpdate(sql);
- } else if ("PostgreSQL".equals(productName)) {
- sql = renderActualSql("CREATE TABLE IF NOT EXISTS casbin_rule(id
int NOT NULL PRIMARY KEY default nextval('CASBIN_SEQUENCE'::regclass), ptype
VARCHAR(100) NOT NULL, v0 VARCHAR(100), v1 VARCHAR(100), v2 VARCHAR(100), v3
VARCHAR(100), v4 VARCHAR(100), v5 VARCHAR(100))");
- stmt.executeUpdate(sql);
+ stmt.executeUpdate(sql);
+ } else if ("PostgreSQL".equals(productName)) {
+ sql = renderActualSql("CREATE TABLE IF NOT EXISTS
casbin_rule(id int NOT NULL PRIMARY KEY default
nextval('CASBIN_SEQUENCE'::regclass), ptype VARCHAR(100) NOT NULL, v0
VARCHAR(100), v1 VARCHAR(100), v2 VARCHAR(100), v3 VARCHAR(100), v4
VARCHAR(100), v5 VARCHAR(100))");
+ stmt.executeUpdate(sql);
+ }
}
}
@@ -209,12 +212,9 @@ abstract class JDBCBaseAdapter implements Adapter,
BatchAdapter, UpdatableAdapte
@Override
public void loadPolicy(Model model) {
Failsafe.with(retryPolicy).run(ctx -> {
- if (ctx.isRetry()) {
- retry(ctx);
- }
- try (Statement stmt = conn.createStatement();
- ResultSet rSet = stmt.executeQuery(renderActualSql("SELECT
ptype,v0,v1,v2,v3,v4,v5 FROM casbin_rule"))) {
- ResultSetMetaData rData = rSet.getMetaData();
+ try (Connection conn = dataSource.getConnection();
+ Statement stmt = conn.createStatement();
+ ResultSet rSet = stmt.executeQuery(renderActualSql("SELECT
ptype,v0,v1,v2,v3,v4,v5 FROM casbin_rule"))) {
while (rSet.next()) {
CasbinRule line = new CasbinRule();
line.ptype = rSet.getObject(1) == null ? "" : (String)
rSet.getObject(1);
@@ -265,28 +265,25 @@ abstract class JDBCBaseAdapter implements Adapter,
BatchAdapter, UpdatableAdapte
String addSql = renderActualSql("INSERT INTO casbin_rule
(ptype,v0,v1,v2,v3,v4,v5) VALUES(?,?,?,?,?,?,?)");
Failsafe.with(retryPolicy).run(ctx -> {
- if (ctx.isRetry()) {
- retry(ctx);
- }
- conn.setAutoCommit(false);
+ try (Connection conn = dataSource.getConnection()) {
+ conn.setAutoCommit(false);
- int count = 0;
+ int count = 0;
- try (Statement statement = conn.createStatement();
PreparedStatement ps = conn.prepareStatement(addSql)) {
- statement.execute(cleanSql);
- count = saveSectionPolicyWithBatch(model, "p", ps, count);
- count = saveSectionPolicyWithBatch(model, "g", ps, count);
+ try (Statement statement = conn.createStatement();
PreparedStatement ps = conn.prepareStatement(addSql)) {
+ statement.execute(cleanSql);
+ count = saveSectionPolicyWithBatch(model, "p", ps, count);
+ count = saveSectionPolicyWithBatch(model, "g", ps, count);
- if (count != 0) {
- ps.executeBatch();
- }
+ if (count != 0) {
+ ps.executeBatch();
+ }
- conn.commit();
- } catch (SQLException e) {
- conn.rollback();
- throw e;
- } finally {
- conn.setAutoCommit(true);
+ conn.commit();
+ } catch (SQLException e) {
+ conn.rollback();
+ throw e;
+ }
}
});
}
@@ -344,38 +341,35 @@ abstract class JDBCBaseAdapter implements Adapter,
BatchAdapter, UpdatableAdapte
Failsafe.with(retryPolicy).run(ctx -> {
- if (ctx.isRetry()) {
- retry(ctx);
- }
- conn.setAutoCommit(false);
- int count = 0;
- try (PreparedStatement ps = conn.prepareStatement(sql)) {
- for (List<String> rule : rules) {
- CasbinRule line = savePolicyLine(ptype, rule);
-
- ps.setString(1, line.ptype);
- ps.setString(2, line.v0);
- ps.setString(3, line.v1);
- ps.setString(4, line.v2);
- ps.setString(5, line.v3);
- ps.setString(6, line.v4);
- ps.setString(7, line.v5);
- ps.addBatch();
- if (++count == batchSize) {
- count = 0;
+ try (Connection conn = dataSource.getConnection()) {
+ conn.setAutoCommit(false);
+ int count = 0;
+ try (PreparedStatement ps = conn.prepareStatement(sql)) {
+ for (List<String> rule : rules) {
+ CasbinRule line = savePolicyLine(ptype, rule);
+
+ ps.setString(1, line.ptype);
+ ps.setString(2, line.v0);
+ ps.setString(3, line.v1);
+ ps.setString(4, line.v2);
+ ps.setString(5, line.v3);
+ ps.setString(6, line.v4);
+ ps.setString(7, line.v5);
+ ps.addBatch();
+ if (++count == batchSize) {
+ count = 0;
+ ps.executeBatch();
+ ps.clearBatch();
+ }
+ }
+ if (count != 0) {
ps.executeBatch();
- ps.clearBatch();
}
+ conn.commit();
+ } catch (SQLException e) {
+ conn.rollback();
+ throw e;
}
- if (count != 0) {
- ps.executeBatch();
- }
- conn.commit();
- } catch (SQLException e) {
- conn.rollback();
- throw e;
- } finally {
- conn.setAutoCommit(true);
}
});
}
@@ -390,30 +384,36 @@ abstract class JDBCBaseAdapter implements Adapter,
BatchAdapter, UpdatableAdapte
}
Failsafe.with(retryPolicy).run(ctx -> {
- if (ctx.isRetry()) {
- retry(ctx);
- }
- String sql = renderActualSql("DELETE FROM casbin_rule WHERE ptype
= ?");
- int columnIndex = 0;
- for (int i = 0; i < rule.size(); i++) {
- sql = String.format("%s%s%s%s", sql, " AND v", columnIndex, "
= ?");
- columnIndex++;
+ try (Connection conn = dataSource.getConnection()) {
+ removePolicyWithConnection(conn, ptype, rule);
}
- while (columnIndex <= 5) {
- sql = String.format("%s%s%s%s", sql, " AND v", columnIndex, "
IS NULL");
- columnIndex++;
+ });
+ }
+
+ /**
+ * Internal method to remove a policy rule using a provided connection
(for transactional use).
+ */
+ private void removePolicyWithConnection(Connection conn, String ptype,
List<String> rule) throws SQLException {
+ String sql = renderActualSql("DELETE FROM casbin_rule WHERE ptype =
?");
+ int columnIndex = 0;
+ for (int i = 0; i < rule.size(); i++) {
+ sql = String.format("%s%s%s%s", sql, " AND v", columnIndex, " =
?");
+ columnIndex++;
+ }
+ while (columnIndex <= 5) {
+ sql = String.format("%s%s%s%s", sql, " AND v", columnIndex, " IS
NULL");
+ columnIndex++;
+ }
+ try (PreparedStatement ps = conn.prepareStatement(sql)) {
+ ps.setString(1, ptype);
+ for (int j = 0; j < rule.size(); j++) {
+ ps.setString(j + 2, rule.get(j));
}
- try (PreparedStatement ps = conn.prepareStatement(sql)) {
- ps.setString(1, ptype);
- for (int j = 0; j < rule.size(); j++) {
- ps.setString(j + 2, rule.get(j));
- }
- int rows = ps.executeUpdate();
- if (rows < 1 && removePolicyFailed) {
- throw new CasbinAdapterException(String.format("Remove
policy error, remove %d rows, expect least 1 rows", rows));
- }
+ int rows = ps.executeUpdate();
+ if (rows < 1 && removePolicyFailed) {
+ throw new CasbinAdapterException(String.format("Remove policy
error, remove %d rows, expect least 1 rows", rows));
}
- });
+ }
}
@Override
@@ -423,20 +423,17 @@ abstract class JDBCBaseAdapter implements Adapter,
BatchAdapter, UpdatableAdapte
}
Failsafe.with(retryPolicy).run(ctx -> {
- if (ctx.isRetry()) {
- retry(ctx);
- }
- conn.setAutoCommit(false);
- try {
- for (List<String> rule : rules) {
- removePolicy(sec, ptype, rule);
+ try (Connection conn = dataSource.getConnection()) {
+ conn.setAutoCommit(false);
+ try {
+ for (List<String> rule : rules) {
+ removePolicyWithConnection(conn, ptype, rule);
+ }
+ conn.commit();
+ } catch (SQLException e) {
+ conn.rollback();
+ throw e;
}
- conn.commit();
- } catch (SQLException e) {
- conn.rollback();
- throw e;
- } finally {
- conn.setAutoCommit(true);
}
});
}
@@ -452,16 +449,14 @@ abstract class JDBCBaseAdapter implements Adapter,
BatchAdapter, UpdatableAdapte
}
Failsafe.with(retryPolicy).run(ctx -> {
- if (ctx.isRetry()) {
- retry(ctx);
- }
String sql = renderActualSql("DELETE FROM casbin_rule WHERE ptype
= ?");
int columnIndex = fieldIndex;
for (int i = 0; i < values.size(); i++, columnIndex++) {
if (Objects.equals(values.get(i), "")) continue;
sql = String.format("%s%s%s%s", sql, " AND v", columnIndex, "
= ?");
}
- try (PreparedStatement ps = conn.prepareStatement(sql)) {
+ try (Connection conn = dataSource.getConnection();
+ PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, ptype);
int index = 2;
for (String value : values) {
@@ -489,45 +484,39 @@ abstract class JDBCBaseAdapter implements Adapter,
BatchAdapter, UpdatableAdapte
Failsafe.with(retryPolicy).run(ctx -> {
- if (ctx.isRetry()) {
- retry(ctx);
- }
- conn.setAutoCommit(false);
- removePolicy(sec, ptype, oldRule);
- try (PreparedStatement ps = conn.prepareStatement(sql)) {
- CasbinRule line = this.savePolicyLine(ptype, newRule);
-
- ps.setString(1, line.ptype);
- ps.setString(2, line.v0);
- ps.setString(3, line.v1);
- ps.setString(4, line.v2);
- ps.setString(5, line.v3);
- ps.setString(6, line.v4);
- ps.setString(7, line.v5);
- ps.executeUpdate();
- conn.commit();
- } catch (SQLException e) {
- conn.rollback();
- throw e;
- } finally {
- conn.setAutoCommit(true);
+ try (Connection conn = dataSource.getConnection()) {
+ conn.setAutoCommit(false);
+ try {
+ removePolicyWithConnection(conn, ptype, oldRule);
+ try (PreparedStatement ps = conn.prepareStatement(sql)) {
+ CasbinRule line = this.savePolicyLine(ptype, newRule);
+
+ ps.setString(1, line.ptype);
+ ps.setString(2, line.v0);
+ ps.setString(3, line.v1);
+ ps.setString(4, line.v2);
+ ps.setString(5, line.v3);
+ ps.setString(6, line.v4);
+ ps.setString(7, line.v5);
+ ps.executeUpdate();
+ }
+ conn.commit();
+ } catch (SQLException e) {
+ conn.rollback();
+ throw e;
+ }
}
});
}
/**
- * Close the Connection.
+ * Close the adapter. With connection-per-operation, this is a no-op.
+ * If the underlying DataSource is a pool (e.g., HikariCP), close it there.
+ *
+ * @deprecated Connections are no longer held; close the DataSource
directly if needed.
*/
public void close() throws SQLException {
- conn.close();
- }
-
- protected void retry(ExecutionContext<Void> ctx) throws SQLException {
- if (ctx.getExecutionCount() < _DEFAULT_CONNECTION_TRIES) {
- conn = dataSource.getConnection();
- } else {
- throw new Error(ctx.getLastFailure());
- }
+ // No-op: connections are obtained and released per operation.
}
protected String renderActualSql(String sql) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]