【JDBC ②】JavaからSQLite3のデータベースアクセスをSQL文ごとにメソッド化してみた。

[前回の記事](https://qiita.com/tsweblabo/items/39bdd73a910417a9a8df)でJDBCを使ってJavaからのSQLiteデータベースにアクセスすることに成功しました。
予めデータベースを用意しておいてJavaプログラムでSELECT文を記述してデータベースからデータを取得するだけだったので、もう一歩踏み込んでSELECT文に加えてINSERT文・UPDATE文・DELETE文等を組み込んだものに挑戦してみました。

## 環境
今回の開発環境については以下のとおりです。

- Ubuntu 18.04.5LTS
- OpenJDK 11.0.8 
- SQLite3 3.22.0

---
## 参考にしたサンプルコード
今回は複数のSQL文を使いたかったので、JDBCリポジトリのREADMEにあったサンプルコードをもとにメソッド化していこうと思います。

```java:参考元のサンプルコード
import java.sql.*;

public class Sample
{
  public static void main(String[] args) throws ClassNotFoundException
  {
    // load the sqlite-JDBC driver using the current class loader
    Class.forName("org.sqlite.JDBC");

    Connection connection = null;
    try
    {
      // create a database connection
      connection = DriverManager.getConnection("jdbc:sqlite:sample.db");
      Statement statement = connection.createStatement();
      statement.setQueryTimeout(30);  // set timeout to 30 sec.

      statement.executeUpdate("drop table if exists person");
      statement.executeUpdate("create table person (id integer, name string)");
      statement.executeUpdate("insert into person values(1, 'leo')");
      statement.executeUpdate("insert into person values(2, 'yui')");
      ResultSet rs = statement.executeQuery("select * from person");
      while(rs.next())
      {
        // read the result set
        System.out.println("name = " + rs.getString("name"));
        System.out.println("id = " + rs.getInt("id"));
      }
    }
    catch(SQLException e)
    {
      // if the error message is "out of memory", 
      // it probably means no database file is found
      System.err.println(e.getMessage());
    }
    finally
    {
      try
      {
        if(connection != null)
          connection.close();
      }
      catch(SQLException e)
      {
        // connection close failed.
        System.err.println(e);
      }
    }
  }
}
```

## SQL文ごとにメソッド化する
上記のサンプルコードは、データベスにアクセス → テーブルを消去 → テーブル作成 → データの入力 → データの読み込みの全てをmainメソッドの中で処理しています。
実際のプログラムでは各動作を別々に行うので、それらをメソッド化して必要時にmainメソッドに呼び出して使うのがより現実的だと思います。

自分なりにメソッド化したコードが以下になります。
尚、データベース内の名前は解りやすくするため、適宜変えてあります。

```java:メソッド化したコード
import java.sql.*;

/**
 * TestDataBaseAccess
 */
public class TestDataBaseAccess {
    static Connection connection;
    static String URL = "jdbc:sqlite:sample.db";

    public static void main(String[] args) throws ClassNotFoundException {
       // load the sqlite-JDBC driver using the current class loader
        Class.forName("org.sqlite.JDBC");
        connection = null;
        
        dropTable();
        createTable();
        insertData();
        loadData();

        updateData();
        loadData();

        deleteData();
        loadData();
    }
    /**
     * SELECT文
     */
    public static void loadData() {
        try {
            // create a database connection
            connection = DriverManager.getConnection(URL);
            Statement statement = connection.createStatement();
            statement.setQueryTimeout(30);  // set timeout to 30 sec.

            ResultSet rs = statement.executeQuery("SELECT * FROM person");
            while(rs.next()){
                // read the result set
                System.out.println("id = " + rs.getInt("id") + " | name = " + rs.getString("name"));
            }
        } catch(SQLException e) {
            // if the error message is "out of memory", 
            // it probably means no database file is found
            System.err.println(e.getMessage());
        } finally {
            try {
                if(connection != null)
                connection.close();
            } catch(SQLException e) {
                // connection close failed.
                System.err.println(e);
            }
        }
    }

    /**
     * INSERT文
     */
    public static void insertData() {
        try {
            // create a database connection
            connection = DriverManager.getConnection(URL);
            Statement statement = connection.createStatement();
            statement.setQueryTimeout(30);  // set timeout to 30 sec.

            statement.executeUpdate("INSERT INTO person VALUES(1, 'Satou')");
            statement.executeUpdate("INSERT INTO person VALUES(2, 'Tanaka')");
            statement.executeUpdate("INSERT INTO person VALUES(3, 'Suzuki')");
            
            
        } catch(SQLException e) {
            // if the error message is "out of memory", 
            // it probably means no database file is found
            System.err.println(e.getMessage());
        } finally {
            try {
                if(connection != null)
                connection.close();
            } catch(SQLException e) {
                // connection close failed.
                System.err.println(e);
            }
        }
    }

    /**
     * UPDATE文
     */
    public static void updateData() {
        try {
            // create a database connection
            connection = DriverManager.getConnection(URL);
            Statement statement = connection.createStatement();
            statement.setQueryTimeout(30);  // set timeout to 30 sec.

            statement.executeUpdate("UPDATE person SET name = 'Takahashi' WHERE id = 1");            
        } catch(SQLException e) {
            // if the error message is "out of memory", 
            // it probably means no database file is found
            System.err.println(e.getMessage());
        } finally {
            try {
                if(connection != null)
                connection.close();
            } catch(SQLException e) {
                // connection close failed.
                System.err.println(e);
            }
        }
    }

    /**
     * DELETE文
     */
    public static void deleteData() {
        try {
            // create a database connection
            connection = DriverManager.getConnection(URL);
            Statement statement = connection.createStatement();
            statement.setQueryTimeout(30);  // set timeout to 30 sec.

            statement.executeUpdate("DELETE FROM person WHERE id = 3");            
        } catch(SQLException e) {
            // if the error message is "out of memory", 
            // it probably means no database file is found
            System.err.println(e.getMessage());
        } finally {
            try {
                if(connection != null)
                connection.close();
            } catch(SQLException e) {
                // connection close failed.
                System.err.println(e);
            }
        }
    }

    /**
     * テーブル作成
     */
    public static void createTable() {
        try {
            // create a database connection
            connection = DriverManager.getConnection(URL);
            Statement statement = connection.createStatement();
            statement.setQueryTimeout(30);  // set timeout to 30 sec.

            statement.executeUpdate("CREATE TABLE person (id INTEGER, name STRING)");
        } catch(SQLException e) {
            // if the error message is "out of memory", 
            // it probably means no database file is found
            System.err.println(e.getMessage());
        } finally {
            try {
                if(connection != null)
                connection.close();
            } catch(SQLException e) {
                // connection close failed.
                System.err.println(e);
            }
        }
    }

    /**
     * テーブル削除
     */
    public static void dropTable() {
        try {
            // create a database connection
            connection = DriverManager.getConnection(URL);
            Statement statement = connection.createStatement();
            statement.setQueryTimeout(30);  // set timeout to 30 sec.

            statement.executeUpdate("DROP TABLE IF EXISTS person");
        } catch(SQLException e) {
            // if the error message is "out of memory", 
            // it probably means no database file is found
            System.err.println(e.getMessage());
        } finally {
            try {
                if(connection != null)
                connection.close();
            } catch(SQLException e) {
                // connection close failed.
                System.err.println(e);
            }
        }
    }
}
```

メソッド化した上で、処理の流れをmainメソッドに呼び出してみました。

```shell:実行結果
id = 1 | name = Satou
id = 2 | name = Tanaka
id = 3 | name = Suzuki
id = 1 | name = Takahashi
id = 2 | name = Tanaka
id = 3 | name = Suzuki
id = 1 | name = Takahashi
id = 2 | name = Tanaka
```

---

### まとめ
各SQL文をメソッド化し、必要に応じてmainメソッドに呼び出すことになんとか成功しました。
SQLを扱う場合、各メソッドごとにtry-catchをしないとエラーになるようでした。
しかし現状では、データの入力内容・変更内容をメソッド内で定義しているため、再利用性が低く未だ未完成です。
今回のコードをベースに再利用性のあるコードにしていこうと思います。

---

### 本記事目次ページ

[【データベース】SQLite3・JDBCまとめ](https://qiita.com/tsweblabo/items/8fa21f3e9e30885be034)

---

### 参考サイト

- [SQLite用JDBCのリポジトリ](https://bitbucket.org/xerial/sqlite-jdbc/src/default/)
- [TECHSCORE BROG/3分で構築！SQLiteを色々な環境で動かしてみる](https://www.techscore.com/blog/2015/03/27/3%E5%88%86%E3%81%A7%E6%A7%8B%E7%AF%89%EF%BC%81sqlite%E3%82%92%E8%89%B2%E3%80%85%E3%81%AA%E7%92%B0%E5%A2%83%E3%81%A7%E5%8B%95%E3%81%8B%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B/)