[JAVA]JDBC - DB Connection 활용
JDBC를 활용한 DB와 상호작용
본격적으로 Connection과 Statement를 활용한 DB에서 CRUD를 해보는 연습을 해보자
그 전에 간단하게 close와 Connection, 드라이버 적재를 어떻게 동작하게 할 것인지 먼저 설정하자
1.드라이버 적재는 클래스가 로드되는 동시에 적재되면 되기에 static 블럭을 활용하여 클래스 로드가 되는 동시에 동작되도록 했다.

2.다음으로 커넥션을 생성하는 메소드를 만들었다.

3. 다음으로 인터페이스를 close할 수 있도록 해주는 메소드도 생성했다.

정의한 메소드들을 라이브러리를 활용하여 타 프로젝트파일에서 사용할 수 있도록 한다.
Create
DB와 연결하여 book테이블을 생성하는 메소드를 만들어보았다.

executeUpdate파라미터에 SQL명령문을 넣어 pk, title, price 컬럼을 갖는 테이블을 만들었다.
executeUpdate는 int값을 반환하는데, 이는 SQL에서 볼 수 있는 명령문이 실행된 후 행의 갯수 값을 반환한다.
Insert, Delete, Update
[Insert]
위의 Create에서 executeUpdate파라미터에 Insert 명령문을 넣어 insert메소드를 만들어보았다.
컬럼정보를 파라미터를 통해 받아 int값을 반환하도록 만들었다.
public static int insertBook(int no, String title, int price) {
Connection conn = makeConnection();
Statement stmt = null;
try {
// 명령어(insert into) 수행
// statement객체는 명령 마무리에 자동으로 세미콜론을 찍어준다.
stmt = conn.createStatement();
int result = stmt.executeUpdate(
"INSERT INTO book (no, title, price) VALUES (" + no + ", '" + title + "', " + price + ");");
return result;
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 접속해제
closeStatement(stmt);
closeConnection(conn);
}
return 0;
}

