JDBC勉強備忘録（Delete処理）

## 備忘録目的
DAOに関しての自分が認識していることの確認と躓いたところや調査方法、仮定したことなど、過程を記録する。
（技術的なことはサイトのリンクを貼る）

## 環境
OS：macOS 12.5.1
IDE:Eclipse IDE for Enterprise Java Developers.
　　Version: 2019-12 (4.14.0)
　　Build id: 20191212-1212
DB：Ver 8.0.32 for macos12.6 on x86_64 (Homebrew)
クラスパス:mysql-connector-j-8.0.32.jar
その他：本文に追記

## 本文
まず、Delete処理に関わるファイルとメソッドを確認する。
```Java:/Sample_4/src/j4_02/Sample4_02_1_Del_Main.java
package j4_02;

/**----------------------------------------------------------------------*
 *■■■Sample4_02_1_Del_Mainクラス■■■
 *概要：メイン（ユーザーの登録解除）
 *----------------------------------------------------------------------**/
public class Sample4_02_1_Del_Main {
	public static void main (String[] args) {

		//コマンドラインから登録解除したいユーザーのIDを受け取る
		int unsubscribeId = Integer.parseInt(args[0]);

		//ビジネスロジック（ユーザーの登録解除）クラスのインスタンス化＆メソッド起動
		Sample4_02_1_Del_BusinessLogic blDel = new Sample4_02_1_Del_BusinessLogic();
		blDel.unsubscribe( unsubscribeId );

	}
}
```
```Java:/Sample_4/src/j4_02/Sample4_02_1_Del_BusinessLogic.java
package j4_02;

/**----------------------------------------------------------------------*
 *■■■Sample4_02_1_Del_BusinessLogicクラス■■■
 *概要：ビジネスロジック（ユーザーの登録解除）
 *----------------------------------------------------------------------**/
public class Sample4_02_1_Del_BusinessLogic {

	/**----------------------------------------------------------------------*
	 *■unsubscribeメソッド
	 *概要　：対象のユーザーを登録解除する
	 *引数　：対象のユーザーID
	 *戻り値：なし
	 *----------------------------------------------------------------------**/
	public void unsubscribe (int targetUserId) {

		//-------------------------------------------
		//データベースへの接続を実施
		//-------------------------------------------

		//DAOクラスをインスタンス化＆指定のIDと合致するデータを削除するよう依頼
		Sample4_02_1_Common_DAO dao = new Sample4_02_1_Common_DAO();
		boolean result = dao.deleteMemberInfo(targetUserId);

		//終了メッセージを表示
		if(result){
			System.out.println("[INFO]削除処理が正常終了しました" ) ;
		}else{
			System.out.println("[INFO]削除処理に失敗しました" ) ;
		}

	}
}
```
```Java:/Sample_4/src/j4_02/Sample4_02_1_Common_DAO.java
	/**----------------------------------------------------------------------*
	 *■deleteMemberInfoメソッド
	 *概要　：「uzuz_member」テーブルから指定のレコードを1行削除する
	 *引数　：削除対象ID
	 *戻り値：実行結果（真：成功、偽：例外発生）
	 *----------------------------------------------------------------------**/
	public boolean deleteMemberInfo(int pk){

		//-------------------------------------------
		//JDBCドライバのロード
		//-------------------------------------------
		try {
			Class.forName(DRIVER_NAME);       //JDBCドライバをロード＆接続先として指定
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

		//-------------------------------------------
		//SQL発行
		//-------------------------------------------

		//JDBCの接続に使用するオブジェクトを宣言
		//※finallyブロックでも扱うためtryブロック内で宣言してはいけないことに注意
		Connection        con = null ;   // Connection（DB接続情報）格納用変数
		PreparedStatement ps  = null ;   // PreparedStatement（SQL発行用オブジェクト）格納用変数

		//実行結果（真：成功、偽：例外発生）格納用変数
		//※最終的にreturnするため、tryブロック内で宣言してはいけないことに注意
		boolean isSuccess = true ;

		try {

			//-------------------------------------------
			//接続の確立（Connectionオブジェクトの取得）
			//-------------------------------------------
			con = DriverManager.getConnection(JDBC_URL, USER_ID, USER_PASS);

			//-------------------------------------------
			//トランザクションの開始
			//-------------------------------------------
			//オートコミットをオフにする（トランザクション開始）
			con.setAutoCommit(false);

			//-------------------------------------------
			//SQL文の送信 ＆ 結果の取得
			//-------------------------------------------

			//発行するSQL文の生成（DELETE）
			StringBuffer buf = new StringBuffer();
			buf.append(" DELETE FROM uzuz_member ");
			buf.append("  WHERE id = ?           ");  //第1パラメータ

			//PreparedStatementオブジェクトを生成＆発行するSQLをセット
			ps = con.prepareStatement(buf.toString());

			//パラメータをセット
			ps.setInt( 1, pk );  //第1パラメータ：削除対象ID

			//SQL文の送信＆戻り値として削除件数を取得
			int delCount = ps.executeUpdate();

			//SQL実行結果を表示
			System.out.println("[INFO]" + delCount + "行削除しました") ;

		} catch (SQLException e) {
			e.printStackTrace();

			//実行結果を例外発生として更新
			isSuccess = false ;

		} finally {
			//-------------------------------------------
			//トランザクションの終了
			//-------------------------------------------
			if(isSuccess){
				//明示的にコミットを実施
				try {
					con.commit();
				} catch (SQLException e) {
					e.printStackTrace();
				}

			}else{
				//明示的にロールバックを実施
				try {
					con.rollback();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}

			//-------------------------------------------
			//接続の解除
			//-------------------------------------------

			//PreparedStatementオブジェクトの接続解除
			if (ps != null) {    //接続が確認できている場合のみ実施
				try {
					ps.close();  //接続の解除
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}

			//Connectionオブジェクトの接続解除
			if (con != null) {    //接続が確認できている場合のみ実施
				try {
					con.close();  //接続の解除
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}

		//実行結果を戻す
		return isSuccess ;

	}
```
Del_MainとDAOのSQL文の内容から、IDを一つのみ引数に可能だと考えられる。
だが、データベースにないIDであれば、SQL文のエラーとなるか、他のエラーになるかを念のために確認がしたい。
そのため、引数には「70」（データベースには確実にないと考えられるID）を設定し、実行。
```
[INFO]0行削除しました
[INFO]削除処理が正常終了しました
```
！？　エラーとならなかった。
`[INFO]0行削除しました`と表示されているため、削除されたデータはないと考えられるが、念のために、terminalで確認をする。
```
mysql> select * from UZUZ_MEMBER;
+-----+--------+--------+-----+--------+
| ID  | NAME   | GENDER | AGE | COURSE |
+-----+--------+--------+-----+--------+
|   1 | MOCO   | F      |   4 | PG     |
|   2 | CHOCO  | M      |   7 | INFRA  |
|   3 | TARO   | M      |   5 | PG     |
|   4 | RINRIN | F      |   3 | PG     |
|   5 | CHAMP  | M      |   5 | MARKET |
| 100 | ogawa  | M      |  80 | DX     |
+-----+--------+--------+-----+--------+
6 rows in set (0.00 sec)

mysql> 
```
削除されているようには見受けられなかったため、削除はされていないと判断する。
DAOに以下のコードがあったことからも、削除はされていないと考えられる。
```Java:/Sample_4/src/j4_02/Sample4_02_1_Common_DAO.java
//パラメータをセット
			ps.setInt( 1, pk );  //第1パラメータ：削除対象ID

			//SQL文の送信＆戻り値として削除件数を取得
			int delCount = ps.executeUpdate();

			//SQL実行結果を表示
			System.out.println("[INFO]" + delCount + "行削除しました") ;
```
そもそも、SQL文のエラーがないのか、JDBCではエラーにならないようになるのか、terminalで直接打って確認する。
```
mysql> DELETE FROM uzuz_member where = 70;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '= 70' at line 1
```
エラーが表示された。
そもそも、構文が違った😅 `where = 70;`
構文を修正し、再度確認。
```
mysql> DELETE FROM uzuz_member where id = 70;
Query OK, 0 rows affected (0.00 sec)

```
エラーがないため、自分の勘違いだったことがわかった。

