동일한 SELECT문에 대해 동시에 열려 있는 여러 ResultSet 오브젝트

동일한 SELECT문에 대해 여러 ResultSet 오브젝트를 동시에 열어두면 pureQuery가 아닌 API 애플리케이션이 SQL을 정적으로 실행할 때 특정 조건에서 문제점이 발생할 수 있습니다.
해당 조건은 다음과 같습니다.
  • ResultSet 오브젝트가 단일 연결에 의해 열렸습니다.
  • ResultSet 오브젝트가 동일한 커서 속성을 갖는 동일한 SELECT문에 의해 리턴되었습니다.
  • ResultSet 오브젝트가 동시에 열려 있습니다.
  • ResultSet 오브젝트가 WHERE CURRENT OF절을 포함하는 UPDATE 또는 DELETE문에 의해 수정됩니다.

예를 들어, 다음 코드를 고려하십시오.

ResultSet rs1, rs2;

Statement stmt1 = jdbcCon.createStatement(TYPE_FORWARD_ONLY, CONCUR_UPDATABLE);
rs1 = stmt1.executeQuery("SELECT * FROM SCH1.TBL1");
rs1.next();

Statement stmt2 = jdbcCon.createStatement(TYPE_FORWARD_ONLY, CONCUR_UPDATABLE);
rs2 = stmt2.executeQuery("SELECT * FROM SCH1.TBL1");
rs2.next();

PreparedStatement pStmt = jdbcCon.prepareStatement(
	"DELETE FROM SCH1.TBL1 WHERE CURRENT OF " +
	rs2.getCursorName());

SQL문이 동적으로 실행되는 경우, 이 코드는 앰비규어티를 제공하지 않습니다. 그러나 SQL문이 정적으로 실행되고 ResultSet 오브젝트가 동일한 연결로 열린 경우, 문제점이 발생합니다. pureQuery는 pureQuery가 아닌 API 애플리케이션에 대한 SQL문을 캡처할 때 동일한 명령문을 한 번만 캡처합니다. pureQuery가 이 예제의 SQL문을 캡처하면, pureQueryXML 파일에는 SELECT * FROM SCH1.TBL1이라는 하나의 인스턴스가 포함됩니다. pureQuery가 커서에 DB_PDQ_SPC7이라는 이름을 지정하는 경우, pureQueryXML 파일에는 DELETE FROM SCH1.TBL1 WHERE CURRENT OF DB_PDQ_SPC7이라는 하나의 인스턴스도 포함됩니다.

런타임 시 WHERE CURRENT OF절에 커서 이름만 사용하는 경우, pureQuery는 두 가지 ResultSet 오브젝트 중 DELETE문의 커서가 작동하는 오브젝트를 판별할 수 없습니다.

덜 명확한 상황에서 동일한 앰비규어티가 발생할 수 있습니다. 예를 들어, SELECT문이 ResultSet 오브젝트를 리턴하는 메소드에 있을 수 있고, UPDATE 또는 DELETE WHERE CURRENT OF문이 ResultSet 오브젝트를 수신하는 메소드 내부에 입력 매개변수로 있을 수 있습니다.

애플리케이션의 소스 코드에서 문제점이 명확하게 드러나지 않을 수 있습니다. 이러한 이유로 pureQuery는 단일 SELECT문에 대해 둘 이상의 ResultSet 오브젝트가 현재 열려 있음을 감지하는 경우 경고를 로그합니다.

문제점을 방지하는 기술

이러한 앰비규어티를 해결하기 위해 시도할 수 있는 기술은 다음과 같습니다.

WHERE CURRENT OF절 사용 방지
대신에 updateRow(), deleteRow() 및 insertRow() 메소드를 사용하십시오. 이 접근법은 WHERE CURRENT OF를 사용하는 명령문을 지정하는 것보다 객체 지향적입니다.
Statement stmt1 = jdbcCon.createStatement(TYPE_FORWARD_ONLY,CONCUR_UPDATABLE);
rs1 = stmt.executeQuery("SELECT * FROM SCH1.TBL1");
rs1.next();

Statement stmt2 = jdbcCon.createStatement(TYPE_FORWARD_ONLY,CONCUR_UPDATABLE);
rs2 = stmt.executeQuery("SELECT * FROM SCH1.TBL1"); 
rs2.next();

rs2.deleteRow(); 
UPDATE 또는 DELETE문에 WHERE CURRENT OF절을 사용해야 하는 경우, 다음 예제에서처럼 명령문을 준비 또는 실행할 때 ResultSet.getCursorName()에 호출을 임베드할 수 있습니다.
PreparedStatement pStmt = jdbcCon.prepareStatement(
	"DELETE FROM SCH1.TBL1 WHERE CURRENT OF " +
	rs2.getCursorName());
런타임 시 pureQuery는 getCursorName() 메소드를 UPDATE 또는 DELETE문과 연관시킬 수 있으며 따라서 올바른 ResultSet 오브젝트를 명령문과 연관시킵니다. 이러한 연관은 getCursorName() 메소드가 다음 두 위치 중 하나에 표시되는 경우에만 보장됩니다.
  • PreparedStatement를 작성하는 메소드 호출에서 SQL문과 함께
  • 명령문 오브젝트의 execute() 또는 executeUpdate() 메소드에서
애플리케이션이 WHERE CURRENT OF절을 포함하는 UPDATE 또는 DELETE문을 사용하여 해당 오브젝트를 조작하는 경우, 하나의 연결을 사용하여 동일한 SELECT문에 대해 동시에 열려 있는 여러 개의 ResultSet 오브젝트를 조작 안함
이 주제의 시작 부분에 있는 코드는 ResultSet 오브젝트가 독립된 연결에 의해 열린 경우에 작동합니다.

동일한 SQL SELECT문을 z/OS용 DB2에서 실행하기 위한 특성

z/OS®용 DB2®에 대해 동일한 정적 SQL SELECT문을 실행하고 여러 개의 동일한 ResultSet 오브젝트를 열어야 하는 경우, 먼저 JDBC 및 SQLJ용 IBM® 데이터 서버 드라이버 특성 db2.jcc.allowSqljDuplicateStaticQueriesYES 또는 TRUE로 설정해야 합니다.


피드백