2009-06-11 4 views
8

오라클 데이터베이스를 사용하여 다른 서비스와의 상호 작용 및 단계를 추적하는 Java 워크 플로 응용 프로그램이 있습니다. 워크 플로를 실행하는 동안 여러 개의 삽입/업데이트/선택이 수행되며 성공적으로 완료되기 전에 실행 된 삽입/업데이트 커밋이 있더라도 select에서 업데이트 된 데이터를 반환하지 않는 경우가 있습니다. 워크 플로우 오류 (잘못된 데이터로 인해)가 끝난 후, 제 3 자 앱을 통해 데이터베이스로 돌아 가면 새로운/업데이트 된 데이터가 표시됩니다. 우리의 위탁이 통과 될 때와 보이는 때 사이에 지연이있는 것 같습니다. 이는 모든 워크 플로 실행 중 약 2 %에서 발생하며 데이터베이스 사용량이 많은 경우 증가합니다.커밋과 선택 사이의 오라클 지연

데이터베이스 지원 팀은 max-commit-propagation-delay 매개 변수를 기본값 인 700으로 변경하는 것이 좋습니다. 이것은 가능한 해결책 인 것처럼 보였지만 궁극적으로 우리의 문제를 해결하지 못했습니다.

응용 프로그램이 WebSphere에서 실행되고 Oracle 데이터베이스가 JDBC 데이터 소스로 구성됩니다. 우리는 Oracle 10.1g을 사용하고 있습니다. 이 애플리케이션은 Java 1.5로 작성되었습니다.

도움을 주시면 감사하겠습니다.

편집 : ORM을 사용하여 샘플 코드

DataSource ds; // spring configured 

String sql = "INSERT INTO " + currentTable + " (" + stepId + ',' + stepEntryId + ", " + stepStepId + ", " + stepActionId + ", " + stepOwner + ", " + stepStartDate + ", " + stepDueDate + ", " + stepFinishDate + ", " + stepStatus + ", " + stepCaller + ") VALUES (?, ?, ?, null, ?, ?, ?, null, ?, null)"; 

Connection conn = ds.getConnection(); 
PreparedStatement stmt = conn.prepareStatement(sql); 
// set values 
stmt.executeUpdate(); 
// close connections 

// later on in the code... 
Connection conn = ds.getConnection(); 
PreparedStatement stmt = null; 
ResultSet rset = null; 

String sql = "SELECT " + stepId + ", " + stepStepId + ", " + stepActionId + ", " + stepOwner + ", " + stepStartDate + ", " + stepDueDate + ", " + stepFinishDate + ", " + stepStatus + ", " + stepCaller + " FROM " + currentTable + " WHERE " + stepEntryId + " = ?"; 
stmt = conn.prepareStatement(sql); 

stmt.setLong(1, entryId); 

rset = stmt.executeQuery(); 
//close connections 
+0

[Oracle 설명서] (http://download.oracle.com/docs/cd/B14117_01/server.101/b10755/initparams115.htm)의 매개 변수 'max_commit_propagation_delay'는 RAC 설정에만 적용되는 것으로 보입니다. RAC 인스턴스에 연결하고 있습니까? –

+0

데이터가 트랜잭션의 일부로 커밋되고 있습니까? 아니면 읽었습니까? –

답변

1

있습니다 사용? 그것은 캐시에서 선택하고 변경 후 DB를 형성하지 않을 수 있습니다.

+0

우리는 ORM을 사용하지 않고 있으며 테이블과 SQL 문은 실제로 기본이며 소량의 추적 정보를 저장하는 데 사용됩니다. – Andrew

+0

가능한 경우 코드 조각 게시 ... –

+1

@Steve Broberg 제안이 작동하지 않으면 동일한 연결을 사용해보십시오 –

6

기본적으로 설명한 동작은 불가능합니다. 커밋 된 트랜잭션의 변경 사항은 모든 세션에서 즉시 사용할 수있게됩니다. 그러나 예외가 있습니다.

  1. COMMIT 명령에서 WRITE 옵션을 사용하고 있습니까? 그렇지 않은 경우, COMMIT_WRITE 초기화 매개 변수의 값을 확인하십시오. 둘 중 하나가 "WRITE BATCH"또는 특히 "WRITE BATCH NOWAIT"를 사용하는 경우 동시성 문제까지 스스로를 열 수 있습니다. "WRITE BATCH NOWAIT"은 일반적으로 쓰기 트랜잭션의 속도가 가능한 동시성 문제보다 더 중요한 경우에 사용됩니다. 초기화 매개 변수가 "WRITE"변형을 사용하는 경우 커밋에 IMMEDIATE 절을 지정하여 트랜잭션 기준으로 재정의 할 수 있습니다 (see COMMIT)

  2. 데이터를 읽으려고하는 트랜잭션이 이전에 SET TRANSACTION 커밋하는 다른 거래로? 읽어 직렬화 레벨을 지정하는 SET 트랜잭션을 사용하는 경우에만 또는 SET 트랜잭션의 호출 이후에 발생한 다른 커밋 세션에서 발생하는 변경을보고하지 않는 트랜잭션 (see SET TRANSACTION)

편집 발생합니다 SERIALIZABLE : 나는 것을 볼 수 DataSource 클래스를 사용하고 있습니다. 이 클래스에 익숙하지 않습니다. 연결 공유 리소스라고 가정합니다. 현재의 앱 디자인은 작업 흐름 전체에서 동일한 연결 개체를 사용하기가 쉽지 않을 수 있음을 알았습니다.이 단계는 독립적으로 작동하도록 설계되었으며 한 단계에서 다른 단계로 연결 개체를 전달하는 기능을 구축하지 않았습니다. next), 그러나 열려있는 트랜잭션과 관련하여 DataSource 객체에 반환되는 연결 객체가 "깨끗한"것인지 확인해야합니다. 코드에서 SET TRANSACTION을 호출하지 않을 수도 있지만 DataSource의 다른 소비자가 다른 곳에서 그렇게 할 수 있으며 SERIALIZABLE 또는 READ ONLY 모드의 세션을 계속 사용하여 데이터 소스로 다시 연결을 반환 할 수 있습니다. 연결을 공유 할 때 모든 연결을 새 소비자에게 전달하기 전에 롤백해야합니다.

