I am getting some errors on some scenario when i am using Pessimistic Write lock with SERIALIZABLE isolation level.
Here is MappingEntity class:
@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;
}
Here is MappingRepository class:
public interface MappingRepository extends JpaRepository<MappingEntity, String> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
MappingEntity findMappingEntityWithLockByTenantIdAndAssetTypeName(
String tenantId, String assetTypeName);
}
Here is service code block where i am getting errors.
@Transactional(isolation = Isolation.SERIALIZABLE)
public void deleteAspectType(String tenantId, String aspectTypeId) {
MappingEntity mappingEntity = mappingRepository.findMappingEntityWithLockByTenantIdAndAssetTypeName(tenantId, assetTypeName);
mappingRepository.delete(mappingEntity);
}
Now let me explain my steps. In my database there is two rows in MappingEntity Table, and i want to delete these two rows at the same time. For that i send two request at same time. Two threads take this request and invoke deleteAspectType() method same time. These two threads first run select query with lock then delete. But one of threads fails to delete, and throw exception:
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.
I am confused. Threads retrieve different rows and lock them. When i change to isolation level to Read Committed, I dont take this exception and works fine. Or when i add to index this table with tenantId and assetTypeName while isolatation level still SERIALIZABLE, I dont take this exception too.
Please somebody explain me, Why am i getting this exception when isolation level SERIALIZABLE without index and why this code works fine when isolation level Read Committed or isolation level SERIALIZABLE with index?