使用Spring Boot + Doma2进行2WaySQL的步骤
背景
最近,由于数据访问使用了S2JDBC(2WaySQL)进行开发,所以对于像Spring Data JPA那样在类文件中以字符串形式”select column1,column2 from table…”的写法感到有些不自然。正好在这个时候有机会了解到了Doma2的存在,于是想试着去尝试一下。
顺便说一下,目前我们的现场环境是使用Spring Boot + MyBatis。
-
- パッと見た感じxmlでマッピング書くのがめんどくさそう
-
- xmlがjavaクラスへの依存を持ってしまっている(resultMapとか)、etc
-
- javaとSQLを分離したい
- そもそもあまり詳しくない
有这个原因,我还是觉得习惯了的2WaySQL比较好。
※如果对其他O/R映射器有更深入的了解可能会改变思考方式。
此外,本次将使用麻生さん介绍的doma-spring-boot-starter自动配置,可在Spring Boot中使用Doma。
https://github.com/domaframework/doma-spring-boot
通过此方式,无需进行任何配置即可在Spring Boot中使用Doma。
Doma是什么意思?
它是一种O/R映射器,简单来说就是O/R Mapper。由于不依赖于Seasar2,因此可以从Spring或其他框架中使用。当然,也可以使用2WaySQL。
Doma有两个主要版本,分别是1和2。
版本1是在Java6上编译的,可以在Java6、Java7和Java8上运行。
※http://doma.seasar.org/index.html
版本2是在Java8上编译的,可以在Java8上运行。
※http://doma.readthedocs.org/ja/stable/
环境
Windows 10 – Windows 十
JDK 8 – JDK 八
Spring Boot 1.3.0 – Spring Boot 一点三点零
STS 3.7.2 – STS 三点七点二
doma 2.5.1 – doma 二点五点一
H2DB 1.4.190 – H2DB 一点四点一九零
Maven 3.3.3 – Maven 三点三点三
我所参考的资料
https://github.com/domaframework/spring-boot-sample 可在此处找到domaframework的spring-boot-sample项目。
http://doma.seasar.org/ 您可以在这里访问doma.seasar.org网站。
http://doma.readthedocs.org/ja/stable/ 你可以在这里访问doma的readthedocs.org网站的日文版本,该版本为稳定版本。
制作的东西
我們將根據書籍《初めてのSpring Boot》創建一個簡單的RestAPI。另外,我們的示例原始碼已經放在以下位置:https://github.com/kenichi-nagaoka/Doma2-SpringBoot
组成
我們會按照以下的結構安排。
│ pom.xml
├─src
│ ├─main
│ │ ├─java
│ │ │ └─com
│ │ │ └─example
│ │ │ │ Application.java
│ │ │ │
│ │ │ ├─controller
│ │ │ │ CustomerController.java
│ │ │ │
│ │ │ ├─model
│ │ │ │ Customer.java
│ │ │ │
│ │ │ ├─repository
│ │ │ │ CustomerRepository.java
│ │ │ │
│ │ │ └─service
│ │ │ CustomerService.java
│ │ │
│ │ ├─resources
│ │ │ │ application.properties
│ │ │ │ data.sql
│ │ │ │ schema.sql
│ │ │ │
│ │ │ └─META-INF
│ │ │ └─com
│ │ │ └─example
│ │ │ └─repository
│ │ │ └─CustomerRepository
│ │ │ selectAll.sql
│ │ │
│ │ └─webapp
│ └─test
│ └─java
│ └─com
│ └─example
│ ApplicationTests.java
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>doma-cooperation</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<description>Demo project for Spring Boot - Doma</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.0.RELEASE</version>
</parent>
<repositories>
<repository>
<id>sonatype-snapshots</id>
<name>Sonatype Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 冒頭でも述べた通り今回Domaとの連携は以下を利用しました、これを依存関係に追加するだけで推移的依存でDomaも使えます -->
<dependency>
<groupId>org.seasar.doma.boot</groupId>
<artifactId>doma-spring-boot-starter</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
数据表定义
当使用Spring Boot时,如果在类路径下(src/main/resources下)存在以下文件,它将在启动时自动执行:
1. 执行schema-(platform).sql文件
2. 执行schema.sql文件
3. 执行data-(platform).sql文件
4. 执行data.sql文件
本次将使用H2数据库进行内存中的数据操作。因此,在启动时将创建表格并插入数据。
CREATE table IF NOT EXISTS customers(id int primary key, name varchar(30));
INSERT INTO customers(id, name) VALUES(1, 'JAY-Z');
INSERT INTO customers(id, name) VALUES(2, 'NAS');
INSERT INTO customers(id, name) VALUES(3, 'DMX');
INSERT INTO customers(id, name) VALUES(4, '2PAC');
Application.java 的汉语释义可以是 “应用程序.java”。
这是一个作为入口点的类。似乎没有什么特别值得注意的地方。
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
顾客控制器.java
这是一个控制器类。它将URL“/customers”和方法“getCustomers”进行了映射。
package com.example.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.example.model.Customer;
import com.example.service.CustomerService;
@RestController
public class CustomerController {
@Autowired
CustomerService customerService;
@RequestMapping(value = "customers", method = RequestMethod.GET)
public List<Customer> getCustomers() {
return customerService.getCustomers();
}
}
客户服务.java
这是与领域层服务相关的内容。只是调用DAO的CustomerRepository的selectAll方法。
package com.example.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.model.Customer;
import com.example.repository.CustomerRepository;
@Service
@Transactional
public class CustomerService {
@Autowired
CustomerRepository customerRepository;
public List<Customer> getCustomers() {
return customerRepository.selectAll();
}
}
顾客.java
这是一个实体类(查询结果集类)。
必须使用@Entity注解,需要注意的是要使用”org.seasar.doma.Entity”注解。请注意,@Entity有多个,需要注意。另外,如果在内存中使用数据库(如H2或HSQL等),使用@Entity注解并在启动时会自动删除/创建与实体对应的表。因此,在这种情况下,上述的schema.sql文件是不必要的。
@Table注解用于明确指定表名。如果没有这个注解,表名将使用实体类的简单名称,列名将使用属性名称。
更详细的信息如下:
http://doma.seasar.org/reference/entity.html
package com.example.model;
import org.seasar.doma.Entity;
import org.seasar.doma.Id;
import org.seasar.doma.Table;
@Entity
@Table(name = "customers")
public class Customer {
@Id
public Integer id;
public String name;
}
顾客仓库.java
我认为关键点可能是在这里,即DAO。
在Doma中,DAO的实现类通常是通过apt自动生成的。因此,我们要给它加上@Dao注解作为注释。实现类会在编译时自动生成。
接下来的@ConfigAutowireable是使用了前面提到的doma-spring-boot-starter的自动配置。这是为了将自动生成的DAO实现类纳入容器管理所必需的。
详细信息请参见以下链接:
http://doma.seasar.org/reference/dao.html
用这个方法几乎已经完成了。
package com.example.repository;
import java.util.List;
import org.seasar.doma.Dao;
import org.seasar.doma.Select;
import org.seasar.doma.boot.ConfigAutowireable;
import com.example.model.Customer;
@Dao
@ConfigAutowireable
public interface CustomerRepository {
@Select
List<Customer> selectAll();
}
创建一个SQL文件
只需创建SQL文件。SQL文件必须放置在已经配置了类路径的 META-INF 目录下。
规则如下:
Meta-INF/Dao 下的类的完全限定名转换为目录名/Dao 的方法名.sql
也就是说,在这个例子中,
META-INF/com/example/repository/CustomerRepository/selectAll.sql
select id, name from customers order by id;
编译
由于这次使用了Maven,因此我们将尝试用以下命令进行编译。
mvn compile
结果如下所示。
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building doma-cooperation 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ doma-cooperation ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 3 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ doma-cooperation ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 5 source files to C:\Development\sts-bundle\workspace\doma-cooperation\target\classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 22.281 s
[INFO] Finished at: 2015-12-13T21:28:22+09:00
[INFO] Final Memory: 21M/93M
maven-resources-plugin会将SQL文件从src/main/resources/META-INF复制到target/classes中。这是因为如果不先复制,编译时会找不到SQL文件并报错。
接下来,maven-compiler-plugin会使用apt生成DAO实现类,并进行编译。
有关Maven构建的详细信息,请参见以下链接:
http://doma.seasar.org/reference/app_build.html#Maven%E3%81%AB%E3%82%88%E3%82%8B%E3%83%93%E3%83%AB%E3%83%89
请注意,尽管maven-resources-plugin和maven-compiler-plugin没有在这个pom.xml中定义,但可以通过父级的父级pom(奇怪的表达方式)即Spring Boot Dependencies.pom来使用它们。
尝试执行
我会立即执行。我将启动Spring Boot并在浏览器上访问以下网址:
http://localhost:8080/customers
结果如下所示。正如期望的那样。
[{“id”:1,”name”:”JAY-Z”},{“id”:2,”name”:”NAS”},{“id”:3,”name”:”DMX”},{“id”:4,”name”:”2PAC”}]
STS的控制台如下所示(由于没有进行日志设置,所以文字会乱码,但是可以看到正在读取SQL文件)。
2015-12-13 21:57:52.519 INFO 8620 --- [nio-8080-exec-4] o.s.doma.jdbc.UtilLoggingJdbcLogger : [DOMA2220] ENTER : 繧ッ繝ゥ繧ケ=[com.example.repository.CustomerRepositoryImpl], 繝。繧ス繝?繝?=[selectAll]
2015-12-13 21:57:52.531 INFO 8620 --- [nio-8080-exec-4] o.s.doma.jdbc.UtilLoggingJdbcLogger : [DOMA2076] SQL繝ュ繧ー : SQL繝輔ぃ繧、繝ォ=[META-INF/com/example/repository/CustomerRepository/selectAll.sql],
select id, name from customers order by id
2015-12-13 21:57:52.534 INFO 8620 --- [nio-8080-exec-4] o.s.doma.jdbc.UtilLoggingJdbcLogger : [DOMA2221] EXIT : 繧ッ繝ゥ繧ケ=[com.example.repository.CustomerRepositoryImpl], 繝。繧ス繝?繝?=[selectAll]
通过这个,我们可以说Spring Boot和Doma2已成功地实现了集成。
摘要/我沉迷过的事情
暫時而言,通過Spring Boot + Doma2的整合,現在可以使用2WaySQL,但在實際應用中似乎需要進一步驗證。例如,這次的例子中只使用了SELECT語句,那麼在INSERT、UPDATE、DELETE等語句中如何處理回滾和異常處理等相關部分就成為了驗證的重點。此外,因為本身對Doma不是很了解,所以理解這部分花了一些時間。不過,無論是Doma1還是Doma2,由於有豐富的日文文檔,所以入門比較容易。這次並沒有進行Eclipse的Annotation Processing設定,因為這樣做會和mvn compile的設定產生衝突,讓人感到困惑。
最后,似乎有Spring Boot + Doma2的实践记录。
下一步,我打算尝试写一些关于INSERT、UPDATE和DELETE的内容。
这就是以上的内容。