문제

5개의 애플리케이션 서버에서 실행되는 분산 Java 애플리케이션이 있습니다.서버는 모두 6번째 시스템에서 실행되는 동일한 Oracle 9i 데이터베이스를 사용합니다.

애플리케이션은 시퀀스에서 100개의 ID 배치를 프리페치해야 합니다.단일 스레드, 비분산 환경에서는 비교적 쉽게 수행할 수 있습니다. 다음 쿼리를 실행하면 됩니다.

select seq.nextval from dual;
alter sequence seq increment by 100;
select seq.nextval from dual;

첫 번째 선택은 애플리케이션이 사용할 수 있는 첫 번째 시퀀스 ID를 가져오고, 두 번째 선택은 사용할 수 있는 마지막 시퀀스 ID를 반환합니다.

멀티스레드 환경에서는 상황이 훨씬 더 흥미로워집니다.두 번째 스레드를 선택하기 전에 다른 스레드를 선택해도 시퀀스가 ​​다시 100만큼 증가하지 않는다는 것을 확신할 수 없습니다.이 문제는 Java 측에서 액세스를 동기화하여 해결할 수 있습니다. 즉, 한 번에 하나의 스레드만 ID 가져오기를 시작하도록 할 수 있습니다.

애플리케이션의 일부가 동일한 JVM, 심지어 동일한 물리적 시스템에서도 실행되지 않기 때문에 동기화할 수 없으면 상황이 정말 어려워집니다.포럼에서 다른 사람들도 이 문제를 해결하는 데 문제가 있다는 참고 자료를 찾았지만 합리적인 답변은 말할 것도 없고 실제로 작동하는 답변도 없습니다.

커뮤니티에서 이 문제에 대한 해결책을 제공할 수 있나요?

추가 정보:

  • 나는 트랜잭션 격리 수준을 실제로 다룰 수 없습니다.나는 JPA를 사용하고 있으며 변경 사항은 프리페칭 쿼리뿐만 아니라 전체 애플리케이션에 영향을 미치므로 이는 허용되지 않습니다.
  • PostgreSQL에서는 다음을 수행할 수 있습니다.

    setval('seq', nextval('seq') + n - 1 ) 선택

  • Matthew의 솔루션은 고정된 증분 값을 사용할 수 있을 때 작동합니다(제 경우에는 완벽하게 허용됩니다).그러나 증분 크기를 고정하지 않고 동적으로 조정하려는 경우 솔루션이 있습니까?

도움이 되었습니까?

해결책

시퀀스를 항상 100씩 증가시키면 안 되는 이유는 무엇입니까?각 "nextval"은 작업할 수 있는 100개의 시퀀스 번호를 제공합니다.

SQL> create sequence so_test start with 100 increment by 100 nocache;

Sequence created.

SQL> select so_test.nextval - 99 as first_seq, so_test.currval as last_seq from dual;

 FIRST_SEQ   LAST_SEQ
---------- ----------
         1        100

SQL> /

 FIRST_SEQ   LAST_SEQ
---------- ----------
       101        200

SQL> /

 FIRST_SEQ   LAST_SEQ
---------- ----------
       201        300

SQL> 

귀하의 예에 대한 참고 사항 ..DDL을 조심하세요..암시적 커밋이 생성됩니다.

DDL로 생성된 커밋의 예

SQL> select * from xx;

no rows selected

SQL> insert into xx values ('x');

1 row created.

SQL> alter sequence so_test increment by 100;

Sequence altered.

SQL> rollback;

Rollback complete.

SQL> select * from xx;

Y
-----
x

SQL> 

다른 팁

처음에 시퀀스 ID를 가져와야 하는 이유는 무엇입니까?대부분의 경우 테이블에 삽입하고 ID를 반환합니다.

insert into t (my_pk, my_data) values (mysequence.nextval, :the_data)
returning my_pk into :the_pk;

처리를 사전 최적화하려는 것 같습니다.

정말로 ID를 미리 가져와야 하는 경우 시퀀스를 100번 호출하면 됩니다.시퀀스의 전체 요점은 번호 매기기를 관리한다는 것입니다.100개의 연속된 숫자를 얻을 수 있다고 가정해서는 안 됩니다.

Matthew는 여기서 올바른 접근 방식을 가지고 있습니다.내 생각에는 애플리케이션이 매 사용 후 시퀀스의 현재 값을 재설정하는 것은 매우 드문 일입니다.증분 크기를 필요한 만큼 미리 설정하는 것이 훨씬 더 일반적입니다.

또한 이 방법이 훨씬 더 성능이 좋습니다.시퀀스에서 nextval을 선택하는 것은 Oracle에서 고도로 최적화된 작업인 반면, 시퀀스를 변경하기 위해 ddl을 실행하는 것은 훨씬 더 비쌉니다.

편집 된 질문의 마지막 요점에 실제로 대답하지 않는 것 같습니다 ...

고정된 크기 증가를 원하지 않는 경우 시퀀스는 실제로 원하는 것이 아니며 실제로 보장하는 것은 마지막 숫자보다 항상 더 큰 고유 숫자를 얻게 된다는 것입니다.항상 간격이 생길 가능성이 있으며 실제로 안전하고 효과적으로 증분량을 즉석에서 조정할 수는 없습니다.

이런 종류의 작업을 수행해야 했던 경우는 실제로 생각해 볼 수 없지만 가장 쉬운 방법은 "현재" 번호를 어딘가에 저장하고 필요할 때 업데이트하는 것입니다.

이 같은.

drop table t_so_test;

create table t_so_test (curr_num number(10));

insert into t_so_test values (1);
create or replace procedure p_get_next_seq (inc IN NUMBER, v_next_seq OUT NUMBER) As
BEGIN
  update t_so_test set curr_num = curr_num + inc RETURNING curr_num into v_next_seq;
END;
/


SQL> var p number;
SQL> execute p_get_next_seq(100,:p);

PL/SQL procedure successfully completed.

SQL> print p;

         P
----------
       101

SQL> execute p_get_next_seq(10,:p);     

PL/SQL procedure successfully completed.

SQL> print p;

         P
----------
       111

SQL> execute p_get_next_seq(1000,:p);

PL/SQL procedure successfully completed.

SQL> print p;

         P
----------
      1111

SQL> 
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top