Dive into connection pooling, batch processing, and more to build scalable, high-performance applications.
Table of Contents
Why Go Beyond Basics?
While basic CRUD operations work for small apps, advanced JDBC techniques unlock:
- Scalability: Handle thousands of requests efficiently.
- Performance: Optimize bulk operations and resource usage.
- Flexibility: Work with complex data types and workflows.
Let’s explore these powerful features.
1. Connection Pooling with HikariCP
Problem: Opening/closing connections for every request is slow and resource-heavy.
Solution: Connection pools reuse existing connections, reducing overhead.
HikariCP Setup
Add the dependency (Maven):
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.0.1</version>
</dependency>
Configure and Use the Pool:
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/student_db");
config.setUsername("root");
config.setPassword("root123");
config.setMaximumPoolSize(10); // Adjust based on workload
try (HikariDataSource dataSource = new HikariDataSource(config);
Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement("...")) {
// Use the connection
}
Benefits:
- Faster connection reuse.
- Configurable pool size and timeouts.
2. Batch Processing for Bulk Operations
Problem: Inserting 10,000 rows one-by-one is slow.
Solution: Batch operations reduce roundtrips to the database.
Batch Insert Example
String sql = "INSERT INTO logs (message) VALUES (?)";
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
for (String message : messages) {
pstmt.setString(1, message);
pstmt.addBatch(); // Add to batch
}
int[] results = pstmt.executeBatch(); // Execute all at once
System.out.println("Inserted " + results.length + " rows.");
}
Best Practices:
- Limit batch size (e.g., 100–1,000 per batch).
- Use
rewriteBatchedStatements=true
in MySQL URL for 10x speed gains.
3. Handling BLOB and CLOB Data
BLOB (Binary Large Object): Stores files like images or PDFs.
CLOB (Character Large Object): Stores large text (e.g., JSON, XML).
Saving an Image (BLOB)
String sql = "UPDATE users SET profile_pic = ? WHERE id = ?";
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
File imageFile = new File("path/to/image.jpg");
try (FileInputStream fis = new FileInputStream(imageFile)) {
pstmt.setBinaryStream(1, fis, (int) imageFile.length());
pstmt.setInt(2, userId);
pstmt.executeUpdate();
}
}
Reading a CLOB
try (ResultSet rs = pstmt.executeQuery()) {
if (rs.next()) {
Clob descriptionClob = rs.getClob("description");
String description = descriptionClob.getSubString(1, (int) descriptionClob.length());
}
}
Use Cases:
- User uploads (images, documents).
- Storing large text configurations.
4. Calling Stored Procedures with CallableStatement
Problem: Complex business logic in Java can be moved to the database.
Solution: Use CallableStatement
to execute stored procedures.
Example
-- Create a stored procedure in MySQL
DELIMITER $$
CREATE PROCEDURE get_student_by_id(IN student_id INT)
BEGIN
SELECT * FROM students WHERE id = student_id;
END$$
DELIMITER ;
Java Code:
String sql = "{CALL get_student_by_id(?)}";
try (Connection conn = dataSource.getConnection();
CallableStatement cstmt = conn.prepareCall(sql)) {
cstmt.setInt(1, 101); // Set input parameter
try (ResultSet rs = cstmt.executeQuery()) {
while (rs.next()) {
// Process student data
}
}
}
5. Savepoints for Partial Rollbacks
Problem: Rolling back an entire transaction discards valid work.
Solution: Savepoints allow partial rollbacks within a transaction.
conn.setAutoCommit(false);
try (Statement stmt = conn.createStatement()) {
stmt.executeUpdate("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
Savepoint savepoint = conn.setSavepoint("SAVEPOINT_1");
stmt.executeUpdate("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
conn.commit();
} catch (SQLException e) {
conn.rollback(savepoint); // Undo only the second update
conn.commit();
}
6. Best Practices for Advanced JDBC
- Monitor Connection Pools: Avoid overloading the database.
- Stream BLOB/CLOB Data: Don’t load large files entirely into memory.
- Use Batch Processing Judiciously: Balance batch size and memory usage.
- Log Stored Procedures: Ensure they’re optimized and indexed.
Summary
- Connection Pooling: Essential for high-traffic apps.
- Batch Processing: Accelerates bulk data operations.
- BLOB/CLOB: Handle large data efficiently.
- Stored Procedures: Offload logic to the database when needed.
Next Up: Troubleshooting Common JDBC Issues – Learn to debug connection leaks, timeouts, and more!