PESSIMISTI C ЗАПИСЬ Блокировка с уровнем изоляции СЕРИАЛИЗИРУЕМЫЙ на postgresql - PullRequest
0 голосов
/ 23 апреля 2020

Я получаю некоторые ошибки в некоторых сценариях, когда использую Pessimisti c Блокировка записи с уровнем изоляции SERIALIZABLE.

Вот класс MappingEntity:

@Data
@Entity(name = "asset_type_mapping")
@Table(
    name = "asset_type_mapping",
    uniqueConstraints =
            @UniqueConstraint(
                name = "UQ_MappingEntity",
                columnNames = {
                    Constants.DATA_TYPE_VALUE,
                    Constants.DATA_TYPE_NAMESPACE_INDEX,
                    Constants.TENANT_ID,
                    Constants.ASSET_TYPE_NAME
                }
            )
)
public class MappingEntity {
    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    private String id;

    @Column(name = Constants.DATA_TYPE_VALUE)
    private long dataTypeValue;

    @Column(name = Constants.DATA_TYPE_NAMESPACE_INDEX)
    private int dataTypeNamespaceIndex;

    @Column(name = Constants.ASSET_TYPE_NAME)
    private String assetTypeName;

    @Column(name = Constants.TENANT_ID)
    private String tenantId;
}

Вот класс MappingRepository :

public interface MappingRepository extends JpaRepository<MappingEntity, String> {

    @Lock(LockModeType.PESSIMISTIC_WRITE)
    MappingEntity findMappingEntityWithLockByTenantIdAndAssetTypeName(
            String tenantId, String assetTypeName);
}

Вот блок кода службы, где я получаю ошибки.

@Transactional(isolation = Isolation.SERIALIZABLE)
    public void deleteAspectType(String tenantId, String aspectTypeId) {

MappingEntity mappingEntity = mappingRepository.findMappingEntityWithLockByTenantIdAndAssetTypeName(tenantId, assetTypeName);

mappingRepository.delete(mappingEntity);

}

Теперь позвольте мне объяснить мои шаги. В моей базе данных есть две строки в таблице MappingEntity, и я хочу удалить эти две строки одновременно. Для этого я отправляю два запроса одновременно. Два потока принимают этот запрос и вызывают метод deleteAspectType () одновременно. Эти два потока сначала запускают запрос выбора с блокировкой, а затем удаляют. Но один из потоков не удаляется, и выдается исключение:

ERROR: could not serialize access due to read/write dependencies among transactions
  Detail: Reason code: Canceled on identification as a pivot, during write.
  Hint: The transaction might succeed if retried.

Я в замешательстве. Потоки извлекают разные строки и блокируют их. Когда я изменяю уровень изоляции на Read Committed, я не беру это исключение и работает нормально. Или когда я добавляю в индекс эту таблицу с tenantId и assetTypeName, пока уровень изоляции все еще SERIALIZABLE, я тоже не беру это исключение.

Пожалуйста, кто-нибудь объяснит мне, почему я получаю это исключение, когда уровень изоляции SERIALIZABLE без индекса и почему этот код работает нормально, когда уровень изоляции Read Committed или уровень изоляции SERIALIZABLE с индексом?

1 Ответ

2 голосов
/ 23 апреля 2020

Такое поведение, вероятно, объясняется тем, что транзакции не читают одни и те же строки, если используется индекс или если используется последовательное сканирование таблицы. Do c говорит

Чтобы гарантировать истинную сериализуемость PostgreSQL использует блокировку предиката, что означает, что он сохраняет блокировки, которые позволяют ему определить, когда запись имела бы влияние на результат предыдущего чтения из параллельной транзакции, если он был запущен первым. В PostgreSQL эти блокировки не вызывают блокировку и, следовательно, не могут играть какую-либо роль в возникновении тупика. Они используются для идентификации и пометки зависимостей между параллельными сериализуемыми транзакциями, которые в определенных комбинациях могут привести к аномалиям сериализации.

И:

Последовательное сканирование всегда требует отношения блокировка предикатов Это может привести к увеличению частоты сбоев сериализации. Может быть полезно поощрять использование сканирования индекса путем уменьшения random_page_cost и / или увеличения cpu_tuple_cost. Обязательно сопоставьте любое уменьшение откатов транзакций и перезапусков с любым общим изменением времени выполнения запроса.

...