[Delete]
똑같이 pk값을 건네받아 executeUpdate파라미터에 DELETE 명령문과 삭제를 원하는 행의 pk값을 넣게되면 해당 행이 삭제되는 메소드를 만들었다.
public static int deleteBook(int no) {
Connection conn = makeConnection();
Statement stmt = null;
try {
stmt = conn.createStatement();
return stmt.executeUpdate("DELETE FROM book WHERE no = " + no + ";");
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 접속해제
closeStatement(stmt);
closeConnection(conn);
}
return 0;
}
[Update]
public static int updateBook(int no, String newTitle, int newPrice) {
Connection conn = makeConnection();
Statement stmt = null;
try {
stmt = conn.createStatement();
return stmt.executeUpdate(
"UPDATE book SET title = '" + newTitle + "', price = " + newPrice + " WHERE no = " + no + ";");
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 접속해제
closeStatement(stmt);
closeConnection(conn);
}
return 0;
}
Select
셀렉트 명령어는 조금 다른 메소드를 활용해야한다.
똑같이 커넥션과 스테이트먼트를 생성하지만 executeQuery메소드를 활용해야한다.
executeQuery는 ResultSet을 반환하며 이 객체에 하나의 행정보가 담기게 된다.
ResultSet클래스의 next메소드는 꺼낼 행이 있다면 true 없다면 false를 반환하며
ResultSet의 getter를 활용해 각각의 컬럼값을 가져 올 수 있다.
나는 각각의 컬럼값을 가져와 java에서 쓸 수 있는 Book객체로 만들어 list에 담아 반환할 수 있도록 메소드를 작성하였다.
public static List<Book> selectAllBook() {
Connection conn = makeConnection();
Statement stmt = null;
ResultSet rs = null;
List<Book> list = new ArrayList<>();
try {
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT * FROM book WHERE title = '파워자바';");
while (rs.next()) {
int no = rs.getInt("no");
String title = rs.getString("title");
int price = rs.getInt("price");
list.add(new Book(no, title, price));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
closeResultSet(rs);
closeStatement(stmt);
closeConnection(conn);
}
return list;
}
다음과 같이 하나의 컬럼값을 건네받아 해당 컬럼값과 같은 book정보를 확인할수도 있다.
public static List<Book> selectBookByTitle(String t) {
Connection conn = makeConnection();
Statement stmt = null;
ResultSet rs = null;
List<Book> list = new ArrayList<>();
try {
stmt = conn.createStatement();
// ResultSet = 한 행의 정보를 전달해줌
rs = stmt.executeQuery("SELECT * FROM book WHERE title = '" + t + "';");
while (rs.next()) {
int no = rs.getInt("no");
String title = rs.getString("title");
int price = rs.getInt("price");
list.add(new Book(no, title, price));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
closeResultSet(rs);
closeStatement(stmt);
closeConnection(conn);
}
return list;
}
Restaurnat 정보 조회 연습
1. Connection,Statement, ResultSet, List 생성

2. executeQuery로 명령 ("SELECT * FROM restaurant")

3. next메소드로 행정보를 건네받아 각각의 컬럼의 자료형에 맞게 getter호출, 초기화한 컬럼값들을
Restaurant 생성자 파라미터에 넣는다.

4. 생성된 객체를 list에 add한 후 next가 모든 행 정보를 가져왔을 때 list가 반환되게끔 한다.
// 식당 전부 다 조회하기
public List<Restaurant> selectAll() {
Connection conn = ConnectionProvider.makeConnection();
Statement stmt = null;
ResultSet rs = null;
List<Restaurant> list = new ArrayList<>();
try {
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT * FROM restaurant");
while (rs.next()) {
int id = rs.getInt("no");
String name = rs.getString("name");
String phoneNumber = rs.getString("phoneNumber");
String address = rs.getString("address");
double score = rs.getDouble("score");
list.add(new Restaurant(id, name, phoneNumber, address, score));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
ConnectionProvider.closeResultSet(rs);
ConnectionProvider.closeStatement(stmt);
ConnectionProvider.closeConnection(conn);
}
return list;
}
[집계 식당 총 개수 구하기]
처음 만들었을 때에는 이렇게 모든 행을 구하고 그 list의 size개수를 반환하게끔 만들었는데
rs = stmt.executeQuery("SELECT COUNT(score) FROM restaurant");
int count = rs.getInt(COUNT(score))를 하게되면 집계함수 값이 반환되는 것을 알게 되었다.
명령문을 용도에 맞게 작성하자. 모든 행을 조회하는 것은 용도에 맞지 않다.

[식당 이름으로 검색해서 조회하기]
// 식당 이름으로 검색해서 조회하기
public List<Restaurant> selectRestaurantByName(String restName) {
Connection conn = ConnectionProvider.makeConnection();
Statement stmt = null;
ResultSet rs = null;
List<Restaurant> list = new ArrayList<>();
try {
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT * FROM restaurant WHERE name = '" + restName + "';");
while (rs.next()) {
int id = rs.getInt("no");
String name = rs.getString("name");
String phoneNumber = rs.getString("phoneNumber");
String address = rs.getString("address");
double score = rs.getDouble("score");
list.add(new Restaurant(id, name, phoneNumber, address, score));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
ConnectionProvider.closeResultSet(rs);
ConnectionProvider.closeStatement(stmt);
ConnectionProvider.closeConnection(conn);
}
return list;
}
[식당 정보가 담긴 list를 건네받아 INSERT해보기]
처음 의도는 list를 건네받아 for문을 활용해 list의 각 index를 Update하는 식으로 접근했었다.
그리고 listsize를 반환하여 몇 행이 추가되었는지 알 수 있도록 해주었다.
public int createValues(List<Restaurant> list) {
Connection conn = ConnectionProvider.makeConnection();
Statement stmt = null;
try {
stmt = conn.createStatement();
for (int i = 0; i < list.size(); i++) {
String name = list.get(i).getName();
String phoneNumber = list.get(i).getPhoneNumber();
String address = list.get(i).getAddress();
double score = list.get(i).getScore();
stmt.executeUpdate("INSERT INTO restaurant (name, phoneNumber, address, score)" + " VALUES ('" + name
+ "', '" + phoneNumber + "', '" + address + "', " + score + ")");
}
return list.size();
} catch (SQLException e) {
e.printStackTrace();
} finally {
ConnectionProvider.closeStatement(stmt);
ConnectionProvider.closeConnection(conn);
}
return 0;
}
이 방법은 강의실 다른 친구가 생각해낸 방법인데, 인상 깊었다.
foreach문을 활용하였고, 기존에 정의해 둔 create메소드를 list에 객체가 있을 때마다 실행되게끔, 꺼내온 r값은 create파라미터에 들어가도록 만들었다. 훨씬 보기편하고 간결해진 것을 볼 수 있다.

기존 create메소드 정의는 이렇다.
// 식당 행 추가하기
public int create(String name, String phoneNumber, String address, double score) {
Connection conn = ConnectionProvider.makeConnection();
Statement stmt = null;
try {
stmt = conn.createStatement();
return stmt.executeUpdate("INSERT INTO restaurant (name, phoneNumber, address, score)" + " VALUES ('" + name
+ "', '" + phoneNumber + "', '" + address + "', " + score + ")");
} catch (SQLException e) {
e.printStackTrace();
} finally {
ConnectionProvider.closeStatement(stmt);
ConnectionProvider.closeConnection(conn);
}
return 0;
}