-
Notifications
You must be signed in to change notification settings - Fork 92
Lightweight Transaction
Achilles offers a complete support for the new distributed Lightweight Transaction (LWT) features of Cassandra 2.0 using the Options API
To insert an entity if it does not exist (using the IF NOT EXISTS clause in CQL), you can use OptionsBuilder.ifNotExists()
as shown below
manager.insert(new MyEntity(...), OptionsBuilder.ifNotExists());
To delete an entity if it already exists (using the IF EXISTS clause in CQL), you can use OptionsBuilder.ifExists()
as shown below
manager.deleteById(MyEntity.class, primaryKey, OptionsBuilder.ifExists());
For conditional LWT updates, you can inject as many LWTCondition as needed using the OptionsBuilder.ifEqualCondition()
API.
@Entity(table = "user")
public class UserEntity {
@PartitionKey
private Long id;
@Column
private String login;
@Column
private String name;
}
...
// For update
manager.update(user, OptionsBuilder
.ifEqualCondition("login","jdoe"),
.ifEqualCondition("id",10L));
// For delete
manager.deleteById(UserEntity.class, OptionsBuilder
.ifEqualCondition("login","jdoe"));
Please note that for now only equality comparison is allowed in Cassandra for LWT conditions. Should that change in the future, Achilles will be updated to support new types of comparison
To have tighter control on LWT updates or inserts, Achilles lets you inject a listener for LWT operations result. Again the OptionsBuilder.lwtResultListener()
API comes to the rescue.
LWTResultListener lwtListener = new LWTResultListener() {
public void onSuccess() {
// Do something on success
}
public void onError(LWTResult lwtResult) {
//Get type of LWT operation that fails
LWTResult.Operation operation = lwtResult.operation();
// Print out current values
TypedMap currentValues = lwtResult.currentValues();
for(Entry<String,Object> entry: currentValues.entrySet()) {
System.out.println(String.format("%s = %s",entry.getKey(), entry.getValue()));
}
}
};
manager.update(user, OptionsBuilder
.ifEqualCondition("login","jdoe"),
.lwtResultListener(lwtListener));
Let's take a concrete example. Suppose you have inserted in the user
table the following data:
INSERT INTO user(id,login,name) VALUES(10,'johndoe','John DOE');
Now you try to update with OptionsBuilder.lwtEqualCondition("login","jdoe")
UPDATE user SET name = 'Johnny DOE' WHERE id=10 IF login='jdoe';
[applied] | login
-----------+-------
False | johndoe
Had you registered a LWTResultListener, the returned TypedMap of LWTResult.currentValues()
would contain:
- key: "[applied]", value: false (boolean)
- key: "login", value: "johndoe" (String)
Remark: it is not possible to register more than one listener but it is very easy to create a listener composite to call a list of ordered listeners yourself:
public class LWTResultListenerComposite implements LWTResultListener {
private final List<LWTResultListener> listeners = new LinkedList<>();
public LWTResultListenerComposite(LWTResultListener...listeners) {
this.listeners = Arrays.asList(listeners);
}
public void onSuccess() {
for(LWTResultListener listener:listeners) {
listener.onSuccess();
}
}
public void onError(LWTResult lwtResult) {
for(LWTResultListener listener:listeners) {
listener.onError(lwtResult);
}
}
}
### LWT Serial Consistency
To use LOCAL_SERIAL consistency in a multi data-center infrastructure instead of the SERIAL consistency for LWT operations, you can call
lwtLocalSerial()
on the OptionsBuilder
manager.update(user, OptionsBuilder
.ifEqualCondition("login","jdoe")
.lwtLocalSerial());
-
Bootstraping Achilles at runtime
- Runtime Configuration Parameters
-
Manager
-
Consistency Level
-
Cassandra Options at runtime
-
Lightweight Transaction (LWT)
-
JSON Serialization
-
Interceptors
-
Bean Validation (JSR-303)