JdbcTemplateでQueryを書く方法です!
(SELECT文で、1件・複数件を取得するケース)
前提
以下のテーブル(users)を持ち、格納するのはUserクラスという想定で説明していきます。
usersテーブル
1 2 3 4 5 6 7 8 9 |
CREATE TABLE IF NOT EXISTS users ( id VARCHAR(50) PRIMARY KEY ,password VARCHAR(100) ,name VARCHAR(50) ,birthday DATE ,age INT ,marrige BOOLEAN ,role VARCHAR(50) ); |
Userクラス
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import java.util.Date; import lombok.Data; // setter/getterを付けるアノテーション @Data public class User { private String id; private String password; private String name; private Date birthday; private int age; private boolean marrige; private String role; // Default Constructor public User() { } public User(String id, String password, String name, Date birthday, int age, boolean marrige, String role){ this.id = id; this.password = password; this.name = name; this.birthday = birthday; this.age = age; this.marrige = marrige; this.role = role; } } |
データの取得
1件のみと複数件を取得するケースで説明します。
Mapで取得する方法
1件のみ取得
Map<String, Object>の形でQuery結果を取得する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; public class UserDao { @Autowired JdbcTemplate jdbcTemplate; public User selectOne(String id) throws DataAccessException { // SQL文を作成 String sql = "" + "SELECT" + " *" + " FROM" + " users" + " WHERE" + " id = ?"; // queryForMapメソッドでSQLを実行し、結果MapのListで受け取る。 // SQL文の ? の部分に当てはめる値を一緒に与える。 Map<String, Object> oneUser = jdbcTemplate.queryForMap(sql, id); // Userオブジェクトに格納する。 User user = new User( (String) oneUser.get("id") ,(String) oneUser.get("password") ,(String) oneUser.get("name") ,(Date) oneUser.get("birthday") ,((Integer) oneUser.get("age")).intValue() ,(Boolean) oneUser.get("marrige") ,(String) oneUser.get("role") ); return user; } } |
複数件を取得
List<Map<String,Object>>でQuery結果を取得する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; public class UserDao { @Autowired JdbcTemplate jdbcTemplate; public List<User> selectMany() throws DataAccessException { // SQL文を作成 String sql = "" String sql = "" + "SELECT" + " *" + " FROM" + " users"; // queryForListメソッドでSQLを実行し、結果MapのListで受け取る。 List<Map<String, Object>> users = jdbcTemplate.queryForList(sql); // Userオブジェクト格納用のListを作成する。 List<User> userList = new ArrayList<User>(); // 受け取ったMapのListをfor文で回し、各ユーザの値をUserオブジェクトに格納する。 for(Map<String, Object> eachUser: users) { User user = new User( (String) eachUser.get("id") ,(String) eachUser.get("password") ,(String) eachUser.get("name") ,(Date) eachUser.get("birthday") ,((Integer) eachUser.get("age")).intValue() ,(Boolean) eachUser.get("marrige") ,(String) eachUser.get("role") ); // UserオブジェクトをListに追加する。 userList.add(user); } return userList; } } |
RowMapperで取得する方法(準備が必要)
RowMapperインターフェースを実装した、独自マッパーの準備が必要です。
準備
RowMapperインターフェースを実装したクラスを作成する。
(1件のみ、複数件の取得に共通)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import java.sql.ResultSet; import java.sql.SQLException; import org.springframework.jdbc.core.RowMapper; import com.example.demo.login.domain.model.User; // RowMapperインターフェースを実装したクラスを準備する。 public class UserRowMapper implements RowMapper<User> { @Override public User mapRow(ResultSet rs, int rowNum) throws SQLException { // Query結果(ResultSet rs)を、Userオブジェクトに格納する実装 User user = new User( rs.getString("id") ,rs.getString("password") ,rs.getString("name") ,rs.getDate("birthday") ,rs.getInt("age") ,rs.getBoolean("marrige") ,rs.getString("role") ); return user; } } |
1件のみ取得
RowMapperインターフェースを実装したマッピング結果を受け取る。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; public class UserDaoRowMapper { @Autowired JdbcTemplate jdbcTemplate; public User selectOne(String id) throws DataAccessException { // SQL文を作成 String sql = "" + "SELECT" + " *" + " FROM" + " users" + " WHERE" + " id = ?"; // queryForObjectメソッドを実行 // SQLの結果をUserRowMapperでマッピングして結果を受け取る。 UserRowMapper rowMapper = new UserRowMapper(); User user = jdbcTemplate.queryForObject(sql, rowMapper, id); return user; } } |
複数件を取得
RowMapperインターフェースを実装した結果をListで受け取る。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; public class UserDaoRowMapper { @Autowired JdbcTemplate jdbcTemplate; public List<User> selectMany() throws DataAccessException { // SQL文を作成 String sql = "" + "SELECT" + " *" + " FROM" + " users"; // queryメソッドでSQLを実行 // UserRowMapperのマッピング結果である、UserオブジェクトのListを受け取る。 UserRowMapper rowMapper = new UserRowMapper(); List<User> userList = jdbcTemplate.query(sql, rowMapper); return userList; } } |
BeanPropertyRowMapperで取得する方法(準備不要!)
RowMapperインターフェースを実装したクラスの作成が不要!
テーブルのカラム名と、マッピングするクラスのフィールド名が同じであれば、
自動で値をセットしてくれる。
適用可能な例
・スネークケース
テーブルのカラム名:user_id
クラスのフィールド名:userId
・同じ
テーブルのカラム名:id
クラスのフィールド名:id
※格納するクラス(今回の場合で言うと、Userクラス)に、
Default Constructor と setterがあることが前提です。
Lombokを使用しているのであれば、@Setterアノテーションか、
@Dataアノテーションがあればいいです。
1件のみ取得
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Repository; public class UserDaoBeanPropertyRowMapper { @Autowired JdbcTemplate jdbcTemplate; public User selectOne(String id) throws DataAccessException { // SQL文を作成 String sql = "" + "SELECT" + " *" + " FROM" + " users" + " WHERE" + " id = ?"; // queryForObjectメソッドを実行 // SQLの実行結果は、自動的にUserクラスにマッピングされて取得できる。 RowMapper<User> rowMapper = new BeanPropertyRowMapper<User>(User.class); User user = jdbcTemplate.queryForObject(sql, rowMapper, id); return user; } } |
複数件を取得
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Repository; public class UserDaoBeanPropertyRowMapper { @Autowired JdbcTemplate jdbcTemplate; public List<User> selectMany() throws DataAccessException { // SQL文を作成 String sql = "" + "SELECT" + " *" + " FROM" + " users"; // queryメソッドを実行 // SQLの実行結果は、自動的にUserクラスにマッピングされて、Listで取得できる。 RowMapper<User> rowMapper = new BeanPropertyRowMapper<User>(User.class); List<User> userList = jdbcTemplate.query(sql, rowMapper); return userList; } } |
どれがいいのか?
1位:BeanPropertyRowMapper
最もマッピングが楽な方法。
setterが許されている開発現場であれば、これを使えばいい。
もし、setterを使えない(ValueObject化する必要がある)場合、
RowMapperで実装すればよい。
2位:RowMapper
マッピングするクラスの作成が少し手間である。
ただし作っておけば、Mapのように1件取得と複数件取得で2か所に
Userクラスへの格納処理を書くということは無い。
マッピングするクラスを独自に定義したいときには使えばよい。
3位:Map
Queryの取得結果をUserクラスに格納するのをわざわざ書かなければならないため、
手間とメンテナンスの面でお勧めできない。
コメント