Couchbase Transactions
Couchbase 支持 ``。本部分记录了如何将它与 Spring Data Couchbase 配合使用。
Couchbase supports Distributed Transactions. This section documents how to use it with Spring Data Couchbase.
Requirements
-
Couchbase Server 6.6.1 or above.
-
Spring Data Couchbase 5.0.0-M5 or above.
-
NTP should be configured so nodes of the Couchbase cluster are in sync with time. The time being out of sync will not cause incorrect behavior, but can impact metadata cleanup.
-
The entity class must have an
@Version Long
property to hold the CAS value of the document.
Overview
Spring Data Couchbase 模板操作(插入、查找、替换和删除)以及使用这些调用的存储库方法可以参与 Couchbase 事务。它们可以通过使用 @Transactional 注释、CouchbaseTransactionalOperator 或在 Couchbase 事务的 lambda 中在事务中执行。
The Spring Data Couchbase template operations insert, find, replace and delete and repository methods that use those calls can participate in a Couchbase Transaction. They can be executed in a transaction by using the @Transactional annotation, the CouchbaseTransactionalOperator, or in the lambda of a Couchbase Transaction.
Getting Started & Configuration
Couchbase 事务通常利用带有 注释的方法。
操作符利用 CouchbaseTransactionManager 实现,它在 AbstractCouchbaseConfiguration 中提供为 bean。Couchbase 事务可以通过使用 CouchbaseTransactionOperator(它也在 AbtractCouchbaseConfiguration 中提供为 bean)而无需定义服务类。Couchbase 事务还可以使用 lambda `` 中的 Spring Data Couchbase 操作直接使用。
Couchbase Transactions are normally leveraged with a method annotated with @Transactional. The @Transactional operator is implemented with the CouchbaseTransactionManager which is supplied as a bean in the AbstractCouchbaseConfiguration. Couchbase Transactions can be used without defining a service class by using CouchbaseTransactionOperator which is also supplied as a bean in AbtractCouchbaseConfiguration. Couchbase Transactions can also be used directly using Spring Data Couchbase operations within a lambda Using Transactions
Transactions with @Transactional
@Transactional 将方法或类上的所有方法定义为事务。
@Transactional defines as transactional a method or all methods on a class.
当在类级别声明此注释时,它对声明类及其子类的所有方法作为默认值应用。
When this annotation is declared at the class level, it applies as a default to all methods of the declaring class and its subclasses.
[[-attribute-semantics]]=== 属性语义
[[-attribute-semantics]] === Attribute Semantics
在此版本中,Couchbase 事务将忽略回滚属性。事务隔离级别已读取提交;
In this release, the Couchbase Transactions ignores the rollback attributes. The transaction isolation level is read-committed;
@Configuration
@EnableCouchbaseRepositories("<parent-dir-of-repository-interfaces>")
@EnableReactiveCouchbaseRepositories("<parent-dir-of-repository-interfaces>")
@EnableTransactionManagement (1)
static class Config extends AbstractCouchbaseConfiguration {
// Usual Setup
@Override public String getConnectionString() { /* ... */ }
@Override public String getUserName() { /* ... */ }
@Override public String getPassword() { /* ... */ }
@Override public String getBucketName() { /* ... */ }
// Customization of transaction behavior is via the configureEnvironment() method
@Override protected void configureEnvironment(final Builder builder) {
builder.transactionsConfig(
TransactionsConfig.builder().timeout(Duration.ofSeconds(30)));
}
}
请注意,如果事务失败,则可以重新执行 @Transactional 方法的主体。方法主体中的全部内容必须是幂等的,这一点非常重要。
Note that the body of @Transactional methods can be re-executed if the transaction fails. It is imperative that everthing in the method body be idempotent.
import reactor.core.publisher.Mono;
import reactor.core.publisher.Flux;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
final CouchbaseOperations personOperations;
final ReactiveCouchbaseOperations reactivePersonOperations;
@Service (2)
public class PersonService {
final CouchbaseOperations operations;
final ReactiveCouchbaseOperations reactiveOperations;
public PersonService(CouchbaseOperations ops, ReactiveCouchbaseOperations reactiveOps) {
operations = ops;
reactiveOperations = reactiveOps;
}
// no annotation results in this method being executed not in a transaction
public Person save(Person p) {
return operations.save(p);
}
@Transactional
public Person changeFirstName(String id, String newFirstName) {
Person p = operations.findById(Person.class).one(id); (3)
return operations.replaceById(Person.class).one(p.withFirstName(newFirstName);
}
@Transactional
public Mono<Person> reactiveChangeFirstName(String id, String newFirstName) {
return personOperationsRx.findById(Person.class).one(person.id())
.flatMap(p -> personOperationsRx.replaceById(Person.class).one(p.withFirstName(newFirstName)));
}
}
@Autowired PersonService personService; (4)
Person walterWhite = new Person( "Walter", "White");
Person p = personService.save(walterWhite); // this is not a transactional method
...
Person renamedPerson = personService.changeFirstName(walterWhite.getId(), "Ricky"); (5)
@Transactional 方法注释的功能需要
Functioning of the @Transactional method annotation requires
-
the configuration class to be annotated with @EnableTransactionManagement;
-
the service object with the annotated methods must be annotated with @Service;
-
the body of the method is executed in a transaction.
-
the service object with the annotated methods must be obtained via @Autowired.
-
the call to the method must be made from a different class than service because calling an annotated method from the same class will not invoke the Method Interceptor that does the transaction processing.
Transactions with CouchbaseTransactionalOperator
CouchbaseTransactionalOperator 可用于构建事务,而不必创建使用 @Transactional 的服务类。CouchbaseTransactionalOperator 可用作 Bean,并可以用 @Autowired 实例化。如果明确创建一个,则必须使用 CouchbaseTransactionalOperator.create(manager) 创建(而不是 TransactionalOperator.create(manager))。
CouchbaseTransactionalOperator can be used to construct a transaction in-line without creating a service class that uses @Transactional. CouchbaseTransactionalOperator is available as a bean and can be instantiated with @Autowired. If creating one explicitly, it must be created with CouchbaseTransactionalOperator.create(manager) (NOT TransactionalOperator.create(manager)).
@Autowired TransactionalOperator txOperator;
@Autowired ReactiveCouchbaseTemplate reactiveCouchbaseTemplate;
Flux<Person> result = txOperator.execute((ctx) ->
reactiveCouchbaseTemplate.findById(Person.class).one(person.id())
.flatMap(p -> reactiveCouchbaseTemplate.replaceById(Person.class).one(p.withFirstName("Walt")))
);
Transactions Directly with the SDK
Spring Data Couchbase 可与 Couchbase Java SDK 无缝配合进行事务处理。可在事务中执行的 Spring Data Couchbase 操作将直接在 transactions().run() 的 lambda 中运行,而无需涉及任何 SpringTransactions 机制。这是在 Spring Data Couchbase 中利用 Couchbase 事务的最直接方法。
Spring Data Couchbase works seamlessly with the Couchbase Java SDK for transaction processing. Spring Data Couchbase operations that can be executed in a transaction will work directly within the lambda of a transactions().run() without involving any of the Spring Transactions mechanisms. This is the most straight-forward way to leverage Couchbase Transactions in Spring Data Couchbase.
请参阅 ``。
Please see the Reference Documentation
@Autowired CouchbaseTemplate couchbaseTemplate;
TransactionResult result = couchbaseTemplate.getCouchbaseClientFactory().getCluster().transactions().run(ctx -> {
Person p = couchbaseTemplate.findById(Person.class).one(personId);
couchbaseTemplate.replaceById(Person.class).one(p.withFirstName("Walt"));
});
@Autowired ReactiveCouchbaseTemplate reactiveCouchbaseTemplate;
Mono<TransactionResult> result = reactiveCouchbaseTemplate.getCouchbaseClientFactory().getCluster().reactive().transactions()
.run(ctx ->
reactiveCouchbaseTemplate.findById(Person.class).one(personId)
.flatMap(p -> reactiveCouchbaseTemplate.replaceById(Person.class).one(p.withFirstName("Walt")))
);