rxjava-jdbcの概要
1. 概要
簡単に言えば、rxjava-jdbcは、流databasesなスタイルのメソッド呼び出しを可能にするリレーショナルデータベースと対話するためのAPIです。 この簡単なチュートリアルでは、ライブラリと、その一般的な機能のいくつかを利用する方法について説明します。
RxJavaの基本を知りたい場合は、this articleを確認してください。
参考文献:
2. メーベン依存
pom.xmlに追加する必要のあるMaven依存関係から始めましょう。
com.github.davidmoten
rxjava-jdbc
0.7.11
APIの最新バージョンはMaven Centralにあります。
3. メインコンポーネント
The Database class is the main entry point for running all common types of database interactions.Databaseオブジェクトを作成するために、ConnectionProviderインターフェースの実装のインスタンスをfrom()静的メソッドに渡すことができます。
public static ConnectionProvider connectionProvider
= new ConnectionProviderFromUrl(
DB_CONNECTION, DB_USER, DB_PASSWORD);
Database db = Database.from(connectionProvider);
ConnectionProviderには、ConnectionProviderFromContext、ConnectionProviderFromDataSource、ConnectionProviderFromUrl、ConnectionProviderPooledなど、一見の価値のあるいくつかの実装があります。
基本的な操作を行うために、Databaseの次のAPIを使用できます。
-
select() –SQL選択クエリに使用
-
update() –作成、削除、挿入、更新、削除などのDDLステートメントに使用されます
4. 起動
次の簡単な例では、すべての基本的なデータベース操作を実行する方法を示します。
public class BasicQueryTypesTest {
Observable create,
insert1,
insert2,
insert3,
update,
delete = null;
@Test
public void whenCreateTableAndInsertRecords_thenCorrect() {
create = db.update(
"CREATE TABLE IF NOT EXISTS EMPLOYEE("
+ "id int primary key, name varchar(255))")
.count();
insert1 = db.update(
"INSERT INTO EMPLOYEE(id, name) VALUES(1, 'John')")
.dependsOn(create)
.count();
update = db.update(
"UPDATE EMPLOYEE SET name = 'Alan' WHERE id = 1")
.dependsOn(create)
.count();
insert2 = db.update(
"INSERT INTO EMPLOYEE(id, name) VALUES(2, 'Sarah')")
.dependsOn(create)
.count();
insert3 = db.update(
"INSERT INTO EMPLOYEE(id, name) VALUES(3, 'Mike')")
.dependsOn(create)
.count();
delete = db.update(
"DELETE FROM EMPLOYEE WHERE id = 2")
.dependsOn(create)
.count();
List names = db.select(
"select name from EMPLOYEE where id < ?")
.parameter(3)
.dependsOn(create)
.dependsOn(insert1)
.dependsOn(insert2)
.dependsOn(insert3)
.dependsOn(update)
.dependsOn(delete)
.getAs(String.class)
.toList()
.toBlocking()
.single();
assertEquals(Arrays.asList("Alan"), names);
}
}
ここで簡単に説明します。クエリの実行順序を決定するためにdependsOn()を呼び出しています。
そうしないと、クエリを実行する順序を指定しない限り、コードが失敗するか、予測できない結果が生成されます。
5. 自動マップ
自動マップ機能により、選択したデータベースレコードをオブジェクトにマップできます。
データベースレコードを自動マッピングする2つの方法を見てみましょう。
5.1. インターフェイスを使用した自動マッピング
注釈付きインターフェースを使用して、データベースレコードをオブジェクトにautomap()することができます。 これを行うには、注釈付きインターフェイスを作成できます。
public interface Employee {
@Column("id")
int id();
@Column("name")
String name();
}
次に、テストを実行できます。
@Test
public void whenSelectFromTableAndAutomap_thenCorrect() {
List employees = db.select("select id, name from EMPLOYEE")
.dependsOn(create)
.dependsOn(insert1)
.dependsOn(insert2)
.autoMap(Employee.class)
.toList()
.toBlocking()
.single();
assertThat(
employees.get(0).id()).isEqualTo(1);
assertThat(
employees.get(0).name()).isEqualTo("Alan");
assertThat(
employees.get(1).id()).isEqualTo(2);
assertThat(
employees.get(1).name()).isEqualTo("Sarah");
}
5.2. クラスを使用した自動マッピング
具象クラスを使用して、データベースレコードをオブジェクトに自動マッピングすることもできます。 クラスがどのように見えるか見てみましょう:
public class Manager {
private int id;
private String name;
// standard constructors, getters, and setters
}
これで、テストを実行できます。
@Test
public void whenSelectManagersAndAutomap_thenCorrect() {
List managers = db.select("select id, name from MANAGER")
.dependsOn(create)
.dependsOn(insert1)
.dependsOn(insert2)
.autoMap(Manager.class)
.toList()
.toBlocking()
.single();
assertThat(
managers.get(0).getId()).isEqualTo(1);
assertThat(
managers.get(0).getName()).isEqualTo("Alan");
assertThat(
managers.get(1).getId()).isEqualTo(2);
assertThat(
managers.get(1).getName()).isEqualTo("Sarah");
}
ここにいくつかのメモ:
-
create、insert1、およびinsert2は、Managerテーブルを作成し、それにレコードを挿入することによって返されるObservablesへの参照です。
-
クエリで選択した列の数は、Managerクラスコンストラクターのパラメーターの数と一致する必要があります
-
列は、コンストラクターの型に自動的にマップできる型である必要があります
自動マッピングの詳細については、GitHubのrxjava-jdbc repositoryにアクセスしてください。
6. 大きなオブジェクトの操作
APIは、CLOBやBLOBなどのラージオブジェクトの操作をサポートしています。 次のサブセクションでは、この機能をどのように利用できるかを見ていきます。
6.1. CLOB
CLOBを挿入して選択する方法を見てみましょう。
@Before
public void setup() throws IOException {
create = db.update(
"CREATE TABLE IF NOT EXISTS " +
"SERVERLOG (id int primary key, document CLOB)")
.count();
InputStream actualInputStream
= new FileInputStream("src/test/resources/actual_clob");
actualDocument = getStringFromInputStream(actualInputStream);
InputStream expectedInputStream = new FileInputStream(
"src/test/resources/expected_clob");
expectedDocument = getStringFromInputStream(expectedInputStream);
insert = db.update(
"insert into SERVERLOG(id,document) values(?,?)")
.parameter(1)
.parameter(Database.toSentinelIfNull(actualDocument))
.dependsOn(create)
.count();
}
@Test
public void whenSelectCLOB_thenCorrect() throws IOException {
db.select("select document from SERVERLOG where id = 1")
.dependsOn(create)
.dependsOn(insert)
.getAs(String.class)
.toList()
.toBlocking()
.single();
assertEquals(expectedDocument, actualDocument);
}
getStringFromInputStream()は、InputStream to a String.のコンテンツを変換するメソッドであることに注意してください
6.2. BLOB
APIを使用して、非常によく似た方法でBLOBを操作できます。 唯一の違いは、StringをtoSentinelIfNull()メソッドに渡す代わりに、バイト配列を渡す必要があることです。
これを行う方法は次のとおりです。
@Before
public void setup() throws IOException {
create = db.update(
"CREATE TABLE IF NOT EXISTS "
+ "SERVERLOG (id int primary key, document BLOB)")
.count();
InputStream actualInputStream
= new FileInputStream("src/test/resources/actual_clob");
actualDocument = getStringFromInputStream(actualInputStream);
byte[] bytes = this.actualDocument.getBytes(StandardCharsets.UTF_8);
InputStream expectedInputStream = new FileInputStream(
"src/test/resources/expected_clob");
expectedDocument = getStringFromInputStream(expectedInputStream);
insert = db.update(
"insert into SERVERLOG(id,document) values(?,?)")
.parameter(1)
.parameter(Database.toSentinelIfNull(bytes))
.dependsOn(create)
.count();
}
その後、前の例で同じテストを再利用できます。
7. トランザクション
次に、トランザクションのサポートを見てみましょう。
トランザクション管理により、複数のデータベース操作を1つのトランザクションにグループ化するために使用されるトランザクションを処理できるため、データベースに永続的に保存するか、完全にロールバックできます。
簡単な例を見てみましょう:
@Test
public void whenCommitTransaction_thenRecordUpdated() {
Observable begin = db.beginTransaction();
Observable createStatement = db.update(
"CREATE TABLE IF NOT EXISTS EMPLOYEE(id int primary key, name varchar(255))")
.dependsOn(begin)
.count();
Observable insertStatement = db.update(
"INSERT INTO EMPLOYEE(id, name) VALUES(1, 'John')")
.dependsOn(createStatement)
.count();
Observable updateStatement = db.update(
"UPDATE EMPLOYEE SET name = 'Tom' WHERE id = 1")
.dependsOn(insertStatement)
.count();
Observable commit = db.commit(updateStatement);
String name = db.select("select name from EMPLOYEE WHERE id = 1")
.dependsOn(commit)
.getAs(String.class)
.toBlocking()
.single();
assertEquals("Tom", name);
}
トランザクションを開始するために、メソッドbeginTransaction()を呼び出します。 このメソッドが呼び出された後、メソッドcommit()またはrollback()のいずれかが呼び出されるまで、すべてのデータベース操作が同じトランザクションで実行されます。
Exceptionをキャッチしながら、rollback()メソッドを使用して、何らかの理由でコードが失敗した場合にトランザクション全体をロールバックできます。 すべてのExceptionsまたは特定の予想されるExceptionsに対してこれを行うことができます。
8. 生成されたキーを返す
作業中のテーブルにauto_incrementフィールドを設定すると、生成された値を取得する必要がある場合があります。 これは、returnGeneratedKeys()メソッドを呼び出すことで実行できます。
簡単な例を見てみましょう:
@Test
public void whenInsertAndReturnGeneratedKey_thenCorrect() {
Integer key = db.update("INSERT INTO EMPLOYEE(name) VALUES('John')")
.dependsOn(createStatement)
.returnGeneratedKeys()
.getAs(Integer.class)
.count()
.toBlocking()
.single();
assertThat(key).isEqualTo(1);
}
9. 結論
このチュートリアルでは、rxjava–jdbcの流暢なスタイルのメソッドを利用する方法を見てきました。 また、自動マッピング、ラージオブジェクトの操作、トランザクションなど、提供される機能のいくつかについても説明しました。
いつものように、コードのフルバージョンはover on GitHubで利用できます。