ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
| この記事の要点 |
|---|
|
JdbcTemplate の役割
素の JDBC でクエリを実行する場合、Connection 取得・PreparedStatement 作成・ResultSet 処理・例外処理・リソース close を毎回書く必要があり、ボイラープレートが大量に発生します。
JdbcTemplate は Spring がこれらを肩代わりし、SQL 実行に集中できる API を提供します。
設定(Spring Boot)
Spring Boot なら spring-boot-starter-jdbc を依存に追加するだけで、DataSource と JdbcTemplate が自動設定されます。
# application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=user
spring.datasource.password=secret
spring.datasource.driver-class-name=org.postgresql.Driver
# Connection Pool (HikariCP がデフォルト)
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.connection-timeout=30000
@Repository
public class UserRepository {
private final JdbcTemplate jdbc;
public UserRepository(JdbcTemplate jdbc) { // 自動注入
this.jdbc = jdbc;
}
// ...
}
主要メソッド
① queryForObject - 単一レコード取得
// 単一カラム (count 等)
int count = jdbc.queryForObject("SELECT COUNT(*) FROM users", Integer.class);
// 単一レコード (RowMapper)
User user = jdbc.queryForObject(
"SELECT id, name, email FROM users WHERE id = ?",
(rs, rowNum) -> new User(
rs.getLong("id"),
rs.getString("name"),
rs.getString("email")
),
userId
);
// レコードが見つからないと EmptyResultDataAccessException
// 見つかってもよいなら Optional でラップ
public Optional findById(Long id) {
try {
User u = jdbc.queryForObject("SELECT ... WHERE id = ?", mapper, id);
return Optional.of(u);
} catch (EmptyResultDataAccessException e) {
return Optional.empty();
}
}
② query - 複数レコード取得
// RowMapper を使う場合
List users = jdbc.query(
"SELECT id, name, email FROM users WHERE status = ?",
(rs, rowNum) -> new User(
rs.getLong("id"),
rs.getString("name"),
rs.getString("email")
),
"ACTIVE"
);
// BeanPropertyRowMapper (フィールド名一致で自動マッピング)
List users = jdbc.query(
"SELECT id, name, email FROM users",
new BeanPropertyRowMapper<>(User.class)
);
③ queryForList - Map のリスト
// 各レコードを Map で取得
List
④ update - INSERT / UPDATE / DELETE
// 影響行数を返す
int rows = jdbc.update(
"UPDATE users SET name = ? WHERE id = ?",
"Alice",
1L
);
// INSERT で生成された ID を取得
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbc.update(connection -> {
PreparedStatement ps = connection.prepareStatement(
"INSERT INTO users (name, email) VALUES (?, ?)",
Statement.RETURN_GENERATED_KEYS
);
ps.setString(1, "Alice");
ps.setString(2, "alice@example.com");
return ps;
}, keyHolder);
Long newId = keyHolder.getKey().longValue();
⑤ batchUpdate - バッチ実行
List users = List.of(new User(1L,"Alice"), new User(2L,"Bob"));
int[] counts = jdbc.batchUpdate(
"INSERT INTO users (id, name) VALUES (?, ?)",
users,
100, // バッチサイズ
(ps, user) -> {
ps.setLong(1, user.getId());
ps.setString(2, user.getName());
}
);
NamedParameterJdbcTemplate(名前付きパラメータ)
引数が多いと ? の順番がわかりにくくなります。名前付きパラメータが便利:
@Repository
public class UserRepository {
private final NamedParameterJdbcTemplate jdbc;
public UserRepository(NamedParameterJdbcTemplate jdbc) {
this.jdbc = jdbc;
}
public List findByStatusAndRole(String status, String role) {
String sql = """
SELECT id, name FROM users
WHERE status = :status AND role = :role
""";
MapSqlParameterSource params = new MapSqlParameterSource()
.addValue("status", status)
.addValue("role", role);
return jdbc.query(sql, params, new BeanPropertyRowMapper<>(User.class));
}
public int insert(User user) {
String sql = "INSERT INTO users (name, email) VALUES (:name, :email)";
SqlParameterSource params = new BeanPropertySqlParameterSource(user);
return jdbc.update(sql, params);
}
}
SimpleJdbcInsert(INSERT 簡略化)
SimpleJdbcInsert insert = new SimpleJdbcInsert(jdbc)
.withTableName("users")
.usingGeneratedKeyColumns("id");
Map params = new HashMap<>();
params.put("name", "Alice");
params.put("email", "alice@example.com");
Number id = insert.executeAndReturnKey(params);
トランザクション
@Service
public class UserService {
private final UserRepository userRepository;
private final OrderRepository orderRepository;
@Transactional // メソッド内の DB 操作をひとつのトランザクションに
public void registerUser(User user, Order initialOrder) {
userRepository.insert(user);
orderRepository.insert(initialOrder);
// どちらかが失敗すれば両方ロールバック
}
@Transactional(readOnly = true) // 読み取り専用 (パフォーマンス最適化)
public User findById(Long id) {
return userRepository.findById(id);
}
}
例外処理
JdbcTemplate は SQLException を DataAccessException 階層に変換します(unchecked になる):
| 例外 | 意味 |
|---|---|
EmptyResultDataAccessException | queryForObject で結果が 0 件 |
IncorrectResultSizeDataAccessException | queryForObject で複数件 |
DuplicateKeyException | UNIQUE 制約違反 |
DataIntegrityViolationException | 制約違反 (NOT NULL, FK 等) |
DeadlockLoserDataAccessException | デッドロック |
QueryTimeoutException | タイムアウト |
BadSqlGrammarException | SQL 構文エラー |
JdbcTemplate vs JPA / MyBatis
| 項目 | JdbcTemplate | JPA / Hibernate | MyBatis |
|---|---|---|---|
| SQL を自分で書く | ○ 全部書く | △ 自動生成 + 一部 JPQL | ○ 全部書く(XML or アノテーション) |
| 学習コスト | 低 | 高 | 中 |
| パフォーマンスチューニング | 容易 | 注意が必要 (N+1 問題等) | 容易 |
| 複雑なクエリ | 得意 | 苦手 | 得意 |
| オブジェクト指向設計 | 弱い | 強い | 中 |
| 移行コスト (DB 変更) | 大 | 小 | 大 |
関連記事
ページの作成
親となるページを選択してください。
親ページに紐づくページを子ページといいます。
例: 親=スポーツ, 子1=サッカー, 子2=野球
子ページを親ページとして更に子ページを作成することも可能です。
例: 親=サッカー, 子=サッカーのルール
親ページはいつでも変更することが可能なのでとりあえず作ってみましょう!
子ページ
子ページはありません
同階層のページ
- インストール(eclipseプラグイン)
- クイックスタート
- プロジェクトの作成
- Spring Bootプロジェクトの作成
- Spring Bootプロジェクトの実行
- Spring BootでHello World!
- アノテーション一覧
- DB接続設定からエンティティおよびリポジトリの作成、値の取得まで(JPA編)
- DB接続設定や値の取得(JdbcTemplate編)
- ビューから値をモデルに格納しコントローラーで受け取る方法
- コントローラーにてモデルに値を格納してビューに渡す方法
- テンプレートエンジン
- ModelとModelAndViewの違い
- AOPの使用方法
- classpath: 内部ファイルの読み込み
- file: 外部ファイルの読み込み
- CSVファイルアップロード方法(Ajax)
- CSVファイルダウンロード方法(Ajax)
- Spring Bootプロジェクトのビルドと本番環境へのデプロイ方法(内部tomcat使用)
- Application.propertiesの環境依存設定の分割方法
- JPAにおけるEntityManagerの取得方法
- JPAにおけるjava.sql.Connectionの取得方法
- エラー一覧
- jarの引数を受け取る方法
- Spring BootでGmailからメール送信
- 複数のDBに接続する設定(Spring Boot & JPA編)
- ポート番号の変更
- Basic認証の実装と特定のURLに限定する方法
- Spring SecurityのBasic認証の無効化
- 独自のエラーページを定義する方法
- プロパティファイルの値やjar実行時の引数を取得する方法
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript base URL 取得方法|window.location.origin と SSR/Node.js 対応
- 4 YouTube Data API v3 エラー一覧|403/400/404 の主要原因と切り分け
- 5 Spring Frameworkのアノテーション一覧
- 6 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 7 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Laravel キャッシュクリア完全ガイド(cache:clear / config:clear / 2026-05-18 07:42:07
- プロジェクトの作成と削除 2026-05-18 07:42:07
- インストール直後にNetbeansが反応しない 2026-05-18 07:42:07
- 動画やチャンネルの検索 2026-05-18 07:42:07
- APIキー取得方法 2026-05-18 07:42:07
- チャンネル情報の取得 2026-05-18 07:42:07
- API 入門 — Web API(REST / GraphQL / gRPC / 2026-05-18 07:42:07
- インストール(eclipseプラグイン) 2026-05-18 07:42:07
- Laravel「Dotenv values containing spaces must be surrounded 2026-05-18 07:42:07
- エラー一覧 2026-05-18 07:42:07
- curl: (51) SSL: certificate subject name '~' does not match 2026-05-18 07:42:07
- インストール方法(Windows版) 2026-05-18 07:42:07
- JSONから配列に変換 2026-05-18 07:42:07
- 処理を一定時間待つ 2026-05-18 07:42:07
- A non well formed numeric value encountered 2026-05-18 07:42:07
コメントを削除してもよろしいでしょうか?