JDBCとは
JDBC(Java Database Connectivity)は、Java言語でリレーショナルデータベースを操作するためのAPIセットです。JDBCは、MySQLやPostgreSQLなど、異なるデータベース間で共通のインターフェースを提供し、Javaアプリケーションからデータベースを操作する手段を統一しています。
このAPIはインターフェースで構成されており、各データベースベンダーが実装を提供します。これらの実装は通常、JDBCドライバとして知られるJARファイルに含まれています。
JDBCの基本的な使い方
以下はJDBCを使用してデータベースに接続し、SQLを実行する基本的な手順です。
// JDBCドライバをロード
Class.forName("com.mysql.cj.jdbc.Driver");
// データベース接続
String url = "jdbc:mysql://localhost:3306/sample_db";
String user = "root";
String password = "password";
Connection conn = DriverManager.getConnection(url, user, password);
// SQLステートメントを作成
Statement stmt = conn.createStatement();
String sql = "UPDATE accounts SET balance = 5000 WHERE id = 1";
int rowsAffected = stmt.executeUpdate(sql);
// 結果を出力
System.out.println(rowsAffected + "件更新しました");
// リソースを解放
stmt.close();
conn.close();
JDBC APIの主要コンポーネント
DriverManager
DriverManagerは、JDBCドライバを管理し、データベース接続を確立する役割を持っています。
registerDriver():JDBCドライバを登録getConnection():データベース接続を取得
MySQL 5以降では、JDBCドライバクラスを明示的にロードする必要がなくなりました。JDBCドライバのJARファイル内に、META-INF/services/java.sql.Driverというファイルがあり、そこにドライバクラス名が記載されています。
Connection
Connectionインターフェースは、データベースとの接続を表します。
createStatement():SQLを実行するためのStatementオブジェクトを生成prepareStatement():SQLインジェクション対策に有効なPreparedStatementを生成setAutoCommit():自動コミットを無効化し、トランザクション制御を行うcommit():トランザクションをコミットrollback():トランザクションをロールバック
トランザクション処理の例:
try {
connection.setAutoCommit(false); // トランザクション開始
Statement stmt = connection.createStatement();
stmt.executeUpdate("UPDATE accounts SET balance = 4000 WHERE id = 1");
stmt.executeUpdate("UPDATE accounts SET balance = 6000 WHERE id = 2");
connection.commit(); // コミット
} catch (SQLException e) {
connection.rollback(); // エラー時のロールバック
e.printStackTrace();
}
Statement
SQL文を実行するためのインターフェースです。
executeUpdate():INSERT、UPDATE、DELETEなどのDML文を実行executeQuery():SELECTなどのDQL文を実行し、ResultSetを返す
ResultSet
SELECT文の実行結果を格納するオブジェクトです。
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
System.out.println("ID: " + id + ", 名前: " + name);
}
PreparedStatement
SQLインジェクションを防ぐために、SQL文のプレースホルダに値を安全に設定できるインターフェースです。
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();
プレースホルダ(?)に値を設定する際には、setInt()、setString()などのメソッドを使用します。
データベース接続プールの概要
データベース接続プールは、アプリケーションがデータベースに頻繁に接続する場合に、接続の再利用を可能にする仕組みです。これにより、接続コストを削減し、パフォーマンスを向上させます。
標準インターフェース DataSource
JDBCでは、接続プールを管理するための標準インターフェースとしてDataSourceが定義されています。
getConnection():プールから接続を取得
代表的な接続プール実装
- Apache DBCP
- C3P0
- Alibaba Druid
Druidの使い方
Druidは、パフォーマンスと監視機能に優れた接続プール実装です。
設定ファイル(druid.properties):
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/sample_db
username=root
password=password
initialSize=5
maxActive=20
maxWait=3000
コード例:
Properties props = new Properties();
props.load(new FileInputStream("druid.properties"));
DataSource ds = DruidDataSourceFactory.createDataSource(props);
Connection conn = ds.getConnection();
System.out.println(conn);
CRUD操作の実装例
以下は、ブランド情報を管理するテーブルtb_brandに対する基本的なCRUD操作の実装例です。
全件取得
public List<Brand> selectAll() throws Exception {
Properties props = new Properties();
props.load(new FileInputStream("druid.properties"));
DataSource ds = DruidDataSourceFactory.createDataSource(props);
Connection conn = ds.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM tb_brand");
List<Brand> brands = new ArrayList<>();
while (rs.next()) {
Brand brand = new Brand();
brand.setId(rs.getInt("id"));
brand.setName(rs.getString("brand_name"));
brand.setCompany(rs.getString("company_name"));
brand.setOrder(rs.getInt("ordered"));
brand.setDescription(rs.getString("description"));
brand.setStatus(rs.getInt("status"));
brands.add(brand);
}
rs.close();
stmt.close();
conn.close();
return brands;
}
データ追加
public boolean insert(Brand brand) throws Exception {
Properties props = new Properties();
props.load(new FileInputStream("druid.properties"));
DataSource ds = DruidDataSourceFactory.createDataSource(props);
Connection conn = ds.getConnection();
PreparedStatement pstmt = conn.prepareStatement(
"INSERT INTO tb_brand (brand_name, company_name, ordered, description, status) VALUES (?, ?, ?, ?, ?)"
);
pstmt.setString(1, brand.getName());
pstmt.setString(2, brand.getCompany());
pstmt.setInt(3, brand.getOrder());
pstmt.setString(4, brand.getDescription());
pstmt.setInt(5, brand.getStatus());
int count = pstmt.executeUpdate();
pstmt.close();
conn.close();
return count > 0;
}
データ更新
public boolean update(Brand brand) throws Exception {
Properties props = new Properties();
props.load(new FileInputStream("druid.properties"));
DataSource ds = DruidDataSourceFactory.createDataSource(props);
Connection conn = ds.getConnection();
PreparedStatement pstmt = conn.prepareStatement(
"UPDATE tb_brand SET brand_name = ?, company_name = ?, ordered = ?, description = ?, status = ? WHERE id = ?"
);
pstmt.setString(1, brand.getName());
pstmt.setString(2, brand.getCompany());
pstmt.setInt(3, brand.getOrder());
pstmt.setString(4, brand.getDescription());
pstmt.setInt(5, brand.getStatus());
pstmt.setInt(6, brand.getId());
int count = pstmt.executeUpdate();
pstmt.close();
conn.close();
return count > 0;
}
データ削除
public boolean delete(int id) throws Exception {
Properties props = new Properties();
props.load(new FileInputStream("druid.properties"));
DataSource ds = DruidDataSourceFactory.createDataSource(props);
Connection conn = ds.getConnection();
PreparedStatement pstmt = conn.prepareStatement("DELETE FROM tb_brand WHERE id = ?");
pstmt.setInt(1, id);
int count = pstmt.executeUpdate();
pstmt.close();
conn.close();
return count > 0;
}