Abstract
Provisioning rules in SailPoint IdentityIQ (IIQ) often interact with multiple database tables to handle identity lifecycle tasks. Without proper transaction control and resource handling, such operations risk data corruption, race conditions, and resource leaks. This paper presents a structured approach to transaction management, database locking, and resource cleanup within SailPoint IIQ provisioning rules, implemented in Java. It demonstrates how to disable auto-commit, apply database-specific locking mechanisms, and ensure efficient cleanup of resources. The practices described here not only improve data integrity and system stability within SailPoint IIQ but also serve as reusable standards for any Java-based application managing multi-table operations.
Background
IdentityIQ provisioning rules extend SailPoint’s automation by allowing custom Java logic for account creation, updates, and removal. Frequently, these rules must update multiple database tables in a single logical transaction. However, challenges arise:
- Atomicity Risks – Without proper transaction handling, partial updates can corrupt sensitive identity data.
- Concurrency Issues – In high-load environments, simultaneous transactions may lead to race conditions or inconsistent states.
- Resource Leaks – Poor handling of connections and statements may exhaust the database connection pool, impacting availability.
Developers need a consistent framework for managing provisioning logic that ensures data consistency, prevents concurrency conflicts, and optimizes resource usage.
Objectives
The goals of this paper are:
- Transaction Integrity – Ensure all database operations are atomic using autoCommit=false, commit, and rollback strategies.
- Concurrency Control – Apply database-specific locking mechanisms to prevent race conditions.
- Resource Optimization – Guarantee proper cleanup of Connection, PreparedStatement, and ResultSet objects.
- Database-Specific Guidance – Provide locking examples for MySQL, Oracle, and SQL Server.
Reusable Java Pattern – Create a generalized transaction handler that can be applied in IIQ provisioning rules or standalone Java applications.
Technical Overview
1. Transaction Management
- Disable auto-commit (connection.setAutoCommit(false)), ensuring multiple table operations are treated as a single transaction.
- Commit once all operations succeed.
- Rollback immediately if any step fails.
2. Table Locking Mechanisms
Database locking is crucial for preventing concurrent updates to the same data.
MySQL
SELECT * FROM GenericTable WHERE status = 'Available' FOR UPDATE;
Locks rows until commit/rollback.
SQL Server
SELECT * FROM GenericTable WITH (UPDLOCK) WHERE status = 'Available';
Uses an update lock for row-level control.
Oracle
SELECT * FROM GenericTable WHERE status = 'Available' FOR UPDATE;
Similar to MySQL, applies row-level locks.
3. Resource Cleanup
Always close:
- ResultSet
- PreparedStatement
- Connection
This prevents memory leaks and ensures connections return to the pool.
Implementation Example
1. Step-by-Step Snippets
Establish Connection and Disable Auto-Commit
Connection connection = DriverManager.getConnection(dbUrl, dbUser, dbPassword);
connection.setAutoCommit(false); // Start transaction
With in Sailpoint IIQ you have the connection passed to the Rule
Lock Rows (MySQL Example)
String selectQuery = "SELECT * FROM GenericTable WHERE status = ? FOR UPDATE";
PreparedStatement selectStmt = connection.prepareStatement(selectQuery);
selectStmt.setString(1, "Available");
ResultSet rs = selectStmt.executeQuery();
Update Example
String updateQuery = "UPDATE GenericTable SET status = ? WHERE id = ?";
PreparedStatement updateStmt = connection.prepareStatement(updateQuery);
updateStmt.setString(1, "Processed");
updateStmt.setString(2, "12345");
updateStmt.executeUpdate();
Insert Example
String insertQuery = "INSERT INTO GenericTable (id, status) VALUES (?, ?)";
PreparedStatement insertStmt = connection.prepareStatement(insertQuery);
insertStmt.setString(1, "new_id");
insertStmt.setString(2, "Available");
insertStmt.executeUpdate();
Commit and Rollback
try {
connection.commit();
} catch (SQLException e) {
connection.rollback();
throw e;
}
Cleanup
if (rs != null) rs.close();
if (selectStmt != null) selectStmt.close();
if (updateStmt != null) updateStmt.close();
if (insertStmt != null) insertStmt.close();
if (connection != null) {
connection.setAutoCommit(true);
connection.close();
}
Complete Optimized Java Code
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class ProvisioningRuleHandler {
public void handleProvisioning(String dbUrl, String dbUser, String dbPassword) throws SQLException {
Connection connection = null;
PreparedStatement selectStmt = null;
PreparedStatement updateStmt = null;
PreparedStatement insertStmt = null;
ResultSet rs = null;
try {
// Establish connection
connection = DriverManager.getConnection(dbUrl, dbUser, dbPassword);
connection.setAutoCommit(false); // Start transaction
// Lock rows for processing
String selectQuery = "SELECT * FROM GenericTable WHERE status = ? FOR UPDATE";
selectStmt = connection.prepareStatement(selectQuery);
selectStmt.setString(1, "Available");
rs = selectStmt.executeQuery();
// Update locked rows
while (rs.next()) {
String id = rs.getString("id");
String updateQuery = "UPDATE GenericTable SET status = ? WHERE id = ?";
updateStmt = connection.prepareStatement(updateQuery);
updateStmt.setString(1, "Processed");
updateStmt.setString(2, id);
updateStmt.executeUpdate();
}
// Insert a new row
String insertQuery = "INSERT INTO GenericTable (id, status) VALUES (?, ?)";
insertStmt = connection.prepareStatement(insertQuery);
insertStmt.setString(1, "new_id");
insertStmt.setString(2, "Available");
insertStmt.executeUpdate();
// Commit transaction
connection.commit();
System.out.println("Provisioning operations completed successfully.");
} catch (SQLException e) {
if (connection != null) {
connection.rollback(); // Rollback on error
System.err.println("Transaction rolled back due to error: " + e.getMessage());
}
throw e;
} finally {
// Cleanup
if (rs != null) rs.close();
if (selectStmt != null) selectStmt.close();
if (updateStmt != null) updateStmt.close();
if (insertStmt != null) insertStmt.close();
if (connection != null) {
connection.setAutoCommit(true);
connection.close();
}
}
}
public static void main(String[] args) {
ProvisioningRuleHandler handler = new ProvisioningRuleHandler();
try {
handler.handleProvisioning("jdbc:mysql://localhost:3306/your_database", "your_username", "your_password");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
In SailPoint IIQ, the method can be invoked directly without the need to establish a separate class.
Benefits
1. Transaction Management
- Ensures atomicity (all or nothing).
- Provides consistent and reliable provisioning.
2. Table Locking
- Prevents race conditions in concurrent environments.
- Maintains data integrity during high-load operations.
3. Resource Cleanup
- Prevents memory leaks and connection pool exhaustion.
- Improves system stability and scalability.
Impact if Not Implemented
- Without Transactions: Data corruption due to partial updates.
- Without Locks: Race conditions leading to inconsistent identity states.
- Without Cleanup: Memory leaks, exhausted DB connections, and downtime.
Conclusion
Handling provisioning rules in SailPoint IIQ requires careful management of database operations. By adopting best practices in transaction management, applying database-specific locking strategies, and enforcing strict resource cleanup, developers can significantly improve the reliability and scalability of IIQ workflows.
The approach outlined in this paper provides:
- Consistency and integrity in multi-table operations.
- Robust concurrency control across MySQL, Oracle, and SQL Server.
- Reusable design patterns that apply both within SailPoint IIQ and broader Java applications.
Implementing these practices is essential for building a resilient identity management infrastructure capable of supporting enterprise-grade scalability and security.
Disclaimer
All code, concepts, and implementations presented in this paper are solely authored and owned by me. They are original contributions and do not contain, reference, or reuse any proprietary assets, intellectual property, or code from my current or past employers.
Got a thought or a different perspective? Drop it in the comments—I’d love to learn from you too! For a deeper discussion, feel free to connect with me at hemanthrajkb005@gmail.com
Top comments (0)