正常な動作を確認するため、「100」を引数に設定して、再度実行した。
```
[INFO]1行削除しました
[INFO]削除処理が正常終了しました
```
コンソール上では正常な動作だと確認ができた。
念のため、terminalでも確認をする。
```
mysql> select * from UZUZ_MEMBER;
+----+--------+--------+-----+--------+
| ID | NAME   | GENDER | AGE | COURSE |
+----+--------+--------+-----+--------+
|  1 | MOCO   | F      |   4 | PG     |
|  2 | CHOCO  | M      |   7 | INFRA  |
|  3 | TARO   | M      |   5 | PG     |
|  4 | RINRIN | F      |   3 | PG     |
|  5 | CHAMP  | M      |   5 | MARKET |
+----+--------+--------+-----+--------+
5 rows in set (0.00 sec)
```
正常に削除されていることが確認できた。

以上で、サンプルコードの確認を終える。

ここまで、以下のことが気になり、修正がしたい。
・DAOで接続の確立と切断に関するコードが全く同じなのに行われている。
　→ 別のクラスやメソッドでまとめ、コードの数を減らしたい。
・どの処理でも、複数のレコードを処理できるようにしたい。
　→ Mainもしくは、Buigenes_Logicで繰り返し構文を使用できるようにしたい。
・引数の設定がめんどくさい。（UIに改良の余地があると考えられる）
　→ argsによってコマンドラインから引数を設定するようになっている処理をprintでコンソール上からできるようにしたい。
　→ Mainの切り替えをなくし、一つのMainに引数を渡してできるようにしたい。

他、それぞれの処理に関しての修正したいことは記事の最後に記述しているため、ここでは省略する。

次回、JDBC勉強備忘録（DAOの接続、切断を修正）