분할된 postgresql을 사용한 최대 절전 모드 삽입 배치
-
01-07-2019 - |
문제
분할된 postgresql 테이블에서 최대 절전 모드를 통해 일괄 삽입을 위한 솔루션이 있습니까?현재 이런 오류가 뜹니다..
ERROR org.hibernate.jdbc.AbstractBatcher - Exception executing batch:
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:61)
at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:46)
at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:68)....
내가 이 링크를 찾았어 http://lists.jboss.org/pipermail/hibernate-dev/2007-October/002771.html 그런데 웹 어디에서도 이 문제가 해결되었는지, 어떻게 해결할 수 있는지 찾을 수 없습니다.
해결책
hibernate.jdbc.factory_class 속성을 설정하여 사용자 정의 Batcher를 사용해 볼 수도 있습니다.최대 절전 모드가 일괄 작업의 업데이트 횟수를 확인하지 않도록 하면 문제가 해결될 수 있습니다. 사용자 정의 Batcher가 BatchingBatcher 클래스를 확장하도록 만든 다음 doExecuteBatch(...) 메서드를 다음과 같이 재정의하여 이를 달성할 수 있습니다.
@Override
protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException {
if ( batchSize == 0 ) {
log.debug( "no batched statements to execute" );
}
else {
if ( log.isDebugEnabled() ) {
log.debug( "Executing batch size: " + batchSize );
}
try {
// checkRowCounts( ps.executeBatch(), ps );
ps.executeBatch();
}
catch (RuntimeException re) {
log.error( "Exception executing batch: ", re );
throw re;
}
finally {
batchSize = 0;
}
}
}
새 메서드는 준비된 문 실행 결과를 확인하지 않습니다.이렇게 변경하면 예상치 못한 방식으로 최대 절전 모드에 영향을 줄 수도 있고 그렇지 않을 수도 있다는 점을 명심하세요.
다른 팁
분할된 테이블에서 두 개의 트리거를 사용하거나 여기에서 @SQLInsert 주석을 사용한다고 합니다. http://www.redhat.com/f/pdf/jbw/jmlogenski_940_scaling_hibernate.pdf 21-26페이지(String 메서드를 지정하는 @SQLInsert도 언급되어 있음)
다음은 마스터에서 추가 행을 삭제하기 위한 이후 트리거의 예입니다. https://gist.github.com/copiousfreetime/59067
삽입을 위해 트리거 대신 RULES를 사용할 수 있는 경우 표시되며 올바른 숫자를 반환할 수 있지만 WHERE 문 없이 단일 RULE만 사용할 수 있습니다.
또 다른 옵션은 분할된 테이블을 '래핑'하는 뷰를 생성한 다음 마스터 테이블에 원치 않는 추가 행을 실수로 추가하지 않고 새로운 행을 반환하여 성공적인 행 업데이트를 나타내는 것입니다.
create view tablename_view as select * from tablename; -- create trivial wrapping view
CREATE OR REPLACE FUNCTION partitioned_insert_trigger() -- partitioned insert trigger
RETURNS TRIGGER AS $$
BEGIN
IF (NEW.partition_key>= 5500000000 AND
NEW.partition_key < 6000000000) THEN
INSERT INTO tablename_55_59 VALUES (NEW.*);
ELSIF (NEW.partition_key >= 5000000000 AND
NEW.partition_key < 5500000000) THEN
INSERT INTO tablename_50_54 VALUES (NEW.*);
ELSIF (NEW.partition_key >= 500000000 AND
NEW.partition_key < 1000000000) THEN
INSERT INTO tablename_5_9 VALUES (NEW.*);
ELSIF (NEW.partition_key >= 0 AND
NEW.partition_key < 500000000) THEN
INSERT INTO tablename_0_4 VALUES (NEW.*);
ELSE
RAISE EXCEPTION 'partition key is out of range. Fix the trigger function';
END IF;
RETURN NEW; -- RETURN NEW in this case, typically you'd return NULL from this trigger, but for views we return NEW
END;
$$
LANGUAGE plpgsql;
CREATE TRIGGER insert_view_trigger
INSTEAD OF INSERT ON tablename_view
FOR EACH ROW EXECUTE PROCEDURE partitioned_insert_trigger(); -- create "INSTEAD OF" trigger
참조: http://www.postgresql.org/docs/9.2/static/trigger-definition.html
뷰 래퍼 경로 중 하나의 옵션은 삭제 및 업데이트를 위한 "대신" 트리거도 정의하는 것입니다. 그런 다음 모든 트랜잭션에서 일반 테이블 대신 뷰 테이블의 이름을 사용할 수 있습니다.
뷰를 사용하는 또 다른 옵션은 기본 테이블의 모든 삽입이 [트리거를 사용하는] 뷰로 이동하도록 삽입 규칙을 만드는 것입니다. partitioned_insert_trigger
위에 나열된 tablename_view 및 insert_view_trigger가 생성됨)
create RULE use_right_inserter_tablename AS
ON INSERT TO tablename
DO INSTEAD insert into tablename_view VALUES (NEW.*);
그런 다음 새 작업 뷰 래퍼 삽입을 사용합니다.
고맙습니다!그것은 트릭을 수행했으며 지금까지는 아무런 문제도 발생하지 않았습니다 :)....한 가지 당신은...나는 구현해야했다 BatcherFactory
수업을 듣고 그것을 persistence.xml
다음과 같은 파일 :
property name="hibernate.jdbc.factory_class" value="path.to.my.batcher.factory.implementation"
그 공장에서 위의 코드를 사용하여 Batcher 구현을 호출했습니다.
PS Hibernate Core 3.2.6 ga
다시 한번 감사합니다
많은 검색 후 최대 절전 모드를 통해 문서를 삽입하는 동안 업데이트된 행이 반환될 것으로 예상된다는 사실을 발견한 후 동일한 문제에 직면했습니다. 따라서 null 대신 트리거 프로시저에서 새 행으로 변경하면 아래와 같이 문제가 해결됩니다.
새로운 반품
같은 문제에 대한 다른 해결책을 찾았습니다 이 웹페이지에서:
이는 @rogerdpack이 말한 것과 동일한 솔루션을 제안합니다. Null 반환 에게 반품 NEW, 쿼리를 사용하여 마스터에서 중복된 튜플을 삭제하는 새 트리거를 추가합니다.
DELETE FROM ONLY master_table;