programing

Postgres와 MariaDb 사이의 다른 동작을 최적으로 잠그는 최대 절전 모드

telecom 2023. 8. 28. 20:50
반응형

Postgres와 MariaDb 사이의 다른 동작을 최적으로 잠그는 최대 절전 모드

방금 Postgresql 또는 MariaDB 데이터베이스에서 낙관적인 잠금을 사용할 때 애플리케이션이 다르게 작동한다는 것을 발견했는데, 누가 무슨 일이 일어나고 어떻게 하면 MariaDB와 동일한 방식으로 애플리케이션이 작동할 수 있는지 설명할 수 있는지 궁금합니다.InnoDB 엔진 및 기본 설정과 함께 Postgresl 10.5 및 MariaDB 10.3.10을 사용합니다.Spring 프레임워크 버전 5.1.0과 Hibernate 5.3.6을 사용합니다.

그래서 제 코드는 다음과 같습니다.

@Entity
@Getter
@Setter
@NoArgsConstructor
public class Bla {

    @Id
    @GeneratedValue
    private long id;

    @Version
    private long version;

    private int counter;
}

또한 이 엔티티 및 다음 서비스 방법에 대한 리포지토리가 있습니다.

@Transactional
public int increment(long id) {
    Bla bla = blaRepo.getOne(id);
    bla.setCounter(bla.getCounter() + 1);
    return bla.getCounter();
}

여러 스레드에서 이 메서드를 호출하면 그 중 하나가 동일한 버전의 엔티티를 터치하는 경우에만 업데이트가 성공할 것으로 예상됩니다.예를 들어, 한 번의 실행에서 Postgresdb로 50개의 스레드를 시작하면 3개의 호출이 성공하고 값 1, 2, 3을 반환하며 나머지 47개는 ObjectOptimisticLockingFailure로 실패합니다.예상되는 동작인 예외 - 이것이 앱이 동작하는 방식입니다.

하지만 MariaDB로 전환하면 이런 일이 발생하지 않습니다.이 스레드 50개가 모두 성공적으로 완료되었으며 낙관적인 잠금이 없을 것처럼 여러 스레드에서 동일한 응답 값을 얻습니다.예를 들어, 처음 5개 스레드는 1을 반환하고, 그 중 20개 스레드는 2를 반환하고, 나머지 3개 또는 4를 반환합니다.

왜 이런 일이 일어날까요?두 데이터베이스 모두에서 생성된 쿼리는 다음과 같습니다.

update bla set counter=?, version=? where id=? and version=?

그러나 Postgresql에서는 올바르게 실패하고 MariaDB에서는 예기치 않게 성공합니다.

Tx가 레코드를 수정하면 커밋하거나 롤백할 때까지 잠그기 때문에 발생할 수 있는 유일한 방법은 MariaDB에 버그가 있는 것입니다.다른 Tx는 잠금으로 인해 UPDATE를 차단하지만 잠금이 해제된 후 조건을 재평가해야 합니다.

READ_로 전환해 봅니다.문제가 해결되는지 확인합니다.반복 가능_READ 이상일 수 있습니다.

저는 이 문제에 대한 해결책을 찾았습니다.

application.properties에서 이 속성을 설정한 것 같습니다.

spring.jpa.properties.hibernate.jdbc.batch_size = 50

Postgresql을 사용하면 두 개의 스레드가 있는 다음 디버그 추적이 표시됩니다.

13223 [pool-2-thread-2] DEBUG org.hibernate.SQL - update bla set counter=?, version=? where id=? and version=?
13223 [pool-2-thread-1] DEBUG org.hibernate.SQL - update bla set counter=?, version=? where id=? and version=? 
13226 [pool-1-thread-1] DEBUG org.hibernate.engine.jdbc.batch.internal.BatchingBatch - Executing batch size: 1
13226 [pool-1-thread-2] DEBUG org.hibernate.engine.jdbc.batch.internal.BatchingBatch - Executing batch size: 1
13230 [pool-1-thread-1] ERROR org.hibernate.engine.jdbc.batch.internal.BatchingBatch - HHH000315: Exception executing batch [org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1], SQL: update bla set counter=?, version=? where id=? and version=?

배치 크기가 동일한 MariaDB를 사용할 경우:

21978 [pool-2-thread-2] DEBUG org.hibernate.SQL - update bla set counter=?, version=? where id=? and version=?
21978 [pool-2-thread-1] DEBUG org.hibernate.SQL - update bla set counter=?, version=? where id=? and version=? 
21979 [pool-2-thread-2] DEBUG org.hibernate.engine.jdbc.batch.internal.BatchingBatch - Executing batch size: 1
21979 [pool-2-thread-1] DEBUG org.hibernate.engine.jdbc.batch.internal.BatchingBatch - Executing batch size: 1
21980 [pool-2-thread-2] DEBUG org.hibernate.jdbc.Expectations - Success of batch update unknown: 0
21980 [pool-2-thread-1] DEBUG org.hibernate.jdbc.Expectations - Success of batch update unknown: 0

배치 크기가 1인 MariaDB를 사용합니다.

12994 [pool-2-thread-2] DEBUG org.hibernate.SQL - update bla set counter=?, version=? where id=? and version=?
12994 [pool-2-thread-1] DEBUG org.hibernate.SQL - update bla set counter=?, version=? where id=? and version=?
12997 [pool-2-thread-1] DEBUG org.hibernate.cache.internal.TimestampsCacheEnabledImpl - Invalidating space [bla], timestamp: 6307671153053696
12998 [pool-2-thread-2] DEBUG org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl - JDBC transaction marked for rollback-only (exception provided for stack trace)

이제 애플리케이션은 예상되는 ObjectOptimisticLockingFailure를 슬로우합니다.예외.

그러나 안타깝게도 이것은 엔티티에 대한 낙관적인 잠금과 1보다 큰 배치 크기를 가진 MariaDb를 사용하는 것은 호환되지 않는다는 것을 의미합니다.

언급URL : https://stackoverflow.com/questions/52891978/hibernate-optimistic-locking-different-behavior-between-postgres-and-mariadb

반응형