Spring BootでのDB操作 ~JDBC編~

Spring BootでDBアクセスの色々なパターンを試してみようと思います。 今回はSpring Frameworkが提供しているJDBC data sourceを利用して、JdbcTemplateを使った実装をしてみます。

DB準備

ローカルのMySQL(5.7系)を利用します。インストール等の手順は省略。 今回はサンプルーデータとして、下記のようなデータを作成しました。

CREATE DATABASE mydb  CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
USE mydb;

CREATE TABLE users (
    userid BIGINT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(32)
);
CREATE TABLE stores (
    storeid BIGINT AUTO_INCREMENT PRIMARY KEY,
    storename VARCHAR(32)
);
CREATE TABLE reserves (
    reserve_id BIGINT AUTO_INCREMENT PRIMARY KEY,
    userid BIGINT NOT NULL,
    storeid BIGINT NOT NULL, 
    reservetime TIMESTAMP DEFAULT current_timestamp(),
    FOREIGN KEY (userid) REFERENCES users (userid),
    FOREIGN KEY (storeid) REFERENCES stores (storeid)
);
  
INSERT INTO users (username) VALUES ('tanaka'), ('katou'), ('yoshida');
INSERT INTO stores (storename) VALUES ('a_store'), ('b_store'), ('c_store');
INSERT INTO reserves (userid, storeid) VALUES (1, 1), (2, 1), (3, 2);

目指すところ

@RestController アノテーションを付けたコントローラーで、以下の全予約情報をjson形式で返却するところまで実装します。

  • username : ユーザー名
  • storename : 店舗名
  • reservetime : 予約情報

実装

1. pom.xmlに以下の依存関係を追加

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

2. JDBC datasourceの設定
resources配下に以下のようにapplication.ymlを追加。

spring:
  datasource:
    url:  jdbc:mysql://127.0.0.1:3306/mydb
    username: root
    password: 794Uguisu
    driverClassName: com.mysql.jdbc.Driver

3. SpringBootのメイン処理

@SpringBootApplication
public class MybootApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybootappApplication.class, args);
    }
}

4. DAOの作成

public class ReserveDao {
    private String username;
    private String storename;
    private String reservetime;

    // getter, setter省略
}

5. Controller作成
Modelに当たる実装もControllerに含めてしまっています。 上記設定をするだけで、JdbcTemlateがAutowiredできるので手軽です。

@RestController
public class SampleController {

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Transactional
    public List<Reserve> findAllReserve() {

        RowMapper<Reserve> mapper = new BeanPropertyRowMapper<>(Reserve.class);
        String sql = "SELECT u.username, s.storename, r.reservetime " +
                "FROM ( reserves AS r LEFT JOIN users as u ON r.userid = u.userid ) " +
                "LEFT JOIN stores AS s ON r.storeid = s.storeid;";

        List<Reserve> rs = jdbcTemplate.query(sql, mapper);

        // 代わりに`queryForList`を利用して以下のようにも書けるらしいが不便
        // List<Reserve> rs = new ArrayList<>();
        // List<Map<String, Object>> sqlResults = jdbcTemplate.queryForList(sql);
        // for( Map<String, Object> map : sqlResults ) {
        //    Reserve reserve = new Reserve();
        //    reserve.setUsername(map.get("username").toString());
        //    reserve.setStorename(map.get("storename").toString());
        //    reserve.setReservetime((Timestamp) map.get("reservetime"));
        //    reserveList.add(reserve);
        //}

        return rs;
    }

    @RequestMapping("/")
    public List<Reserve> index() {
        return findAllReserve();
    }
}