DataSource 클래스의 동작을 제어하거나 볼 수없는 경우 새로 획득 한 연결에서 ROLLBACK을 실행하여 느린 트랜잭션이 이미 설정되지 않았는지 확인할 수 있습니다.

+0

+1 !!! 나는 IMMEDIATE WAIT가 아닌 COMMIT를 고려했거나 트랜잭션 격리 수준이 READ COMMITTED가 아닌 것으로 생각했습니다. – spencer7593

+0

환불을 늦게 드려 죄송합니다. 내가 커밋을 위해 쓰기 옵션을 사용하고 있다고 생각하지 않습니다. 난 그냥 자바 연결 클래스 기본값을 사용하고, 트랜잭션 격리 설정에 대한 간다. 여기에 내가 사용하고있는 자바 클래스에 대한 몇 가지 문서 링크는 다음과 같습니다 http://java.sun.com/j2se/1.5.0/docs/api/javax/sql/DataSource.html HTTP : //java.sun .com/j2se/1.5.0/docs/api/java/sql/Connection.html http://java.sun.com/j2se/1.5.0/docs/guide/jdbc/getstart/connection.html – Andrew

4

DBA 팀이 max_commit_propagation_delay 매개 변수를 수정하려고 한 경우 이는 아마도 하나의 단일 데이터베이스에 액세스하는 여러 개의 별개 서버 인 RAC 인스턴스에 연결하고 있음을 의미합니다.

그런 경우 Java 코드에서 연결을 닫았다가 다시 열면 다른 서버가 응답 할 수 있습니다. 지연 매개 변수는 두 인스턴스가 정확히 동일한 시점에 있지 않을 때 작은 시간 프레임이 있음을 의미합니다. 귀하가 얻는 답은 한 시점과 일치하지만 가장 최신의 것은 아닙니다.

KM에서 제안한 가장 쉬운 해결책은 커밋 후에 연결을 유지하는 것입니다.

또는 실용적인 경우 연결을 종료 한 후에 지연을 추가 할 수도 있습니다 (배치 작업이고 응답 시간이 중요하지 않은 경우).

0

두 개의 서로 다른 인스턴스에 연결되어 있고 SCN이 동기화되지 않은 경우 RAC에 문제가있는 것 같습니다.

해결 방법으로 데이터베이스 연결을 닫고 새 연결을 가져 오지 않지만 동일한 연결을 다시 사용하지 않는 것이 좋습니다.

작동하지 않는 경우 삽입 된 행을 검색하려고 시도하는 쿼리에 다시 시도하십시오. 행이 리턴되지 않은 경우 약간 잠을 자고 조회를 다시 시도하십시오. 루프에 넣으십시오. 지정한 횟수만큼 재시도하면 실패 할 수 있습니다. 그의 대답에서

[부칙]

, 스티브 Broberg (+1!) 흥미로운 아이디어를 발생시킵니다. 내가 고려하지 않았 :

  • COMMIT 트랜잭션 격리 수준이 READ 이외의 다른 COMMITTED 수 있습니다 IMMEDIATE WAIT
  • 이외의 다른 수 있습니다

