Apache CommonsDbUtilsのガイド

1。概要

Apache Commons DbUtilsは、JDBCの操作を非常に簡単にする小さなライブラリです。

この記事では、その特徴と機能を紹介する例を実装します。

2.セットアップ

2.1。Mavenの依存関係

まず、commons-dbutilsh2の依存関係をpom.xmlに追加する必要があります。

 commons-dbutils commons-dbutils 1.6   com.h2database h2 1.4.196 

Commonsの最新バージョンであるdbutilsとh2は、MavenCentralにあります。

2.2。テストデータベース

依存関係が整ったら、使用するテーブルとレコードを作成するスクリプトを作成しましょう。

CREATE TABLE employee( id int NOT NULL PRIMARY KEY auto_increment, firstname varchar(255), lastname varchar(255), salary double, hireddate date, ); CREATE TABLE email( id int NOT NULL PRIMARY KEY auto_increment, employeeid int, address varchar(255) ); INSERT INTO employee (firstname,lastname,salary,hireddate) VALUES ('John', 'Doe', 10000.10, to_date('01-01-2001','dd-mm-yyyy')); // ... INSERT INTO email (employeeid,address) VALUES (1, '[email protected]'); // ...

この記事のすべてのサンプルテストケースでは、H2インメモリデータベースへの新しく作成された接続を使用します。

