Java and databases with JDBC
Connection, SQL queries, CRUD, prepared statements and transactions with JDBC, with interactive examples.
Introduction to JDBC
JDBC (Java Database Connectivity) is a Java API that lets applications interact with databases using the SQL standard. You'll learn from basic connections to advanced transactions.
Connection
Establish and manage connections to different databases
Queries
Run SELECT, INSERT, UPDATE, DELETE
PreparedStatement
Parameterized queries to prevent SQL Injection
Transactions
Handling ACID: Atomicity, Consistency, Isolation, Durability
Connection Pool
Resource optimization in enterprise applications
JDBC Architecture
Java Application
Use JDBC API
Driver Manager
Manages JDBC drivers
Driver JDBC
Specific connector (MySQL, PostgreSQL, etc.)
Database
MySQL, Oracle, SQL Server, etc.
Common Drivers
mysql-connector-java
postgresql
ojdbc
mssql-jdbc
Establish Connection
Connection Simulator
// Ejemplo de conexión básicaimport java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConexionBD {
private static final String URL = "jdbc:mysql://localhost:3306/mi_base_datos";
private static final String USER = "root";
private static final String PASSWORD = "password123";
public Connection conectar() {
Connection conexion = null;
try {
// Cargar driver (opcional en JDBC 4.0+) Class.forName("com.mysql.cj.jdbc.Driver");
// Establecer conexión conexion = DriverManager.getConnection(URL, USER, PASSWORD);
if (conexion != null) {
System.out.println("✅ Conexión exitosa a MySQL");
}
} catch (ClassNotFoundException e) {
System.err.println("❌ Driver no encontrado: " + e.getMessage());
} catch (SQLException e) {
System.err.println("❌ Error de conexión: " + e.getMessage());
}
return conexion;
}
}
CRUD Operations
User Table Simulator
Table: usuarios
| ID | Name | Age | Actions |
|---|
Query Users
// Consultar todos los usuariospublic List obtenerUsuarios() {
List usuarios = new ArrayList<>();
String sql = "SELECT * FROM usuarios";
try (Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
Usuario usuario = new Usuario();
usuario.setId(rs.getInt("id"));
usuario.setNombre(rs.getString("nombre"));
usuario.setEmail(rs.getString("email"));
usuario.setEdad(rs.getInt("edad"));
usuarios.add(usuario);
}
} catch (SQLException e) {
e.printStackTrace();
}
return usuarios;
}
Insert New User
// Insertar un usuariopublic void insertarUsuario(Usuario usuario) {
String sql = "INSERT INTO usuarios (nombre, email, edad) VALUES (?, ?, ?)";
try (Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, usuario.getNombre());
pstmt.setString(2, usuario.getEmail());
pstmt.setInt(3, usuario.getEdad());
int filasAfectadas = pstmt.executeUpdate();
System.out.println("Filas insertadas: " + filasAfectadas);
} catch (SQLException e) {
e.printStackTrace();
}
}
Update User
// Actualizar usuariopublic void actualizarUsuario(int id, Usuario usuario) {
String sql = "UPDATE usuarios SET nombre = ?, email = ?, edad = ? WHERE id = ?";
try (Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, usuario.getNombre());
pstmt.setString(2, usuario.getEmail());
pstmt.setInt(3, usuario.getEdad());
pstmt.setInt(4, id);
int filasAfectadas = pstmt.executeUpdate();
System.out.println("Filas actualizadas: " + filasAfectadas);
} catch (SQLException e) {
e.printStackTrace();
}
}
Delete User
// Eliminar usuariopublic void eliminarUsuario(int id) {
String sql = "DELETE FROM usuarios WHERE id = ?";
try (Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, id);
int filasAfectadas = pstmt.executeUpdate();
if (filasAfectadas > 0) {
System.out.println("Usuario eliminado: ID " + id);
} else {
System.out.println("No se encontró usuario con ID " + id);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
PreparedStatement
SQL Injection Prevention
❌ VULNERABLE (Statement)
// ❌ VULNERABLE A SQL INJECTIONpublic boolean loginVulnerable(String usuario, String password) {
String sql = "SELECT * FROM usuarios WHERE username = '" + usuario +
"' AND password = '" + password + "'";
try (Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
return rs.next(); // Si encuentra usuario } catch (SQLException e) {
e.printStackTrace();
return false;
}
}
// Ejemplo de ataque:// usuario: admin' --
// password: (cualquier cosa)// SQL resultante: SELECT * FROM usuarios WHERE username = 'admin' --' AND password = ''
Injection Test
✅ SAFE (PreparedStatement)
// ✅ SEGURO CONTRA SQL INJECTIONpublic boolean loginSeguro(String usuario, String password) {
String sql = "SELECT * FROM usuarios WHERE username = ? AND password = ?";
try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
pstmt.setString(1, usuario); // Los parámetros se escapan automáticamente pstmt.setString(2, password);
try (ResultSet rs = pstmt.executeQuery()) {
return rs.next();
}
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
// Mismo ataque:// usuario: admin' --
// password: (cualquier cosa)// SQL resultante: SELECT * FROM usuarios WHERE username = 'admin'' --' AND password = ''
Automatic SQL Injection prevention
Better performance (precompilation)
Cleaner, more maintainable code
PreparedStatement Generator
Transactions
Banking Transactions Simulator
Bank Accounts
Make Transfer
✅ WITH TRANSACTION
// Transferencia con transacciónpublic boolean transferirConTransaccion(int origen, int destino, double monto) {
Connection conn = null;
try {
conn = getConnection();
conn.setAutoCommit(false); // Iniciar transacción
// 1. Retirar de cuenta origen String sqlRetiro = "UPDATE cuentas SET saldo = saldo - ? WHERE id = ? AND saldo >= ?";
try (PreparedStatement pstmt = conn.prepareStatement(sqlRetiro)) {
pstmt.setDouble(1, monto);
pstmt.setInt(2, origen);
pstmt.setDouble(3, monto);
int filas = pstmt.executeUpdate();
if (filas == 0) {
conn.rollback();
return false; // Saldo insuficiente }
}
// 2. Depositar en cuenta destino String sqlDeposito = "UPDATE cuentas SET saldo = saldo + ? WHERE id = ?";
try (PreparedStatement pstmt = conn.prepareStatement(sqlDeposito)) {
pstmt.setDouble(1, monto);
pstmt.setInt(2, destino);
pstmt.executeUpdate();
}
conn.commit(); // Confirmar transacción return true;
} catch (SQLException e) {
if (conn != null) {
try { conn.rollback(); } catch (SQLException ex) {}
}
e.printStackTrace();
return false;
} finally {
if (conn != null) {
try { conn.setAutoCommit(true); conn.close(); } catch (SQLException e) {}
}
}
}
❌ WITHOUT TRANSACTION
// Transferencia sin transacción - PELIGROSOpublic boolean transferirSinTransaccion(int origen, int destino, double monto) {
try (Connection conn = getConnection()) {
conn.setAutoCommit(true); // Cada SQL es independiente
// 1. Retirar de cuenta origen String sqlRetiro = "UPDATE cuentas SET saldo = saldo - ? WHERE id = ? AND saldo >= ?";
try (PreparedStatement pstmt = conn.prepareStatement(sqlRetiro)) {
pstmt.setDouble(1, monto);
pstmt.setInt(2, origen);
pstmt.setDouble(3, monto);
int filas = pstmt.executeUpdate();
if (filas == 0) {
return false; // Saldo insuficiente }
}
// ⚠️ Si hay un error aquí, el dinero ya se retiró pero no se depositó // ⚠️ Resultado: Dinero perdido en el limbo
// 2. Depositar en cuenta destino String sqlDeposito = "UPDATE cuentas SET saldo = saldo + ? WHERE id = ?";
try (PreparedStatement pstmt = conn.prepareStatement(sqlDeposito)) {
pstmt.setDouble(1, monto);
pstmt.setInt(2, destino);
pstmt.executeUpdate();
}
return true;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
Connection Pool
Resource Optimization
Connection Pool (HikariCP)
Application
Settings HikariCP
// HikariCP Settingsimport com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
public class DatabaseConfig {
private static HikariDataSource dataSource;
static {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mi_base_datos");
config.setUsername("root");
config.setPassword("password123");
// Configuración del pool config.setMaximumPoolSize(20);
config.setMinimumIdle(10);
config.setConnectionTimeout(30000); // 30 seconds config.setIdleTimeout(600000); // 10 minutos config.setMaxLifetime(1800000); // 30 minutos config.setConnectionTestQuery("SELECT 1");
dataSource = new HikariDataSource(config);
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public static void closeDataSource() {
if (dataSource != null && !dataSource.isClosed()) {
dataSource.close();
}
}
}
Advantages of the Connection Pool
Performance
Reuse of existing connections instead of creating new ones
Scalability
Efficient handling of multiple concurrent requests
Stability
Prevention of database connection exhaustion
Management
Centralized configuration of connection parameters
Practical Exercises
User Management System
Create a complete CRUD system for user management with:
- MySQL/PostgreSQL database connection
- CRUD Operations with PreparedStatement
- Data validation and exception handling
- Advanced search and filtering
- CSV export
Sales System
Implement a sales system with transactions:
- Related tables: productos, clientes, ventas, detalles
- Transactions for sales (ACID)
- Concurrent inventory handling
- Reports with complex JOINs
- Automatic data backup
Data Analysis System
Develop a system for analyzing large volumes of data:
- Connection pool with HikariCP
- Batch processing
- Optimized queries with indexes
- Connection handling in web applications
- Performance monitoring
Code Editor
Summary and Resources
What You Learned in This Module
Database Connection
- DriverManager to establish connections
- URL, username and password configuration
- SQLException exception handling
- Proper resource closing
CRUD Operations
- Statement for simple queries
- ResultSet to process results
- executeQuery() for SELECT
- executeUpdate() for INSERT/UPDATE/DELETE
PreparedStatement
- Prevention of SQL Injection
- Better performance from precompilation
- setXXX() methods for parameters
- Query reuse
Transactions
- setAutoCommit(false)
- commit() and rollback()
- ACID Properties
- Error handling in transactions
Connection Pool
- Resource optimization
- HikariCP as the standard solution
- Parameter configuration
- Handling in web applications
Download Resources
Knowledge Assessment
Check what you've learned with our interactive quiz