Attach a condition to a write or delete operation in Tablestore SDK for Java. Tablestore performs the operation only when the target row meets the condition; otherwise, it returns an error. Use conditional update to implement optimistic locking or to avoid overwriting concurrent changes that you have not read.
Prerequisites
Install Tablestore SDK for Java and initialize a client.
How it works
Conditional update lets you attach a condition to a write or delete operation. The Condition container holds a row existence condition (rowExistenceExpectation), a column condition (columnCondition), or both. Pass the configured Condition to setCondition() on RowPutChange, RowUpdateChange, or RowDeleteChange. If the condition is not met, the server returns an error and the row remains unchanged.
The classes include:
public class Condition {
private RowExistenceExpectation rowExistenceExpectation;
private ColumnCondition columnCondition;
}
public class SingleColumnValueCondition extends ColumnCondition
public class CompositeColumnValueCondition extends ColumnCondition
The following example updates the row with primary key row1 in the condition_demo table only when the row exists. Otherwise, the server returns an error.
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
.addPrimaryKeyColumn("id", PrimaryKeyValue.fromString("row1"))
.build();
RowUpdateChange rowUpdateChange = new RowUpdateChange("condition_demo", primaryKey);
rowUpdateChange.put("col1", ColumnValue.fromString("changed_val1"));
Condition condition = new Condition();
condition.setRowExistenceExpectation(RowExistenceExpectation.EXPECT_EXIST);
rowUpdateChange.setCondition(condition);
UpdateRowResponse response = client.updateRow(new UpdateRowRequest(rowUpdateChange));
System.out.println("RequestId: " + response.getRequestId());
System.out.println("Write CU: " + response.getConsumedCapacity().getCapacityUnit().getWriteCapacityUnit());
See Parameters for the full field reference of Condition, rowExistenceExpectation, and columnCondition.
Parameters
Condition
Condition is the condition container. It includes a row existence condition field and a column condition field. At least one field must be set.
|
Name |
Type |
Description |
|
rowExistenceExpectation (optional) |
RowExistenceExpectation |
The row existence condition. Valid values:
|
|
columnCondition (optional) |
ColumnCondition |
The column condition. The subclasses are |
SingleColumnValueCondition
Construct with new SingleColumnValueCondition(columnName, operator, columnValue).
|
Name |
Type |
Description |
|
columnName (required) |
String |
The name of the attribute column to check. |
|
operator (required) |
CompareOperator |
The comparison operator. Valid values:
|
|
columnValue (required) |
ColumnValue |
The value to compare against. |
|
passIfMissing (optional) |
boolean |
Whether to treat the row as meeting the condition when the target attribute column is missing. Default: Set to |
|
latestVersionsOnly (optional) |
boolean |
Whether to check only the latest data version. Default: Set to |
CompositeColumnValueCondition
Construct with new CompositeColumnValueCondition(logicOperator). Add subconditions with addCondition(). You can add up to 32 subconditions.
|
Name |
Type |
Description |
|
type (required) |
LogicOperator |
The logical operator. Valid values:
|
|
conditions (required) |
List<ColumnCondition> |
The subconditions for the logical operation. Add each subcondition with |
Examples
Single column value condition
Use SingleColumnValueCondition to check a single attribute column value. The following example updates col2 for the row with primary key row1 only when col1 == "changed_val1".
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
.addPrimaryKeyColumn("id", PrimaryKeyValue.fromString("row1"))
.build();
RowUpdateChange rowUpdateChange = new RowUpdateChange("condition_demo", primaryKey);
rowUpdateChange.put("col2", ColumnValue.fromString("new_val2"));
Condition condition = new Condition();
SingleColumnValueCondition singleCondition = new SingleColumnValueCondition(
"col1",
SingleColumnValueCondition.CompareOperator.EQUAL,
ColumnValue.fromString("changed_val1"));
condition.setColumnCondition(singleCondition);
rowUpdateChange.setCondition(condition);
client.updateRow(new UpdateRowRequest(rowUpdateChange));
Composite column value condition
Use CompositeColumnValueCondition to combine multiple conditions with logical operators. You can nest composite conditions inside one another. The following example builds the condition (col1 == "changed_val1" AND col2 == "new_val2") OR (col3 == "val3").
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
.addPrimaryKeyColumn("id", PrimaryKeyValue.fromString("row1"))
.build();
RowUpdateChange rowUpdateChange = new RowUpdateChange("condition_demo", primaryKey);
rowUpdateChange.put("col1", ColumnValue.fromString("final_val1"));
// Sub-condition: col1 == "changed_val1" AND col2 == "new_val2"
CompositeColumnValueCondition andCondition = new CompositeColumnValueCondition(
CompositeColumnValueCondition.LogicOperator.AND);
andCondition.addCondition(new SingleColumnValueCondition(
"col1",
SingleColumnValueCondition.CompareOperator.EQUAL,
ColumnValue.fromString("changed_val1")));
andCondition.addCondition(new SingleColumnValueCondition(
"col2",
SingleColumnValueCondition.CompareOperator.EQUAL,
ColumnValue.fromString("new_val2")));
// Top-level OR: (col1 AND col2) OR (col3)
CompositeColumnValueCondition orCondition = new CompositeColumnValueCondition(
CompositeColumnValueCondition.LogicOperator.OR);
orCondition.addCondition(andCondition);
orCondition.addCondition(new SingleColumnValueCondition(
"col3",
SingleColumnValueCondition.CompareOperator.EQUAL,
ColumnValue.fromString("val3")));
Condition condition = new Condition();
condition.setColumnCondition(orCondition);
rowUpdateChange.setCondition(condition);
client.updateRow(new UpdateRowRequest(rowUpdateChange));
Optimistic locking with compare-and-swap
Implement compare-and-swap with conditional update: first read the current value, then pass it as the update condition. The update succeeds only when the column still holds the value you read. If another process modifies the column between your read and write, the update fails. This prevents you from overwriting that process's write.
PrimaryKey primaryKey = PrimaryKeyBuilder.createPrimaryKeyBuilder()
.addPrimaryKeyColumn("id", PrimaryKeyValue.fromString("row1"))
.build();
// 1. Read the current value.
SingleRowQueryCriteria queryCriteria = new SingleRowQueryCriteria("condition_demo", primaryKey);
queryCriteria.setMaxVersions(1);
GetRowResponse getResponse = client.getRow(new GetRowRequest(queryCriteria));
String oldValue = getResponse.getRow().getLatestColumn("col1").getValue().asString();
// 2. Perform a conditional update based on the value just read (only update if col1 still equals oldValue).
RowUpdateChange rowUpdateChange = new RowUpdateChange("condition_demo", primaryKey);
rowUpdateChange.put("col1", ColumnValue.fromString("cas_updated"));
Condition condition = new Condition(RowExistenceExpectation.EXPECT_EXIST);
SingleColumnValueCondition casCondition = new SingleColumnValueCondition(
"col1",
SingleColumnValueCondition.CompareOperator.EQUAL,
ColumnValue.fromString(oldValue));
casCondition.setPassIfMissing(false);
casCondition.setLatestVersionsOnly(true);
condition.setColumnCondition(casCondition);
rowUpdateChange.setCondition(condition);
client.updateRow(new UpdateRowRequest(rowUpdateChange));