itsource

커밋과 선택 사이의 Oracle 시차

mycopycode 2023. 9. 19. 21:03
반응형

커밋과 선택 사이의 Oracle 시차

Oracle 데이터베이스를 사용하여 단계 및 다른 서비스와의 상호 작용을 추적하는 Java Workflow 애플리케이션이 있습니다.워크플로우 실행 중에 여러 개의 삽입/업데이트/선택이 수행되며 성공적으로 완료되기 전에 실행된 삽입/업데이트 커밋이 실행되더라도 선택한 항목이 업데이트된 데이터를 반환하지 않는 경우도 있습니다.워크플로우 오류가 발생한 후(데이터가 좋지 않아), 다시 돌아가서 타사 앱을 통해 데이터베이스를 확인하면 새/업데이트된 데이터가 표시됩니다.우리의 약속이 실행될 때와 실행될 때 사이에 시차가 있는 것 같습니다.이는 전체 워크플로우 실행의 약 2%에서 발생하며 데이터베이스 사용량이 많을 때 증가합니다.

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

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

어떤 도움이라도 주시면 감사하겠습니다.

편집: 샘플 코드

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

기본적으로 설명한 동작은 불가능합니다. 커밋된 트랜잭션에서 변경된 내용은 모든 세션에서 즉시 사용할 수 있습니다.단, 예외는 있습니다.

  1. COMIT 명령에서 WRITE 옵션을 사용하고 있습니까?그렇지 않은 경우 COMIT_WRITE 초기화 파라미터의 값을 확인합니다."WRITE BATCH" 또는 특히 "WRITE BATCH NOWAIT" 중 하나를 사용하는 경우 동시성 문제에 대해 개방적일 수 있습니다."WRITE BATCH NOWAIT"는 일반적으로 동시성 문제보다 쓰기 트랜잭션의 속도가 더 중요한 경우에 사용됩니다.초기화 매개 변수가 "WRITE" 변형을 사용하는 경우 커밋에서 REMINETE 절을 지정하여 트랜잭션 기반으로 재정의할 수 있습니다(COMIT 참조).

  2. SET TRANCE를 호출하는 데이터를 읽으려는 트랜잭션이 다른 트랜잭션보다 먼저 커밋됩니까?SET Transaction을 사용하여 SET Transaction 호출 후에 발생한 다른 커밋된 세션에서 변경 사항이 발생하지 않도록 SET Transaction을 지정하면 트랜잭션이 발생하지 않습니다(SET Transaction 참조).

edit: DataSource 클래스를 사용하고 있습니다.저는 이 수업을 잘 모릅니다. 연결 공유 자원인 것 같습니다.현재의 앱 설계로 인해 워크플로우 전체에서 동일한 연결 객체를 쉽게 사용할 수 없다는 것을 알고 있습니다(단계는 독립적으로 작동하도록 설계될 수 있으며 연결 객체를 한 단계에서 다음 단계로 전달하도록 설비를 구축하지 않았습니다). 하지만 연결 객체가 DataSource 객체로 반환되는지 확인해야 합니다.특히 공개 거래와 관련하여 re "clean".코드에서 SET Transaction(거래 설정)을 호출하지 않을 수도 있지만 다른 데이터 소스의 다른 소비자가 호출하여 세션이 여전히 직렬화 또는 읽기 전용 모드에 있는 상태에서 연결을 데이터 소스로 다시 되돌리는 것일 수도 있습니다.연결 공유 시 모든 연결을 롤백한 후 새 소비자에게 넘겨야 합니다.

DataSource 클래스의 동작에 대한 제어나 가시성이 없는 경우 새로 획득한 연결에 대해 ROLLBACK을 실행하여 아직 트랜잭션이 설정되지 않았는지 확인할 수 있습니다.

max_commit_propagation_delay매개 변수는 RAC 인스턴스(즉, 하나의 단일 데이터베이스에 액세스하는 여러 개의 개별 서버)에 연결하는 것을 의미할 수 있습니다.

이 경우 자바 코드에서 연결을 닫고 다시 열 때 다른 서버에서 응답을 받을 가능성이 있습니다.지연 매개 변수는 두 인스턴스가 정확히 같은 시점에 있지 않을 때 작은 시간 프레임이 있음을 의미합니다.답변은 특정 시점과 일치하지만 가장 최근의 답변은 아닐 수도 있습니다.

KM이 제안한 것처럼, 가장 쉬운 해결책은 커밋 후에 연결을 계속 열어두는 것입니다.

