일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- SESSION
- MVC
- js
- 고객센터 구현
- 일단_해보는거야
- jquery
- ajax
- jsp 프로젝트
- jsp
- 세션
- 프로그래머스
- 인증코드로 비밀번호 변경 구현
- java
- json
- MySQL
- 자바
- 오라클
- 교보문고 따라하기
- Spring MVC
- Oracle
- jakarta.mail
- Level 1
- 이메일로 인증코드 전송 구현
- 로그인과 장바구니 구현
- 다중 카테고리 구현
- Spring
- 대분류/중분류/소분류
- 스프링
- 코딩
- Sts
감 잃지말고 개발하기
[Error][Java][DB] java.sql.SQLException: org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement with address: "NULL" is closed. 본문
[Error][Java][DB] java.sql.SQLException: org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement with address: "NULL" is closed.
persii 2023. 5. 20. 01:01ERROR
java.sql.SQLException :
org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement with address: "NULL" is closed.
배경
아래 CartDAO 클래스의 insertCart() 메서드를 실행하는 도중 에러가 발생했다.
insertCart() 메서드는 ArrayList<Integer> 타입의 idList와 String 타입의 s_userId를 인자로 받아 idList의 배열 길이만큼 for문을 돌리면서 idList의 요소를 DB 테이블에 저장하는 역할을 수행한다.
public class CartDAO {
Connection conn;
/** 도서 아이디(배열)와 로그인 아이디를 DB에 추가하는 메서드
* @throws SQLException */
public int insertCart(ArrayList<Integer> idList, String s_userId) throws SQLException {
int insertCount = 0;
String sql = "INSERT INTO jspbookshop.cart VALUES(NULL,?,?,?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
for (int id : idList) {
try {
pstmt.setString(1, s_userId);
pstmt.setInt(2, id);
pstmt.setInt(3, 1);
insertCount += pstmt.executeUpdate();
} catch (Exception e) {
System.out.println(" Ca.DAO: insertCart(idList) ERROR: " + e);
} finally {
JdbcUtil.close(pstmt);
}
}
return insertCount;
}
}
원인
It suggests that the PreparedStatement object is being closed before it is used.
즉, PreparedStatement 객체가 필요한만큼 사용되기도 전에 닫혀버려 일어난 에러였다.
위 코드에서 첫 번째 for문을 돌 때 finally 문에서 clost(pstmt) 메서드로 PreparedStatement 객체를 닫아버려(리소스 해제) 사용할 PreparedStatement 객체가 없어진 것이다.
해결
자바 7부터 제공하는 try-with-resources 문을 사용하여 try문의 괄호 안에 사용할 리소스(PreparedStatement 객체)를 선언한다.
try문 괄호 안에 PreparedStatement 객체를 선언하면,
루프를 돌 때마다 새로운 PreparedStatement 객체가 try-with-resources 블록 안에 생성되게 된다.
그런 후 PreparedStatement 객체가 완전히 사용되면 예외가 발생하더라도 PreparedStatement 인터페이스가 상속한 AutoCloseable 인터페이스의 close() 메서드로 인해 정상적으로 해제되게 된다.
public class CartDAO {
Connection conn;
/** 도서 아이디(배열)와 로그인 아이디를 DB에 추가하는 메서드
* @throws SQLException */
public int insertCart(ArrayList<Integer> idList, String s_userId) throws SQLException {
int insertCount = 0;
String sql = "INSERT INTO jspbookshop.cart VALUES(NULL,?,?,?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
for (int id : idList) {
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, s_userId);
pstmt.setInt(2, id);
pstmt.setInt(3, 1);
insertCount += pstmt.executeUpdate();
} catch (Exception e) {
System.out.println(" Ca.DAO: insertCart(idList) ERROR: " + e);
}
}
return insertCount;
}
}
♠ 추가 설명 ♠
1. try-with-resources 문
자바 7부터 제공하는 try-with-resources 문은 close() 메서드를 명시적으로 호출하지 않아도 try 블록 내에서 열린 리소스를 자동으로 닫도록 만들어준다.
단, try-with-resources 문을 사용하기 위해선 해당 리소스가 AutoCloseable 인터페이스를 구현해야 한다.
JavaDoc에서 해당 리소스 PreparedStatement 인터페이스를 살펴보면 해당 인터페이스는 Statement 인터페이스를 상속하고 있고, 이 Statement 인터페이스가 AutoCloseable 인터페이스를 상속하고 있음을 알 수 있다.
2. AutoCloseable 인터페이스
An object that may hold resources (such as file or socket handles) until it is closed. The close() method of an AutoCloseable object is called automatically when exiting a try-with-resources block for which the object has been declared in the resource specification header. This construction ensures prompt release, avoiding resource exhaustion exceptions and errors that may otherwise occur.
- javadoc
AutoCloseable 객체는 파일, 소켓 등의 자원을 보유할 수 있는데,
해당 객체의 close() 메서드는 해당 객체를 상속한 리소스가 try-with-resources 블록을 벗어날 때 자동으로 호출된다.
그래서 만약 예외가 발생할 시 리소스의 close() 메서드가 먼저 호출된 이후에 예외 블록 부분(catch 블록)이 수행된다.
이 구조는 리소스 고갈 예외와 오류를 방지하기 위해 즉시 해제되도록 보장한다.
♠ Java 8 JavaDoc 페이지 ♠
https://docs.oracle.com/javase/8/docs/api/index.html
Java Platform SE 8
docs.oracle.com
끝.
'Java > Error' 카테고리의 다른 글
[JAVA][ERROR] 'javac'은(는) 내부 또는 외부 명령, 실행할 수 있는 프로그램, 또는 배치 파일이 아닙니다. (0) | 2023.08.10 |
---|---|
[Error][Java][Android] java.net.UnknownHostException (0) | 2022.12.19 |