public class DbUtilsUnitTest { private Connection connection; @Before public void setupDB() throws Exception { Class.forName("org.h2.Driver"); String db = "jdbc:h2:mem:;INIT=runscript from 'classpath:/employees.sql'"; connection = DriverManager.getConnection(db); } @After public void closeBD() { DbUtils.closeQuietly(connection); } // ... }

2.3。POJO

最後に、2つの簡単なクラスが必要です。

public class Employee { private Integer id; private String firstName; private String lastName; private Double salary; private Date hiredDate; // standard constructors, getters, and setters } public class Email { private Integer id; private Integer employeeId; private String address; // standard constructors, getters, and setters }

3.はじめに

DbUtilsライブラリは、利用可能なほとんどの機能のメインエントリポイントとしてQueryRunnerクラスを提供ます。

このクラスは、データベースへの接続、実行されるSQLステートメント、およびクエリのプレースホルダーに値を提供するためのオプションのパラメーターリストを受け取ることによって機能します。

後で説明するように、いくつかのメソッドはResultSetHandler実装も受け取ります。これは、ResultSetインスタンスをアプリケーションが期待するオブジェクトに変換する役割を果たします。

もちろん、ライブラリには、リスト、マップ、JavaBeansなどの最も一般的な変換を処理するいくつかの実装がすでに提供されています。

4.データのクエリ

基本がわかったので、データベースにクエリを実行する準備が整いました。

MapListHandlerを使用して、データベース内のすべてのレコードをマップのリストとして取得する簡単な例から始めましょう。

@Test public void givenResultHandler_whenExecutingQuery_thenExpectedList() throws SQLException { MapListHandler beanListHandler = new MapListHandler(); QueryRunner runner = new QueryRunner(); List list = runner.query(connection, "SELECT * FROM employee", beanListHandler); assertEquals(list.size(), 5); assertEquals(list.get(0).get("firstname"), "John"); assertEquals(list.get(4).get("firstname"), "Christian"); }

次に、BeanListHandlerを使用して結果をEmployeeインスタンスに変換する例を次に示します。

@Test public void givenResultHandler_whenExecutingQuery_thenEmployeeList() throws SQLException { BeanListHandler beanListHandler = new BeanListHandler(Employee.class); QueryRunner runner = new QueryRunner(); List employeeList = runner.query(connection, "SELECT * FROM employee", beanListHandler); assertEquals(employeeList.size(), 5); assertEquals(employeeList.get(0).getFirstName(), "John"); assertEquals(employeeList.get(4).getFirstName(), "Christian"); }

単一の値を返すクエリの場合、ScalarHandlerを使用できます。

@Test public void givenResultHandler_whenExecutingQuery_thenExpectedScalar() throws SQLException { ScalarHandler scalarHandler = new ScalarHandler(); QueryRunner runner = new QueryRunner(); String query = "SELECT COUNT(*) FROM employee"; long count = runner.query(connection, query, scalarHandler); assertEquals(count, 5); }

ResultSerHandlerのすべての実装については、ResultSetHandlerのドキュメントを参照してください。

4.1。カスタムハンドラー

結果をオブジェクトに変換する方法をさらに制御する必要がある場合は、QueryRunnerのメソッドに渡すカスタムハンドラーを作成することもできます。

これは、ResultSetHandlerインターフェイスを実装するか、ライブラリによって提供される既存の実装の1つを拡張することによって実行できます。

2番目のアプローチがどのように見えるかを見てみましょう。まず、Employeeクラスに別のフィールドを追加しましょう。

public class Employee { private List emails; // ... }

次に、BeanListHandlerタイプを拡張し、各従業員のメーリングリストを設定するクラスを作成しましょう。

public class EmployeeHandler extends BeanListHandler { private Connection connection; public EmployeeHandler(Connection con) { super(Employee.class); this.connection = con; } @Override public List handle(ResultSet rs) throws SQLException { List employees = super.handle(rs); QueryRunner runner = new QueryRunner(); BeanListHandler handler = new BeanListHandler(Email.class); String query = "SELECT * FROM email WHERE employeeid = ?"; for (Employee employee : employees) { List emails = runner.query(connection, query, handler, employee.getId()); employee.setEmails(emails); } return employees; } }

電子メールを取得するためのクエリを実行できるように、コンストラクターにConnectionオブジェクトが必要であることに注意してください。

最後に、コードをテストして、すべてが期待どおりに機能しているかどうかを確認しましょう。

@Test public void givenResultHandler_whenExecutingQuery_thenEmailsSetted() throws SQLException { EmployeeHandler employeeHandler = new EmployeeHandler(connection); QueryRunner runner = new QueryRunner(); List employees = runner.query(connection, "SELECT * FROM employee", employeeHandler); assertEquals(employees.get(0).getEmails().size(), 2); assertEquals(employees.get(2).getEmails().size(), 3); }

4.2。カスタム行プロセッサ

この例では、employeeテーブルの列名はEmployeeクラスのフィールド名と一致します(一致は大文字と小文字を区別しません)。ただし、常にそうであるとは限りません。たとえば、列名でアンダースコアを使用して複合語を区切る場合などです。

このような状況では、RowProcessorインターフェースとその実装を利用して、列名をクラスの適切なフィールドにマップできます。

これがどのように見えるか見てみましょう。まず、別のテーブルを作成して、そのテーブルにいくつかのレコードを挿入しましょう。

CREATE TABLE employee_legacy ( id int NOT NULL PRIMARY KEY auto_increment, first_name varchar(255), last_name varchar(255), salary double, hired_date date, ); INSERT INTO employee_legacy (first_name,last_name,salary,hired_date) VALUES ('John', 'Doe', 10000.10, to_date('01-01-2001','dd-mm-yyyy')); // ...

それでは、EmployeeHandlerクラスを変更しましょう。

public class EmployeeHandler extends BeanListHandler { // ... public EmployeeHandler(Connection con) { super(Employee.class, new BasicRowProcessor(new BeanProcessor(getColumnsToFieldsMap()))); // ... } public static Map getColumnsToFieldsMap() { Map columnsToFieldsMap = new HashMap(); columnsToFieldsMap.put("FIRST_NAME", "firstName"); columnsToFieldsMap.put("LAST_NAME", "lastName"); columnsToFieldsMap.put("HIRED_DATE", "hiredDate"); return columnsToFieldsMap; } // ... }

BeanProcessorを使用して、列からフィールドへの実際のマッピングを実行していることに注意してください。これは、対処する必要があるものに対してのみです。

Finally, let's test everything is ok:

@Test public void givenResultHandler_whenExecutingQuery_thenAllPropertiesSetted() throws SQLException { EmployeeHandler employeeHandler = new EmployeeHandler(connection); QueryRunner runner = new QueryRunner(); String query = "SELECT * FROM employee_legacy"; List employees = runner.query(connection, query, employeeHandler); assertEquals((int) employees.get(0).getId(), 1); assertEquals(employees.get(0).getFirstName(), "John"); }

5. Inserting Records

The QueryRunner class provides two approaches to creating records in a database.

The first one is to use the update() method and pass the SQL statement and an optional list of replacement parameters. The method returns the number of inserted records:

@Test public void whenInserting_thenInserted() throws SQLException { QueryRunner runner = new QueryRunner(); String insertSQL = "INSERT INTO employee (firstname,lastname,salary, hireddate) " + "VALUES (?, ?, ?, ?)"; int numRowsInserted = runner.update( connection, insertSQL, "Leia", "Kane", 60000.60, new Date()); assertEquals(numRowsInserted, 1); }

The second one is to use the insert() method that, in addition to the SQL statement and replacement parameters, needs a ResultSetHandler to transform the resulting auto-generated keys. The return value will be what the handler returns:

@Test public void givenHandler_whenInserting_thenExpectedId() throws SQLException { ScalarHandler scalarHandler = new ScalarHandler(); QueryRunner runner = new QueryRunner(); String insertSQL = "INSERT INTO employee (firstname,lastname,salary, hireddate) " + "VALUES (?, ?, ?, ?)"; int newId = runner.insert( connection, insertSQL, scalarHandler, "Jenny", "Medici", 60000.60, new Date()); assertEquals(newId, 6); }

6. Updating and Deleting

The update() method of the QueryRunner class can also be used to modify and erase records from our database.

Its usage is trivial. Here's an example of how to update an employee's salary:

@Test public void givenSalary_whenUpdating_thenUpdated() throws SQLException { double salary = 35000; QueryRunner runner = new QueryRunner(); String updateSQL = "UPDATE employee SET salary = salary * 1.1 WHERE salary <= ?"; int numRowsUpdated = runner.update(connection, updateSQL, salary); assertEquals(numRowsUpdated, 3); }

And here's another to delete an employee with the given id:

@Test public void whenDeletingRecord_thenDeleted() throws SQLException { QueryRunner runner = new QueryRunner(); String deleteSQL = "DELETE FROM employee WHERE id = ?"; int numRowsDeleted = runner.update(connection, deleteSQL, 3); assertEquals(numRowsDeleted, 1); }

7. Asynchronous Operations

DbUtils provides the AsyncQueryRunner class to execute operations asynchronously. The methods on this class have a correspondence with those of QueryRunner class, except that they return a Future instance.

Here's an example to obtain all employees in the database, waiting up to 10 seconds to get the results:

@Test public void givenAsyncRunner_whenExecutingQuery_thenExpectedList() throws Exception { AsyncQueryRunner runner = new AsyncQueryRunner(Executors.newCachedThreadPool()); EmployeeHandler employeeHandler = new EmployeeHandler(connection); String query = "SELECT * FROM employee"; Future
    
      future = runner.query(connection, query, employeeHandler); List employeeList = future.get(10, TimeUnit.SECONDS); assertEquals(employeeList.size(), 5); }
    

8. Conclusion

In this tutorial, we explored the most notable features of the Apache Commons DbUtils library.

データをクエリしてさまざまなオブジェクトタイプに変換し、生成された主キーを取得するレコードを挿入し、特定の基準に基づいてデータを更新および削除しました。また、AsyncQueryRunnerクラスを利用して、クエリ操作を非同期で実行しました。

そして、いつものように、この記事の完全なソースコードはGithubにあります。