回答編集履歴

1

テーブルを 1 つにしたコードに全面変更

2024/03/02 17:14

投稿

jimbe
jimbe

スコア12672

test CHANGED
@@ -1,21 +1,7 @@
1
- 質問等の感じからして、あまり仕様を意識せずなんとなく作られていて、ある部分を作った時と別部分を作った時とでその瞬間の考えが違っていてあちこちで齟齬が起きているのではないでしょうか。
2
- カレーを作か肉じゃを作るかシチューを作るか決めないま料理をしているようなのです。作慣れているならそれでも何とすが、調べがら作っている状態では何が起きるか分かりせん
1
+ SELECT に関す情報質問に追加されましたが、テーブルが 2 つあっどちら有ったったりするの原因で複雑処理・SELECT 文になっていま
2
+ テーブルを 1 つに纏めてしまえば id の問題も SELECT の複雑さも無くなり処理が簡単になります。
3
3
 
4
- とりあえずネットワークは関係無さそうですのでデータベースの部分だけに注目してみます。
5
- テキスト(とユーザ名)を保存する mutters テーブルと画像を保存して関係するテキストの id を持つ filepaths テーブルがあり、テキスト+画像、テキストのみ、画像のみの 3 パターンでテーブルに保存するメソッド insertTextAndImage を考えます。
6
- 仕様としては
7
-
8
- - text があれば texts テーブルに保存する.
9
- - image があれば images テーブルに保存する. この時 text もあって texts テーブルに保存していたら、 texts_id にその id を入れる.
10
-
11
- の 2 点のみです。まずはこれだけをしっかり作ります。
12
- テーブル構造がアプリに対して十分なのかは(現状こちらには情報がありませんので)考えません。
13
-
14
- テキストの保存メソッドとイメジの保存メソッドをそれぞれり、 insertTextAndImage は必要データが有れば必要メソッドを適切なパラメータで呼ぶこに集中します。
4
+ テキストが無い時や画像が無い時等はぞれぞれレコードを作れば何かの節約に考えられたのかもせんが、そのような最適化を考えるのは時期尚早です。
15
- このように小さな機能をメソッドとして完結するよう定義し、それらを組み合わせてより大きくしていく構造を意識しておくと、混乱し難いかもしれません。(個人の感想です。)
16
-
17
- **※Spring を使わないため Image クラスはダミーを定義・利用しています。**
18
-
19
5
  ```java
20
6
  import java.io.IOException;
21
7
  import java.io.InputStream;
@@ -28,102 +14,71 @@
28
14
  public static void main(String[] args) throws Exception {
29
15
  try(Connection conn = DriverManager.getConnection("jdbc:h2:~/test", "sa", "")) {
30
16
  initTables(conn);
31
- ボールドテキスト
17
+
32
- // 3パターンをテスト
18
+ // 3パターンをテスト(少し時間を開けて insert )
33
19
  //text & image
34
- insertTextAndImage(conn, "Aaa", "ABCDEFG", new Image("test1", new byte[]{1,2,3,4}));
20
+ insertPost(conn, "Aaa", "ABCDEFG", "file1", new Image("type1", new byte[]{1,2,3,4}));
35
21
  //text only
22
+ Thread.sleep(10);
36
- insertTextAndImage(conn, "Bbb", "abcdefg", null);
23
+ insertPost(conn, "Bbb", "abcdefg", null, null);
37
24
  //image only
25
+ Thread.sleep(10);
38
- insertTextAndImage(conn, "Ccc", null, new Image("test2", new byte[]{5,6,7,8}));
26
+ insertPost(conn, "Ccc", null, "file2", new Image("type2", new byte[]{5,6,7,8}));
39
27
 
40
28
  //確認
41
29
  printTables(conn);
42
30
  }
43
31
  }
44
32
 
45
- static void insertTextAndImage(Connection conn, String name, String text, Image image) throws SQLException {
33
+ static void insertPost(Connection conn, String name, String text, String file_name, Image image) throws SQLException {
46
- conn.setAutoCommit(false);
34
+ String sql = "INSERT INTO posts (name, datetime, text, image_name, image_type, image) VALUES (?, ?, ?, ?, ?, ?)";
47
35
 
36
+ try(PreparedStatement pstmt = conn.prepareStatement(sql)) {
37
+ //共通
48
- Integer texts_id = null;
38
+ pstmt.setString(1, name);
39
+ pstmt.setTimestamp(2, new java.sql.Timestamp(System.currentTimeMillis()));
40
+ //テキスト
41
+ if(isValid(text)) {
42
+ pstmt.setString(3, text);
43
+ } else {
44
+ pstmt.setNull(3, Types.VARCHAR);
45
+ }
46
+ //画像
49
- if(text != null && text.length() > 0) {
47
+ if(isValid(file_name) && image != null) {
48
+ pstmt.setString(4, file_name);
50
- texts_id = insertText(conn, name, text);
49
+ pstmt.setString(5, image.getContentType());
50
+ pstmt.setBlob(6, image.getFileContent());
51
+ } else {
52
+ pstmt.setNull(4, Types.VARCHAR);
53
+ pstmt.setNull(5, Types.VARCHAR);
54
+ pstmt.setNull(6, Types.BLOB);
55
+ }
56
+
57
+ if(pstmt.executeUpdate() <= 0) {
58
+ throw new IllegalStateException();
59
+ }
51
60
  }
52
-
53
- if(image != null) {
54
- insertImage(conn, texts_id, image.getFileContent(), image.getContentType());
55
- }
56
-
57
- conn.commit();
58
61
  }
59
62
 
60
- static int insertText(Connection conn, String name, String text) throws SQLException {
61
- String sql = "INSERT INTO texts (name, text, tweet_date) VALUES (?, ?, ?)";
62
-
63
- try(PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
64
-
65
- pstmt.setString(1, name);
66
- pstmt.setString(2, text);
67
- pstmt.setDate(3, new java.sql.Date(System.currentTimeMillis()));
68
-
69
- if(pstmt.executeUpdate() > 0) {
63
+ static boolean isValid(String s) {
70
- try(ResultSet generatedKeys = pstmt.getGeneratedKeys()) {
71
- if(generatedKeys.next()) {
72
- return generatedKeys.getInt(1);
64
+ return s != null && !s.isEmpty();
73
- }
74
- }
75
- }
76
- }
77
- throw new IllegalStateException();
78
65
  }
79
66
 
80
- static int insertImage(Connection conn, Integer texts_id, Blob content, String content_type) throws SQLException {
81
- String sql = "INSERT INTO images (texts_id, content, content_type) VALUES (?, ?, ?)";
82
-
83
- try(PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
84
-
85
- if(texts_id == null) {
86
- pstmt.setNull(1, Types.INTEGER);
87
- } else {
88
- pstmt.setInt(1, texts_id);
89
- }
90
- pstmt.setBlob(2, content);
91
- pstmt.setString(3, content_type);
92
-
93
- if(pstmt.executeUpdate() > 0) {
94
- try(ResultSet generatedKeys = pstmt.getGeneratedKeys()) {
95
- if(generatedKeys.next()) {
96
- return generatedKeys.getInt(1);
97
- }
98
- }
99
- }
100
- }
101
- throw new IllegalStateException();
102
- }
103
-
104
- //テスト用 初期化
67
+ //テスト用 初期化
105
68
  static void initTables(Connection conn) throws SQLException {
106
69
  try(Statement stmt = conn.createStatement()) {
107
70
  stmt.execute(
108
- "DROP TABLE IF EXISTS images;"
109
- + "CREATE TABLE IF NOT EXISTS images ("
110
- + " id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,"
111
- + " texts_id INT,"
112
- + " content BLOB,"
113
- + " content_type VARCHAR(32),"
114
- + " update_at TIMESTAMP"
115
- + ");");
116
- stmt.execute(
117
- "DROP TABLE IF EXISTS texts;"
71
+ "DROP TABLE IF EXISTS posts;"
118
- + "CREATE TABLE IF NOT EXISTS texts ("
72
+ + "CREATE TABLE IF NOT EXISTS posts ("
119
73
  + " id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,"
120
74
  + " name VARCHAR(200),"
121
- + " text VARCHAR(200),"
122
- + " tweet_date DATE"
75
+ + " datetime DATETIME,"
76
+ + " text VARCHAR(200)," //テキスト投稿(テキストが無いときは null)
77
+ + " image_name VARCHAR(200)," //画像投稿(画像が無いときは null)
78
+ + " image_type VARCHAR(32)," //同上
79
+ + " image BLOB" //同上
123
- + ")");
80
+ + ");"
124
-
125
- stmt.execute("DELETE FROM filepaths");
126
- stmt.execute("DELETE FROM mutters");
81
+ + "DELETE FROM posts;");
127
82
  }
128
83
  }
129
84
 
@@ -142,24 +97,16 @@
142
97
  //テスト用 確認表示
143
98
  private static void printTables(Connection conn) throws SQLException {
144
99
  try(Statement stmt = conn.createStatement()) {
145
- System.out.println("-- texts --------");
100
+ System.out.println("-- posts --------");
146
- try(ResultSet rs = stmt.executeQuery("SELECT * FROM texts")) {
101
+ try(ResultSet rs = stmt.executeQuery("SELECT id, name, datetime, text, image_name, image_type, image FROM posts ORDER BY datetime DESC")) {
147
102
  while(rs.next()) {
148
103
  System.out.println("ID=" + rs.getInt(1));
149
104
  System.out.println("name=" + rs.getString(2));
105
+ System.out.println("datetime=" + rs.getTimestamp(3));
150
- System.out.println("text=" + rs.getString(3));
106
+ System.out.println("text=" + rs.getString(4));
107
+ System.out.println("image_name=" + rs.getString(5));
151
- System.out.println("date=" + rs.getDate(4));
108
+ System.out.println("image_type=" + rs.getString(6));
152
- }
153
- }
154
- System.out.println("-- images --------");
155
- try(ResultSet rs = stmt.executeQuery("SELECT * FROM images")) {
156
- while(rs.next()) {
157
- System.out.println("ID=" + rs.getInt(1));
158
- Integer texts_id = rs.getInt(2);
159
- if(rs.wasNull()) texts_id = null;
160
- System.out.println("texts_id=" + texts_id);
161
- System.out.println("content=" + toString(rs.getBlob(3)));
109
+ System.out.println("image=" + toString(rs.getBlob(7)));
162
- System.out.println("content_type=" + rs.getString(4));
163
110
  }
164
111
  }
165
112
  }
@@ -167,6 +114,7 @@
167
114
 
168
115
  //テスト用 Blob 表示
169
116
  private static String toString(Blob blob) throws SQLException {
117
+ if(blob == null) return "null";
170
118
  StringJoiner sj = new StringJoiner(",");
171
119
  try(InputStream is = blob.getBinaryStream()) {
172
120
  for(int c ; (c=is.read())!=-1; ) sj.add(String.format("%d", c&0xff));
@@ -177,24 +125,27 @@
177
125
  }
178
126
  }
179
127
  ```
180
- 実行結果
181
128
  ```
182
- -- texts --------
129
+ -- posts --------
130
+ ID=3
131
+ name=Ccc
132
+ datetime=2024-03-03 02:01:07.598
133
+ text=null
134
+ image_name=file2
135
+ image_type=type2
136
+ image=5,6,7,8
137
+ ID=2
138
+ name=Bbb
139
+ datetime=2024-03-03 02:01:07.582
140
+ text=abcdefg
141
+ image_name=null
142
+ image_type=null
143
+ image=null
183
144
  ID=1
184
145
  name=Aaa
146
+ datetime=2024-03-03 02:01:07.563
185
147
  text=ABCDEFG
186
- date=2024-02-29
187
- ID=2
188
- name=Bbb
189
- text=abcdefg
190
- date=2024-02-29
191
- -- images --------
148
+ image_name=file1
192
- ID=1
193
- texts_id=1
149
+ image_type=type1
194
- content=1,2,3,4
150
+ image=1,2,3,4
195
- content_type=test1
196
- ID=2
197
- texts_id=null
198
- content=5,6,7,8
199
- content_type=test2
200
151
  ```