【发布时间】:2020-10-24 21:58:43
【问题描述】:
用例:-
我们正在使用 Spring-data-aerospike 来获取和设置 aerospike 记录。 同时,我们有多个 Kafka 消费者正在尝试更新单个记录的不同字段。
问题:- 我们正面临着 Dirt-read 问题的挑战。记录正在被覆盖。
At t-0, Consumer-1 reads the Record-1, with intent to update the Field-name(mobileNumber).
Record-1 looks like something :(custId:1, mobileNumber:1234567890, custType:PERMANENT)
At t-1, Consumer-2 reads the Record-1, with intent to update the Field-2(custType).
At t-3, Consumer-2 commits the Record-1, with updated value for custType.
Record-1 looks like something :(custId:1, mobileNumber:1234567890, custType:PERM_CHANGED_2)
At t-4, Consumer-1 commits the Record-1, with updated value for mobileNumber.
Record-1 looks like something :(custId:1, mobileNumber:9988776655, custType:PERMANENNT)
这里的问题是:Consumer-2 更新的 'custType' 值在 t=4 时丢失了。
这里的代码-sn-p 看起来像:-
@Document(collection = "cust", expiration = 90, expirationUnit = TimeUnit.DAYS)
public class Customer {
@Id
@Field(value = "PK")
private String custId;
@Field(value = "mobileNumber")
private String mobileNumber;
@Field(value = "custType")
private String custType;
}
@Repository
public interface CustomerRepository extends AerospikeRepository<Customer, String> {
// Working.
List<Customer> findById(String primaryKeyId);
}
@Autowired
AerospikeTemplate aerospikeTemplate;
@Transactional(isolation = Isloation.SERIALIZABLE, rollbackFor=Exception.class)
public ResponseDTO<String> updateCustomer(CustomerUpdateRequest custUpdateReqDTO) {
Optional<Customer> cust = customerRepository.findById(custUpdateReqDTO.getCustId());
// Update Business logic by consumers.
aerospikeTemplate.update(cust);
}
这里的依赖看起来像:-
<dependency>
<groupId>com.aerospike</groupId>
<artifactId>aerospike-client</artifactId>
<version>4.1.3</version>
</dependency>
<dependency>
<groupId>com.aerospike</groupId>
<artifactId>spring-data-aerospike</artifactId>
<version>${aerospike.data.version}</version>
<scope>system</scope>
<systemPath>${basedir}/lib/spring-data-aerospike-2.0.0.RELEASE.jar</systemPath>
</dependency>
<dependency>
<groupId>com.aerospike</groupId>
<artifactId>aerospike-client</artifactId>
</dependency>
<dependency>
<groupId>com.aerospike</groupId>
<artifactId>aerospike-helper-java</artifactId>
<version>1.2.2</version>
</dependency>
问题:-
我们知道 Spring 事务与 RDBMS 一起工作!在这种情况下,让事务性属性在这里工作的方法是什么??
任何帮助或建议将不胜感激!
【问题讨论】:
-
您需要为此使用乐观锁定,请阅读
spring data/jpa optimistic locking。为此,您应该添加到您的文档类@Version private long version;。它会阻止并发更新,如果发生了,你会捕获OptimisticLockingFailureException并再次重试读取更新 -
感谢您的回复。 @Version 的使用是否也适用于 aerospike 等 NoSql 数据库??
-
是的,
@Version也适用于spring-data-aerospike -
如果是
spring-data-aerospike,则使用@Document而不是@Entity。@Version private long version;开箱即用。 -
仍然,如果没有乐观锁定,您将有竞争条件,不好的方法。奇怪的是,在您的情况下没有抛出异常,我之前使用过它并且效果很好。请做以下实验:手动设置版本= 5将文档保存在数据库中。然后尝试更新版本= 4的数据库中的相同记录。它不会抛出异常吗?
标签: spring-boot spring-data-jpa spring-transactions aerospike aerospike-ce