또는 연결이 실제적인 경우(예를 들어 배치 작업이고 응답 시간이 중요하지 않은 경우) 연결을 닫은 후 지연을 추가할 수도 있습니다.

ORM을 사용하고 있습니까? 변경 후 db를 형성하지 않고 캐시에서 선택하는 것일 수 있습니다.

이는 두 개의 다른 인스턴스에 연결되어 SCN이 동기화되지 않는 RAC의 문제로 들립니다.

이를 해결하기 위해 데이터베이스 연결을 닫고 새로 연결하지 말고 동일한 연결을 재사용하는 것을 고려해 보십시오.

작동할 수 없는 경우, 삽입된 행을 검색하는 쿼리에 재시도를 추가합니다.행이 반환되지 않으면 잠시 잠을 자고 쿼리를 다시 시도합니다.이를 루프에 넣으면 지정된 횟수만큼 재시도하면 실패할 수 있습니다.

[부록]

그의 대답에서 스티브 브로버그(+1!)는 흥미로운 아이디어를 제시합니다.다음을 고려하지 않았습니다.

  • COMMIT다가 아닌 일 수도 .IMMEDIATE WAIT
  • 트랜잭션 분리 수준은 READ COMITED가 아닌 다른 수준일 수 있습니다.

저는 플래시백 쿼리의 가능성을 고려했고, OP가 플래시백 쿼리를 사용할 명백한 이유가 없고, 코드 스니펫에도 그런 증거가 없기 때문에 이를 언급하지 않고 무시했습니다.)

[/부속]

JTA 트랜잭션을 사용하는 것이 해결책이 될 수 있습니다.여러 개의 열림/닫힘 jdbc 연결을 통해 "현장 뒤" 연결을 열어 둡니다.아마도 이것이 당신의 연결을 같은 서버에 유지하고 이 동기화 문제를 피할 수 있을 것입니다.

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

코드 조각에 커밋이 포함되어 있지 않습니다.

커밋을 수행하는 근접 연결을 가정하거나 의존하는 경우 동기화되지 않을 수 있습니다(즉, Java가 Oracle에 연결을 닫으라고 할 때 연결을 닫았다고 보고할 수 있음). 즉, Oracle에 의해 커밋이 완료되기 전일 수 있습니다.

당신의 코드에는 커밋이 없습니다.이러한 앱에서 가장 중요한 문구이므로 닫기 등에 의존하지 않고 매번 명시적으로 작성하고 싶습니다.

또한 연결에서 자동 커밋이 기본적으로 true로 설정되어 동작을 정확하게 설명할 수 있습니다(매 삽입/업데이트 후 커밋됩니다).

당신은 당신이 원하는 장소에 정확하게 커밋을 가지고 있는지 확인할 수 있습니까? 예를 들어, 거래가 끝날 때가 아니라 말이죠.

부분적으로 완료된 상태에서 커밋이 발생하면 스레드 간에 경합 조건이 발생합니다. 이는 부하가 더 클 때 더 많은 문제가 발생하는 이유도 설명해 줍니다.

"인서트/업데이트 커밋이 성공적으로 완료되기 전에 실행되었음에도 불구하고"

이것은 당신이 커밋()을 실행하고 있다는 것을 의미하며, 그 후에 정확히 동일한 데이터를 다시 읽기를 기대합니다(반복적으로 읽을 수 있음).

이것은 당신이 범하지 말아야 한다는 것을 암시합니다.명시적으로 안정적으로 유지될 것으로 예상되는 데이터를 다른 작업이 수정할 수 없도록 하려면 잠금을 해제할 여유가 없습니다(커밋이 수행하는 작업).

일부 리소스를 잠금 상태로 유지하는 동안 "해당 리소스를 사용할 수 있을 때까지" 다른 스레드가 쌓입니다.잠금을 해제할 때 해당 스택이 비어 있지 않을 가능성은 일반 시스템 로드가 높을수록 높아집니다.마지막으로 "커밋"을 발행하면 DBMS에서 결론을 내릴 수 있습니다. "이 사람이 드디어 이 리소스를 다 썼군요. 그래서 이제 다른 대기자들도 모두 이 리소스로 작업을 시도하고 수행하도록 할 수 있습니다. (그리고 "그들의 작업"이 업데이트되는 것을 막을 수 있는 것은 아무것도 없습니다!)"라고 결론입니다.

아마도 오라클의 스냅샷 격리와 관련된 문제가 있을 수도 있습니다.그렇다면 죄송합니다.

언급URL : https://stackoverflow.com/questions/983296/oracle-lag-between-commit-and-select

반응형