JdbcTemplateでSELECT文を実行してデータを取得する方法【初心者向けSQLとSpring JDBC解説】
新人
「データベースから情報を取り出すには、どんな方法がありますか?」
先輩
「まずはSELECT文というSQLを使って、データベースから必要なデータを取得するのが基本だよ。」
新人
「SELECT文ってどんな内容なんですか?書き方も知りたいです。」
先輩
「よし、それじゃあSELECT文の基本から説明して、JavaとSpringのJdbcTemplateを使ってどう実装するのか見ていこう!」
1. SELECT文とは何か
データベース操作において、最も基本的でよく使われるSQL文がSELECT文です。SELECT文は、テーブルに格納されているデータの中から、特定の条件に合ったデータを取り出すためのSQL(Structured Query Language)です。
例えば、社員情報を管理するテーブルがあったとして、社員全員の名前とメールアドレスを取得したい場合、次のようなSQLになります。
SELECT name, email FROM employees;
このようにSELECTのあとに取得したいカラム(列)名を指定し、FROMのあとに対象のテーブル名を書きます。また、条件を指定するにはWHERE句を使います。
たとえば部署が「営業部」の社員だけを取得したいときは、以下のように書きます。
SELECT name, email FROM employees WHERE department = '営業部';
SELECT文はとてもシンプルですが、SQLの基本となるので、まずはこの構文に慣れることが大切です。
2. Spring JDBCにおけるJdbcTemplateの役割とSELECT文の位置づけ
Javaでアプリケーションを開発する場合、データベースとのやりとりは不可欠です。Spring Frameworkでは、Spring JDBCというモジュールを使って、簡単にSQLを実行できます。
Spring JDBCの中心にあるのがJdbcTemplateです。JdbcTemplateは、SQLの実行や接続の管理、例外処理などを自動化してくれる非常に便利なクラスです。
通常、JDBCを使ってSQLを実行するには、接続の確立・PreparedStatementの作成・例外処理など、多くのコードが必要になります。しかし、SpringのJdbcTemplateを使えば、わずか数行でSELECT文の実行とデータの取得が可能です。
では、具体的にJdbcTemplateでSELECT文を使ってデータを取得するコードを見てみましょう。以下は、社員情報を取得してリストに格納する例です。
@Controller
public class EmployeeController {
private final JdbcTemplate jdbcTemplate;
public EmployeeController(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public List<Employee> getEmployeeList() {
String sql = "SELECT id, name, email FROM employees";
return jdbcTemplate.query(sql, (rs, rowNum) -> {
Employee emp = new Employee();
emp.setId(rs.getInt("id"));
emp.setName(rs.getString("name"));
emp.setEmail(rs.getString("email"));
return emp;
});
}
}
このコードでは、JdbcTemplateのqueryメソッドを使ってSQLを実行し、ResultSetからJavaのEmployeeオブジェクトを生成しています。ラムダ式でマッピング処理も簡潔に記述できます。
重要なのは、SQLのSELECT文をJavaコードに組み込むことで、データベースの情報をアプリケーションで自由に扱えるようになる点です。
このように、Spring JDBCとJdbcTemplateを組み合わせれば、SELECT文を安全・簡単に実行することができ、初心者でも迷わずデータ操作が行えます。
なお、上記のEmployeeクラスは以下のような内容になります。
public class Employee {
private int id;
private String name;
private String email;
// getterとsetterを記述
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
このように、POJO(Plain Old Java Object)クラスを使うことで、SQLのSELECT結果をJavaオブジェクトに簡単に変換できます。
3. JdbcTemplateのqueryメソッドの使い方
Spring JDBCを使ったSQL実行では、JdbcTemplateクラスのqueryメソッドが中心になります。このqueryメソッドは、SQLのSELECT文を実行して、データベースから取得した結果をJavaオブジェクトに変換するために使います。
初心者の方でも混乱しないように、まずqueryメソッドの基本形を見てみましょう。
List<T> query(String sql, RowMapper<T> rowMapper)
このように、queryメソッドはSQL文字列とRowMapperを引数に取り、SQLの実行結果をJavaのリストとして返します。RowMapperは、データベースの1行をどのようにJavaのオブジェクトに変換するかを定義するものです。
また、バインド変数(?)を使ってプレースホルダを設定し、動的に値を渡すこともできます。
List<T> query(String sql, Object[] args, RowMapper<T> rowMapper)
このように引数に配列を渡すことで、実行時に値を差し込むことができます。これはSQLインジェクション対策としても重要なポイントです。
4. 実際のSELECT文の例とデータ取得のサンプルコード
ここでは、実際のSELECT文をJdbcTemplateを使って実行するコード例を紹介します。社員テーブルから部署名が「開発部」の社員情報だけを取得する処理を考えてみましょう。
検索条件をつけて、特定の部署の社員だけを取り出すには、以下のように記述します。
@Controller
public class EmployeeController {
private final JdbcTemplate jdbcTemplate;
public EmployeeController(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public List<Employee> getDeveloperEmployees() {
String sql = "SELECT id, name, email FROM employees WHERE department = ?";
Object[] params = { "開発部" };
return jdbcTemplate.query(sql, params, (rs, rowNum) -> {
Employee emp = new Employee();
emp.setId(rs.getInt("id"));
emp.setName(rs.getString("name"));
emp.setEmail(rs.getString("email"));
return emp;
});
}
}
この例では、SQL文にWHERE department = ?というバインド変数を使い、実行時に"開発部"を渡しています。こうすることで、SQLの構造を変えずに動的な条件指定ができます。
SQLの実行部分はqueryメソッドを使っていて、実行結果の各行をEmployeeオブジェクトにマッピングしています。Javaのラムダ式を使うことで、コードを簡潔に記述できます。
このように、Spring JDBCではSQL実行と結果の取得をJdbcTemplateが効率よくサポートしてくれます。
5. RowMapperを使ったオブジェクトへのマッピング方法
先ほどの例では、JdbcTemplateのqueryメソッドの第3引数にラムダ式を直接記述していました。しかし、マッピング処理が複雑になる場合は、RowMapperをクラスとして分けることもできます。
ここでは、EmployeeRowMapperというクラスを作成して、オブジェクトへの変換処理を分離してみます。
public class EmployeeRowMapper implements RowMapper<Employee> {
@Override
public Employee mapRow(ResultSet rs, int rowNum) throws SQLException {
Employee emp = new Employee();
emp.setId(rs.getInt("id"));
emp.setName(rs.getString("name"));
emp.setEmail(rs.getString("email"));
return emp;
}
}
そしてコントローラのコードでは、EmployeeRowMapperを使って以下のように書き換えることができます。
@Controller
public class EmployeeController {
private final JdbcTemplate jdbcTemplate;
public EmployeeController(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public List<Employee> getEmployeesByDepartment(String dept) {
String sql = "SELECT id, name, email FROM employees WHERE department = ?";
Object[] params = { dept };
return jdbcTemplate.query(sql, params, new EmployeeRowMapper());
}
}
このように、RowMapperを使えばマッピング処理の再利用性も高まり、コードの見通しも良くなります。特に多くのテーブルやカラムに対応する場合は、この方法が推奨されます。
Spring JDBCでは、JdbcTemplateとRowMapperを組み合わせることで、SQLのSELECT文によって取得したデータを柔軟に扱えるようになります。初心者の方も、最初は簡単なラムダ式から始め、慣れてきたらクラス分離を試してみるとよいでしょう。
6. JdbcTemplateでよくあるSELECT時のエラーとその対処法
JdbcTemplateを使ってSELECT文を実行するとき、初心者がつまずきやすいポイントとして、SQLの構文ミスやマッピングの失敗、引数の不一致などがあります。ここでは、よくあるエラーとその対処法を紹介します。
まず最も多いのが、SQL構文エラーです。例えば、カラム名を間違えたり、WHERE句の条件にミスがあると、実行時に例外が発生します。
org.springframework.jdbc.BadSqlGrammarException:
PreparedStatementCallback; bad SQL grammar [SELECT idd, namee FROM employees];
nested exception is org.postgresql.util.PSQLException: ERROR: column "idd" does not exist
このようなエラーが出た場合は、カラム名やテーブル名のスペルをもう一度見直してください。データベースの構造と完全に一致している必要があります。
次に多いのが、Incorrect column countのようなマッピングエラーです。これはRowMapperで取得しようとしている列と、SELECT文で指定した列が一致していないときに起こります。
また、バインド変数(?)の数と、渡す引数の数が合っていない場合にもエラーになります。
org.springframework.dao.InvalidDataAccessApiUsageException:
PreparedStatementCallback; SQL [SELECT name FROM employees WHERE id = ? AND department = ?];
Invalid argument value: expected 2 parameters, but was given 1
このようなときは、Object[]の中に値をすべて揃えて渡しているかを確認しましょう。
もしエラー内容が難しく感じた場合は、ログを読みながら、どの部分で不一致があるのかを一つずつ丁寧に確認することが大切です。
7. JdbcTemplateで複数の条件を使ったSELECT文の書き方
JdbcTemplateを使ってSELECT文を実行する際、複数の条件を使いたいこともよくあります。たとえば、部署が「開発部」で、かつ役職が「マネージャー」の社員だけを取得したい場合です。
そのようなときは、WHERE句にANDを使って条件を複数指定します。
@Controller
public class EmployeeController {
private final JdbcTemplate jdbcTemplate;
public EmployeeController(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public List<Employee> getEmployeesByDeptAndRole(String dept, String role) {
String sql = "SELECT id, name, email FROM employees WHERE department = ? AND role = ?";
Object[] params = { dept, role };
return jdbcTemplate.query(sql, params, new EmployeeRowMapper());
}
}
このように、SELECT文に複数の条件を組み合わせて、絞り込みを細かく設定することができます。SQL文自体はシンプルですが、実際の業務システムではよく使われる形です。
また、必要に応じてORやBETWEEN、LIKEなどを組み合わせることで、柔軟な検索が可能になります。
初心者の方は、まずはANDやORの基本から慣れていき、徐々に応用へと進むのがおすすめです。
8. SELECT文の処理をサービス層やDAOに分けて再利用する方法
これまでのサンプルコードでは、すべての処理を@Controllerの中に直接書いていました。しかし、現実のプロジェクトでは、ロジックを役割ごとに分けて再利用できるように構成することが大切です。
よく使われる設計として、DAO(データアクセスオブジェクト)というクラスを作成して、SELECT文などのデータ取得処理をそこにまとめます。
@Repository
public class EmployeeDao {
private final JdbcTemplate jdbcTemplate;
public EmployeeDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public List<Employee> findByDepartment(String dept) {
String sql = "SELECT id, name, email FROM employees WHERE department = ?";
return jdbcTemplate.query(sql, new Object[]{dept}, new EmployeeRowMapper());
}
}
そして、@Service層では、このEmployeeDaoを呼び出してビジネスロジックを記述します。
@Service
public class EmployeeService {
private final EmployeeDao employeeDao;
public EmployeeService(EmployeeDao employeeDao) {
this.employeeDao = employeeDao;
}
public List<Employee> getEmployeesByDept(String dept) {
return employeeDao.findByDepartment(dept);
}
}
最後に@Controllerからは、EmployeeServiceを呼び出すだけにします。
@Controller
public class EmployeeController {
private final EmployeeService employeeService;
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
public List<Employee> showEmployees(String dept) {
return employeeService.getEmployeesByDept(dept);
}
}
このように処理をDAO層、Service層、Controller層に分けることで、SELECT文の実行処理が再利用しやすくなり、保守もしやすくなります。
Spring JDBCとJdbcTemplateの組み合わせに慣れてきたら、このような設計にも挑戦してみましょう。シンプルなコードでも、整理して構造化することで、開発全体の品質が大きく向上します。