Last updated: June 22, 2021
This notebook explains the basics of executing multiple operations on one record as a transaction.
Aerospike was architected to process a high volume of concurrent real time reads and writes for Internet scale applications. Aerospike provides scale out performance by adding additional nodes or racks without changing application code.
Application code specifies the necessary process and data policy to execute one or billions of Aerospike read and write operations.
This notebook covers:
This notebook does not detail replication across a cluster.
This Jupyter Notebook requires the Aerospike Database running locally with Java kernel and Aerospike Java Client. To create a Docker container that satisfies the requirements and holds a copy of these notebooks, visit the Aerospike Notebooks Repo.
import io.github.spencerpark.ijava.IJava;
import io.github.spencerpark.jupyter.kernel.magic.common.Shell;
IJava.getKernelInstance().getMagics().registerMagics(Shell.class);
%sh asd
%%loadFromPOM
<dependencies>
<dependency>
<groupId>com.aerospike</groupId>
<artifactId>aerospike-client</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>
The default cluster location for the Docker container is localhost port 3000. If your cluster is not running on your local machine, modify localhost and 3000 to the values for your Aerospike cluster.
import com.aerospike.client.AerospikeClient;
AerospikeClient client = new AerospikeClient("localhost", 3000);
System.out.println("Initialized the client and connected to the cluster.");
Initialized the client and connected to the cluster.
Aerospike provides client APIs to read and write different types of data. Each record read or write operation that an Aerospike server or cluster executes as an atomic (ACID) operation.
For additional information on Aerospike's single-record variant of ACID compliance, go here.
For the case where an application uses Aerospike as a key/value store without applying Aerospike data types to data, the AerospikeClient provides the super fast, basic getters and setters for bins of data.
The most frequently used and simplest technique to execute more than one operation in an atomic fashion is the Operate API. Using this API, the Aerospike client can execute a single read or write operation or complex combinations of reads and writes
For more information on Operate, go here.
For more information on applying multiple operations to a record, go here.
Aerospike provides the following record operations:
Create a simple instance of every Aerospike data type.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
String txnString = "atomic";
Integer txnInteger = 8;
Double txnDouble = 6.022;
byte[] txnBlob = new byte[] {0b00000001, 0b00000010, 0b00000011, 0b00000100, 0b00000101};
String txnGeo = String.format("{ \"type\": \"Polygon\", \"coordinates\": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] }");
ArrayList<Integer> txnList = new ArrayList<Integer>();
txnList.add(1);
HashMap<Integer, Integer> txnMap = new HashMap <Integer, Integer>();
txnMap.put(2, 4);
System.out.println("String: " + txnString);
System.out.println("Integer: " + txnInteger);
System.out.println("Double: " + txnDouble);
System.out.println("Blob: " + Arrays.toString(txnBlob));
System.out.println("HLL: Starts with no data.");
System.out.println("Geo: " + txnGeo);
System.out.println("List: " + txnList);
System.out.println("Map: " + txnMap);
String: atomic Integer: 8 Double: 6.022 Blob: [1, 2, 3, 4, 5] HLL: Starts with no data. Geo: { "type": "Polygon", "coordinates": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] } List: [1] Map: {2=4}
import com.aerospike.client.Key;
import com.aerospike.client.Bin;
import com.aerospike.client.Value;
import com.aerospike.client.policy.ClientPolicy;
Integer theKey = 0;
String txnSet = "txnset";
String txnNamespace = "test";
String txnStringBin = "str";
String txnIntegerBin = "int";
String txnDoubleBin = "double";
String txnBlobBin = "blob";
String txnHLLBin = "hll";
String txnGeoBin = "geo";
String txnListBin = "list";
String txnMapBin = "map";
ClientPolicy clientPolicy = new ClientPolicy();
Key key = new Key(txnNamespace, txnSet, theKey);
Bin bin0 = new Bin(txnStringBin, txnString);
Bin bin1 = new Bin(txnIntegerBin, txnInteger);
Bin bin2 = new Bin(txnDoubleBin, txnDouble);
Bin bin3 = new Bin(txnBlobBin, txnBlob);
Bin bin4 = new Bin(txnHLLBin, Value.getAsNull());
Bin bin5 = new Bin(txnGeoBin, Value.getAsGeoJSON(txnGeo));
Bin bin6 = new Bin(txnListBin, txnList);
Bin bin7 = new Bin(txnMapBin, txnMap);
client.put(clientPolicy.writePolicyDefault, key, bin0, bin1, bin2, bin3, bin5, bin6, bin7);
System.out.println("Put data into Aerospike: "
+ txnStringBin + ", "
+ txnIntegerBin + ", "
+ txnDoubleBin + ", "
+ txnBlobBin + ", "
+ txnHLLBin + ", "
+ txnGeoBin + ", "
+ txnListBin + ", "
+ txnMapBin);
Put data into Aerospike: str, int, double, blob, hll, geo, list, map
import com.aerospike.client.Record;
Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.get(null, key);
System.out.println(record);
(gen:4),(exp:358043147),(bins:(str:atomic),(int:8),(double:6.022),(blob:[B@5c70658),(geo:{ "type": "Polygon", "coordinates": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] }),(list:[1]),(map:{2=4}),(hll:00080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000400000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000c0000000000))
Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.getHeader(null, key);
System.out.println(record);
(gen:4),(exp:358043147),(bins:null)
Key key = new Key(txnNamespace, txnSet, theKey);
client.touch(client.writePolicyDefault, key);
Record record = client.get(client.writePolicyDefault, key);
System.out.println(record);
(gen:5),(exp:358043147),(bins:(str:atomic),(int:8),(double:6.022),(blob:[B@3efad74b),(geo:{ "type": "Polygon", "coordinates": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] }),(list:[1]),(map:{2=4}),(hll:00080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000400000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000c0000000000))
When operating on simple data–Strings, Integers, and Doubles–, Aerospike provides standard create, read, update, and delete operations and also increment operations, like prepend/append and add.
For more information on record operations and simple data operations, go here.
Append to a string.
String txnAppendString = "-operation";
bin0 = new Bin(txnStringBin, txnAppendString);
Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.get(client.writePolicyDefault, key);
client.append(client.writePolicyDefault, key, bin0);
Record after = client.get(client.writePolicyDefault, key);
System.out.println("Before, the " + txnStringBin + " was - " + record.getValue(txnStringBin));
System.out.println(" After, the " + txnStringBin + " is - " + after.getValue(txnStringBin));
Before, the str was - atomic After, the str is - atomic-operation
Add to an integer.
Integer txnAddInt = 5;
Bin binIntAdd = new Bin(txnIntegerBin, txnAddInt);
Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.get(client.writePolicyDefault, key);
client.add(client.writePolicyDefault, key, binIntAdd);
Record after = client.get(client.writePolicyDefault, key);
System.out.println("Before, the " + txnIntegerBin + " was - " + record.getValue(txnIntegerBin));
System.out.println(" After, the " + txnIntegerBin + " is - " + after.getValue(txnIntegerBin));
Before, the int was - 8 After, the int is - 13
Subtract from a double.
Double txnAddDouble = -3.142;
Bin binDoubleAdd = new Bin(txnDoubleBin, txnAddDouble);
Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.get(client.writePolicyDefault, key);
client.add(client.writePolicyDefault, key, binDoubleAdd);
Record after = client.get(client.writePolicyDefault, key);
System.out.println("Before, the " + txnDoubleBin + " was - " + record.getValue(txnDoubleBin));
System.out.println(" After, the " + txnDoubleBin + " is - " + after.getValue(txnDoubleBin));
Before, the double was - 6.022 After, the double is - 2.8800000000000003
Aerospike also provides data-type-specific operations to work with complex data types:
import com.aerospike.client.cdt.ListOperation;
Integer listAddition = 5;
Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.get(client.writePolicyDefault, key);
client.operate(client.writePolicyDefault, key,
ListOperation.append(txnListBin, Value.get(listAddition))
);
Record after = client.get(client.writePolicyDefault, key);
System.out.println("Before, the " + txnListBin + " was - " + record.getValue(txnListBin));
System.out.println(" After, the " + txnListBin + " is - " + after.getValue(txnListBin));
Before, the list was - [1] After, the list is - [1, 5]
import com.aerospike.client.cdt.MapOperation;
import com.aerospike.client.cdt.MapPolicy;
Integer mapKey = 2;
Integer mapIncrementValue = 57;
MapPolicy txnMapPolicy = new MapPolicy();
Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.get(client.writePolicyDefault, key);
client.operate(client.writePolicyDefault, key,
MapOperation.increment(txnMapPolicy, txnMapBin, Value.get(mapKey), Value.get(mapIncrementValue))
);
Record after = client.get(client.writePolicyDefault, key);
System.out.println("Before, the " + txnMapBin + " was - " + record.getValue(txnMapBin));
System.out.println(" After, the " + txnMapBin + " is - " + after.getValue(txnMapBin));
Before, the map was - {2=4} After, the map is - {2=61}
import com.aerospike.client.operation.BitOperation;
import com.aerospike.client.operation.BitPolicy;
byte[] bitsToSet = new byte[] {(byte)0b11100000};
Integer bitSize = 8;
Integer bitOffset = 13;
BitPolicy bitPolicy = new BitPolicy();
Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.get(client.writePolicyDefault, key);
client.operate(client.writePolicyDefault, key,
BitOperation.set(bitPolicy.Default, txnBlobBin, bitOffset, bitSize, bitsToSet)
);
Record after = client.get(client.writePolicyDefault, key);
byte[] beforeBytes = (byte[])record.getValue(txnBlobBin);
byte[] afterBytes = (byte[])after.getValue(txnBlobBin);
System.out.println("Before, the " + txnBlobBin + " was - " + Arrays.toString(beforeBytes));
System.out.println(" After, the " + txnBlobBin + " is - " + Arrays.toString(afterBytes));
Before, the blob was - [1, 2, 3, 4, 5] After, the blob is - [1, 7, 3, 4, 5]
Init the HyperLogLog bin.
HyperLogLog is a probabilistic data type used for counting really large data sets. Aerospike provides operations to:
For more information on HyperLogLog Operations, go here.
import com.aerospike.client.operation.HLLOperation;
import com.aerospike.client.operation.HLLPolicy;
HLLPolicy defHLLPolicy = new HLLPolicy();
Integer bitsHLLIndex = 8;
Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.get(client.writePolicyDefault, key);
client.operate(client.writePolicyDefault, key,
HLLOperation.init(defHLLPolicy, txnHLLBin, bitsHLLIndex)
);
Record after = client.get(client.writePolicyDefault, key);
System.out.println("Before, the " + txnHLLBin + " was - " + record.getValue(txnHLLBin));
System.out.println(" After, the " + txnHLLBin + " is - " + after.getValue(txnHLLBin));
Before, the hll was - 00080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000400000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000c0000000000 After, the hll is - 0008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Get GeoJSON data.
For the purposes of simple transactions, Aerospike quickly stores and retrieves GeoJSON data in bins, and optionally nested in maps. In addition, Aerospike validates GeoJSON and processes Geospatial queries, including circle queries.
For more information on using Aerospike for geospatial indexes and queries, go here.
Key key = new Key(txnNamespace, txnSet, theKey);
Record pullGeo = client.get(client.writePolicyDefault, key, txnGeoBin);
System.out.println("The " + txnGeoBin + " is - " + pullGeo.getValue(txnGeoBin));
The geo is - { "type": "Polygon", "coordinates": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] }
The above operations were each performed as atomic operations. Operate executes multiple operations to one or more bins during a single record lock in an ACID-compliant fashion. Results are returned in an array for each bin.
Create data for each data type.
Put it into Aerospike.
Apply the following operations as one transaction.
// Create data for each data type.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
String txnString = "atomic";
Integer txnInteger = 8;
Double txnDouble = 6.022;
byte[] txnBlob = new byte[] {0b00000001, 0b00000010, 0b00000011, 0b00000100, 0b00000101};
String txnGeo = String.format("{ \"type\": \"Polygon\", \"coordinates\": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] }");
ArrayList<Integer> txnList = new ArrayList<Integer>();
txnList.add(1);
HashMap<Integer, Integer> txnMap = new HashMap <Integer, Integer>();
txnMap.put(2, 4);
System.out.println("--Initial Data–-");
System.out.println("String: " + txnString);
System.out.println("Integer: " + txnInteger);
System.out.println("Double: " + txnDouble);
System.out.println("Blob: " + Arrays.toString(txnBlob));
System.out.println("HLL: Starts with no data.");
System.out.println("Geo: " + txnGeo);
System.out.println("List: " + txnList);
System.out.println("Map: " + txnMap);
System.out.println();
// Put it into Aerospike.
import com.aerospike.client.AerospikeClient;
import com.aerospike.client.Key;
import com.aerospike.client.Bin;
import com.aerospike.client.Value;
import com.aerospike.client.policy.ClientPolicy;
import com.aerospike.client.Operation;
import com.aerospike.client.cdt.ListOperation;
import com.aerospike.client.cdt.MapOperation;
import com.aerospike.client.cdt.MapPolicy;
import com.aerospike.client.operation.BitOperation;
import com.aerospike.client.operation.BitPolicy;
import com.aerospike.client.operation.HLLOperation;
import com.aerospike.client.operation.HLLPolicy;
Integer theKey = 0;
String txnSet = "txnset";
String txnNamespace = "test";
String txnStringBin = "str";
String txnIntegerBin = "int";
String txnDoubleBin = "double";
String txnBlobBin = "blob";
String txnHLLBin = "hll";
String txnGeoBin = "geo";
String txnListBin = "list";
String txnMapBin = "map";
AerospikeClient client = new AerospikeClient("localhost", 3000);
ClientPolicy clientPolicy = new ClientPolicy();
BitPolicy bitPolicy = new BitPolicy();
HLLPolicy defHLLPolicy = new HLLPolicy();
MapPolicy txnMapPolicy = new MapPolicy();
Key key = new Key(txnNamespace, txnSet, theKey);
Bin bin0 = new Bin(txnStringBin, txnString);
Bin bin1 = new Bin(txnIntegerBin, txnInteger);
Bin bin2 = new Bin(txnDoubleBin, txnDouble);
Bin bin3 = new Bin(txnBlobBin, txnBlob);
Bin bin4 = new Bin(txnHLLBin, Value.getAsNull());
Bin bin5 = new Bin(txnGeoBin, Value.getAsGeoJSON(txnGeo));
Bin bin6 = new Bin(txnListBin, txnList);
Bin bin7 = new Bin(txnMapBin, txnMap);
client.put(clientPolicy.writePolicyDefault, key, bin0, bin1, bin2, bin3, bin5, bin6, bin7);
// Apply the following operations as one transaction.
// 1. Touch the record.
// 2. Append to the string.
// 3. Increment the integer.
// 4. Subtract from the double.
// 5. Put an item in the list.
// 6. Increment a value in the map.
// 7. Set bits in the blob.
// 8. Init and add set elements to the hyperloglog.
// 9. Get the GeoJSON.
String txnAppendString = "-transactions";
Bin binStrAppend = new Bin(txnStringBin, txnAppendString);
Integer txnAddInt = 5;
Bin binIntAdd = new Bin(txnIntegerBin, txnAddInt);
Double txnAddDouble = -3.142;
Bin binDoubleSub = new Bin(txnDoubleBin, txnAddDouble);
byte[] bitsToSet = new byte[] {(byte)0b11100000};
Integer bitSize = 8;
Integer bitOffset = 13;
Integer bitsHLLIndex = 8;
Integer listAddition = 5;
Integer mapKey = 2;
Integer mapIncrementValue = 57;
ArrayList<Value> dataListForHLL = new ArrayList<Value>();
dataListForHLL.add(Value.get(txnAddInt));
dataListForHLL.add(Value.get(bitSize));
dataListForHLL.add(Value.get(bitOffset));
dataListForHLL.add(Value.get(bitsHLLIndex));
dataListForHLL.add(Value.get(listAddition));
dataListForHLL.add(Value.get(mapKey));
dataListForHLL.add(Value.get(mapIncrementValue));
Record beforeOps = client.get(client.writePolicyDefault, key);
Record operationsRecord = client.operate(client.writePolicyDefault, key,
Operation.touch(),
Operation.append(binStrAppend),
Operation.add(binIntAdd),
Operation.add(binDoubleSub),
ListOperation.append(txnListBin, Value.get(listAddition)),
MapOperation.increment(txnMapPolicy, txnMapBin, Value.get(mapKey), Value.get(mapIncrementValue)),
BitOperation.set(bitPolicy.Default, txnBlobBin, bitOffset, bitSize, bitsToSet),
HLLOperation.init(defHLLPolicy, txnHLLBin, bitsHLLIndex),
HLLOperation.add(defHLLPolicy, txnHLLBin, dataListForHLL, bitsHLLIndex)
);
Record afterOps = client.get(client.writePolicyDefault, key);
System.out.println("--The Data in Aerospike–-");
System.out.println(beforeOps);
System.out.println();
System.out.println("--Operation Details–-");
System.out.println("Before, the " + txnStringBin + " was - " + beforeOps.getValue(txnStringBin));
System.out.println(" After, the " + txnStringBin + " is - " + afterOps.getValue(txnStringBin));
System.out.println();
System.out.println("Before, the " + txnIntegerBin + " was - " + beforeOps.getValue(txnIntegerBin));
System.out.println(" After, the " + txnIntegerBin + " is - " + afterOps.getValue(txnIntegerBin));
System.out.println();
System.out.println("Before, the " + txnDoubleBin + " was - " + beforeOps.getValue(txnDoubleBin));
System.out.println(" After, the " + txnDoubleBin + " is - " + afterOps.getValue(txnDoubleBin));
System.out.println();
System.out.println("Before, the " + txnListBin + " was - " + beforeOps.getValue(txnListBin));
System.out.println(" After, the " + txnListBin + " is - " + afterOps.getValue(txnListBin));
System.out.println();
System.out.println("Before, the " + txnMapBin + " was - " + beforeOps.getValue(txnMapBin));
System.out.println(" After, the " + txnMapBin + " is - " + afterOps.getValue(txnMapBin));
System.out.println();
byte[] beforeBytes = (byte[])beforeOps.getValue(txnBlobBin);
byte[] afterBytes = (byte[])afterOps.getValue(txnBlobBin);
System.out.println("Before, the " + txnBlobBin + " was - " + Arrays.toString(beforeBytes));
System.out.println(" After, the " + txnBlobBin + " is - " + Arrays.toString(afterBytes));
System.out.println();
System.out.println("Before, the " + txnHLLBin + " was - " + beforeOps.getValue(txnHLLBin));
System.out.println(" After, the " + txnHLLBin + " is - " + afterOps.getValue(txnHLLBin));
System.out.println();
System.out.println("The " + txnGeoBin + " is - " + afterOps.getValue(txnGeoBin));
System.out.println();
System.out.println("--The Record After the Operations–-");
System.out.println(afterOps);
--Initial Data–- String: atomic Integer: 8 Double: 6.022 Blob: [1, 2, 3, 4, 5] HLL: Starts with no data. Geo: { "type": "Polygon", "coordinates": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] } List: [1] Map: {2=4} --The Data in Aerospike–- (gen:13),(exp:358043150),(bins:(str:atomic),(int:8),(double:6.022),(blob:[B@42a7022c),(geo:{ "type": "Polygon", "coordinates": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] }),(list:[1]),(map:{2=4}),(hll:0008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)) --Operation Details–- Before, the str was - atomic After, the str is - atomic-transactions Before, the int was - 8 After, the int is - 13 Before, the double was - 6.022 After, the double is - 2.8800000000000003 Before, the list was - [1] After, the list is - [1, 5] Before, the map was - {2=4} After, the map is - {2=61} Before, the blob was - [1, 2, 3, 4, 5] After, the blob is - [1, 7, 3, 4, 5] Before, the hll was - 0008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 After, the hll is - 00080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000400000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000c0000000000 The geo is - { "type": "Polygon", "coordinates": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] } --The Record After the Operations–- (gen:14),(exp:358043150),(bins:(str:atomic-transactions),(int:13),(double:2.8800000000000003),(blob:[B@56bc27c5),(geo:{ "type": "Polygon", "coordinates": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] }),(list:[1, 5]),(map:{2=61}),(hll:00080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000400000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000c0000000000))
Simple transactions require arbitrary logic. The main technique to add conditional logic to these transactions is to apply a write policy.
Write operations use policy with the policy flags to indicate how to behave when data does or does not exist. For example, if executing a simple transaction containing multiple operations including one map operation that uses the conditional logic if (bin doesn't have a value), then put a default value into the bin
, apply that one operation using a write policy using the flags:
The default write policy if data exists in a bin is to merge data, whenever possible.
Each complex data type has its own write mode policy options.
Now, insert a new Mapkey:Value pair only if the mapkey doesn't already exist.
import com.aerospike.client.cdt.MapOrder;
import com.aerospike.client.cdt.MapWriteFlags;
Integer txnDefaultMapkey=2;
Integer txnDefaultValue=1;
MapPolicy txnMapPolicy = new MapPolicy(MapOrder.UNORDERED, MapWriteFlags.CREATE_ONLY | MapWriteFlags.NO_FAIL | MapWriteFlags.PARTIAL);
Key key = new Key(txnNamespace, txnSet, theKey);
Record mapFailRecord = client.operate(client.writePolicyDefault, key,
MapOperation.put(txnMapPolicy, txnMapBin, Value.get(txnDefaultMapkey), Value.get(txnDefaultValue))
);
Record afterOps = client.get(client.writePolicyDefault, key);
System.out.println("The " + txnMapBin + " is - " + afterOps.getValue(txnMapBin));
System.out.println();
The map is - {2=61}
If a process does requires conditional logic to check data values before writing, the common practice is to use a Read-Modify-Write pattern to check the data and write only if the generation counter is the same as when read.
For more information about Read-Modify-Write, go [here].(https://www.aerospike.com/blog/developers-understanding-aerospike-transactions/)
Truncate the set from the Aerospike Database.
import com.aerospike.client.policy.InfoPolicy;
InfoPolicy infoPolicy = new InfoPolicy();
client.truncate(infoPolicy, txnNamespace, txnSet, null);
System.out.println("Set Truncated.");
Set Truncated.
client.close();
System.out.println("Server connection closed.");
Server connection closed.
Simple transactions are a tool for efficient atomic execution of multiple operations on one record. The ability to process many real time, multi-operation simple transactions at scale is a strength of the Aerospike platform. A little forethought into application reads and writes before coding results in higher performance applications.
Have questions? Don't hesitate to reach out if you have additional questions about executing app transactions at https://discuss.aerospike.com/.
Want to check out other Java notebooks?
Are you running this from Binder? Download the Aerospike Notebook Repo and work with Aerospike Database and Jupyter locally using a Docker container.
Simple transactions are one of Aerospike's tools to work with data at scale. Other tools include Queries and UDFs, Batches, and Scans.