나는 플래시백 쿼리의 가능성을 고려했고, OP가 플래시백 쿼리를 사용한다는 명확한 이유는 없으며 코드 스 니펫에 그러한 증거가 없음을 알 수 없으므로이를 언급하지 않고이를 기각했다.

[/ ADDENDUM]

0

가능한 해결 방법은 JTA 트랜잭션을 사용하는 것일 수 있습니다. 다중 열기/닫기 jdbc conn을 통해 연결이 "장면 뒤에서"열리도록합니다. 어쩌면 동일한 서버에 연결을 유지하고이 동기화 문제를 피할 수 있습니다.

UserTransaction transaction = (UserTransaction)new InitialContext().lookup("java:comp/UserTransaction"); 
transaction.begin(); 
// doing multiple open/close cxs 
transaction.commit(); 
0

코드 스 니펫에 실제로 커밋이 포함되지 않았습니다.

닫기 연결을 사용하여 커밋을 수행하는 것으로 가정하면/동기화되지 않을 수 있습니다 (즉, Java에서 연결을 종료하도록 Oracle에 알릴 때 연결이 닫힌 것으로보고 할 수 있습니다. 오라클에 의해 완료).

+0

http : 자동으로 각을 실행 한 후 변경 내용을 커밋 것을 의미 Connection 객체가 자동 위탁 모드에 기본적으로 //java.sun.com/j2se/1.5.0/docs/api/java/sql/Connection.html , 성명서. – Andrew

+0

헉. 그러나 커밋이 수행되는 방법/시점에 대한 제어권이 없기 때문에 동일하게 적용될 수 있습니다. 게다가, 불필요하게 커밋에 성능 저하 (및 데이터 무결성 결과)가 있습니다. 그것을 끄고 명시 적으로 커밋하고 문제가 사라지는지 확인하십시오. –

0

코드에 커밋이 없습니다.이러한 응용 프로그램에서 가장 중요한 문구이므로 close() 등을 사용하지 않고 항상 명시 적으로 작성해야합니다.

또한 자동 커밋 정확히 동작을 (그것이 모든 삽입/업데이트 후 커밋) 설명 할 연결 (들)에 기본적으로 true로 설정했을 수 있습니다.

원하는대로 정확하게 커밋했는지 확인할 수 있습니까? 예 : 전에 거래의 끝에서?

당신이 부분적 통해 때 커밋이있는 경우

는, 당신은 또한 부하가 클 때 더 많은 문제가있는 이유를 설명 할 수 귀하의 스레드 간의 경쟁 조건을 가지고있다.

+0

내가 본 동작을 어떻게 설명 할 지 모르지만 자동 커밋을 true로 설정했습니다. insert 및 executeUpdate()를 수행하여 자동 커밋 한 다음 나중에 select를 수행하고 삽입 된 행을 찾을 수 없습니다. executeUpdate()가 커밋 될 때까지 반환되지 않는다는 것을 고려하면 어떻게 경쟁 조건이 발생할 수 있는지를 알 수 없습니다. – Andrew

0

"성공적으로 완료되기 전에 실행 된 삽입/업데이트 커밋에도 불구하고."

이 당신이이 commit()을 발행 한 다음 이후 (즉, 반복 읽기의) 다시 정확히 같은 데이터를 읽을 것으로 예상되는 나에게 제안합니다.

이것은 나에게 당신이 저 지르지 말아야한다는 것을 암시합니다. NO TASK이 안정적으로 유지 될 것으로 예상되는 데이터를 수정할 수 없다는 것을 확인하고 싶다면 잠금을 해제 할 수 없습니다 (이는 커밋과 동일합니다). 당신이 어떤 리소스에 대한 잠금을 유지하면서, 다른 스레드는 "해당 자원을 사용할 수있게 기다리고"쌓아됩니다

참고. 잠금을 해제 할 때 해당 스택이 비어 있지 않은 가능성은 일반 시스템로드가 높을수록 높습니다. 그리고 DBMS가 "커밋"을 할 때 결론을 내리는 것은 "이봐, 와우,이 사람은 마침내이 자료로 끝난다. 그래서 지금 나는 다른 대기자들 모두 시도하고 할 수있게 할 수있다. 그들과 함께하는 것 (그리고 "그들의 것을"업데이트하지 못하도록 막는 것은 아무것도 없다!) ".

제가 간과하고있는 오라클의 스냅 샷 격리와 관련된 문제가있을 수 있습니다. 그렇다면 죄송합니다.

관련 문제