Spring Data JDBCでSpring JDBCとMyBatisの両立(仮)

[JSUG勉強会 2019その1 Spring Data JDBC正式リリース記念！データアクセス特集](https://jsug.doorkeeper.jp/events/86027) で [早わかりSpring Data JDBC](https://speakerdeck.com/rshindo/jsug-2019-01) を聞いて、Mybatisもサポートしてると言うことで検証してみることにしました。

調査に当たっては、findByIdといった定番を自動生成任せにして、込み入ったところはMyBatisの外だしファイルで別管理をしたいというのが目標

## カスタム操作を利用する

1. マッパーを作成する  
この際、namespaceは任意で良い。理由はこの方法の場合DataAccessStrategyがデフォルトの「Spring JDBC」実装を利用するため

    ```
    <mapper namespace="com.example.mapper">
    <select id="findByName" resultType="Employee">
    ```

2. リファレンス通りカスタム操作用のインターフェースを作成する

    ```
    public interface EmployeeRepositoryExtension {
        public List<Employee> findByLastName(String lastName);
    }
    ```

3. リファレンス通りカスタム操作用の実装クラスを作成する  
ここで指定する引数の「statement」がマッパーの定義とかみ合っていれば問題ない

    ```
    public class EmployeeRepositoryExtensionImpl implements EmployeeRepositoryExtension {
    
        private final SqlSession sqlSession;
    
        public EmployeeRepositoryExtensionImpl(SqlSession sqlSession) {
            this.sqlSession = sqlSession;
        }
    
    	@Override
    	public List<Employee> findByLastName(String lastName) {
    		return this.sqlSession.selectList("com.example.mapper.findByName", lastName);
    	}
    }
    ```

4. リファレンス通り他のレポジトリインターフェースに継承させる

    ```
    public interface EmployeeRepository extends CrudRepository<Employee, Long>, EmployeeRepositoryExtension {
    	@Query("SELECT * FROM employee WHERE first_name = :firstName")
    	public List<Employee> findByFirstName(@Param("firstName") String firstName);
    }
    ```


## DataAccessStrategyをいじる

[参考先の「実装の併用」](https://qiita.com/kazuki43zoo/items/bd63d28dc2348aa21719#実装の併用)でも記載されているとおりDataAccessStrategyをいい感じに定義することでもできそう。（未検証）

[MyBatisDataAccessStrategy](https://github.com/spring-projects/spring-data-jdbc/blob/master/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategy.java)を見る感じ、MyBatisDataAccessStrategy#createCombinedAccessStrategy(...)を使うことでできそうな雰囲気はあります。

## 参考資料
* https://speakerdeck.com/rshindo/jsug-2019-01
* https://github.com/rshindo/spring-data-jdbc-demo/tree/master/spring-data-jdbc-demo
* https://qiita.com/kazuki43zoo/items/bd63d28dc2348aa21719
* https://docs.spring.io/spring-data/jdbc/docs/1.0.4.RELEASE/reference/html/

## ソース
https://github.com/tac-yacht/Sample-SpringDataJDBC-mix-MyBatis

## 感想
[Query Creation](https://docs.spring.io/spring-data/jdbc/docs/1.0.4.RELEASE/reference/html/#repositories.query-methods.query-creation)を見るとメソッド名を生成根拠としてクエリ自動生成してくれそうな雰囲気が既にあるので使える様になったら、基本的には自動生成で、生成するには複雑すぎるところはMyBatisでクエリのスクラッチにしたいなと
（1.0.4時点では使えない）
とはいっても現時点でfindByIdなどは書かなくて済むので個人的には結構うれしい


## 付録:実行結果ログ

```text:Mybatisのとき
2019-02-02 12:04:38.176 DEBUG 3108 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : GET "/findByLastName?name=doe", parameters={masked}
2019-02-02 12:04:38.646 DEBUG 3108 --- [nio-8080-exec-1] com.example.mapper.findByName            : ==>  Preparing: SELECT * FROM employee WHERE last_name = ? 
2019-02-02 12:04:38.670 DEBUG 3108 --- [nio-8080-exec-1] com.example.mapper.findByName            : ==> Parameters: doe(String)
2019-02-02 12:04:38.704 DEBUG 3108 --- [nio-8080-exec-1] com.example.mapper.findByName            : <==      Total: 1
```

```text:@Queryでカスタムクエリのとき
2019-02-02 12:06:04.184 DEBUG 3108 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : GET "/findByFirstName?name=jone", parameters={masked}
2019-02-02 12:06:04.185 DEBUG 3108 --- [nio-8080-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public java.lang.Object com.example.Controller.findByFirstName(java.lang.String)
2019-02-02 12:06:04.195 DEBUG 3108 --- [nio-8080-exec-3] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL query
2019-02-02 12:06:04.196 DEBUG 3108 --- [nio-8080-exec-3] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [SELECT * FROM employee WHERE first_name = ?]
```

```text:組み込みのクエリ生成のとき
2019-02-02 12:06:07.882 DEBUG 3108 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet        : GET "/findById?id=1", parameters={masked}
2019-02-02 12:06:07.882 DEBUG 3108 --- [nio-8080-exec-4] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public java.lang.Object com.example.Controller.findById(java.lang.Long)
2019-02-02 12:06:07.896 DEBUG 3108 --- [nio-8080-exec-4] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL query
2019-02-02 12:06:07.896 DEBUG 3108 --- [nio-8080-exec-4] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [SELECT employee.id AS id, employee.first_name AS first_name, employee.last_name AS last_name FROM employee WHERE employee.id = ?]
```