Transactions

GetAll, SetAll and ExecAll are the foundation of transactions in immudb. They allow the execution of a group of commands in a single step, with two important guarantees:

  • All the commands in a transaction are serialized and executed sequentially. No request issued by another client can ever interrupt the execution of a transaction. This guarantees that the commands are executed as a single isolated operation.
  • Either all of the commands are processed, or none are, so the transaction is also atomic.

GetAll

  1. itList, err := db.GetAll( [][]byte{
  2. []byte("key1"),
  3. []byte("key2"),
  4. []byte("key3"),
  5. })
  1. // Using getAll:
  2. List<String> keys = Arrays.asList("key1", "key2", "key3");
  3. List<KV> got = immuClient.getAll(keys);
  4. // Using execAll for setting multiple KVs at once:
  5. byte[] item1 = "execAll_key1".getBytes(StandardCharsets.UTF_8);
  6. byte[] item2 = "execAll_key2".getBytes(StandardCharsets.UTF_8);
  7. immuClient.execAll(
  8. Arrays.asList( // Providing just a kvList, which is a List< Pair<byte[], byte[]> >.
  9. Pair.of(item1, item1),
  10. Pair.of(item2, item2)
  11. ),
  12. null, // No refList provided.
  13. null // No zaddList provided.
  14. );
  15. // Using execAll for setting multiple references and doing zAdd(s):
  16. immuClient.execAll(
  17. null, // No kvList provided.
  18. Arrays.asList( // The refList.
  19. Pair.of("ref1".getBytes(StandardCharsets.UTF_8), item1),
  20. Pair.of("ref2".getBytes(StandardCharsets.UTF_8), item2)
  21. ),
  22. // The zaddList.
  23. Collections.singletonList(Triple.of("set1", 1.0, "execAll_key1"))
  24. );

This feature is not yet supported or not documented. Do you want to make a feature request or help out? Open an issue on Python sdk github projectTransactions - 图1 (opens new window)

  1. import ImmudbClient from 'immudb-node'
  2. import Parameters from 'immudb-node/types/parameters'
  3. const IMMUDB_HOST = '127.0.0.1'
  4. const IMMUDB_PORT = '3322'
  5. const IMMUDB_USER = 'immudb'
  6. const IMMUDB_PWD = 'immudb'
  7. const cl = new ImmudbClient({ host: IMMUDB_HOST, port: IMMUDB_PORT });
  8. (async () => {
  9. await cl.login({ user: IMMUDB_USER, password: IMMUDB_PWD })
  10. const getAllReq: Parameters.GetAll = {
  11. keysList: ['key1', 'key2', 'key3'],
  12. sincetx: 0
  13. }
  14. const getAllRes = await cl.getAll(getAllReq)
  15. console.log('success: getAll', getAllRes)
  16. })()

This feature is not yet supported or not documented. Do you want to make a feature request or help out? Open an issue on .Net sdk github projectTransactions - 图2 (opens new window)

If you’re using another development language, please read up on our immugwTransactions - 图3 (opens new window) option.

SetAll

A more versatile atomic multi set operation

SetBatch and GetBatch example

  1. kvList := &schema.KVList{KVs: []*schema.KeyValue{
  2. {Key: []byte("1,2,3"), Value: []byte("3,2,1")},
  3. {Key: []byte("4,5,6"), Value: []byte("6,5,4")},
  4. }}
  5. _, err = client.SetAll(ctx, kvList)
  1. List<KV> kvs = Arrays.asList(
  2. new KVPair("key1", "val1".getBytes(StandardCharsets.UTF_8)),
  3. new KVPair("key2", "val2".getBytes(StandardCharsets.UTF_8)),
  4. );
  5. KVList kvList = KVList.newBuilder().addAll(kvs).build();
  6. try {
  7. immuClient.setAll(kvList);
  8. } catch (CorruptedDataException e) {
  9. // ...
  10. }

This feature is not yet supported or not documented. Do you want to make a feature request or help out? Open an issue on Python sdk github projectTransactions - 图4 (opens new window)

  1. import ImmudbClient from 'immudb-node'
  2. import Parameters from 'immudb-node/types/parameters'
  3. const IMMUDB_HOST = '127.0.0.1'
  4. const IMMUDB_PORT = '3322'
  5. const IMMUDB_USER = 'immudb'
  6. const IMMUDB_PWD = 'immudb'
  7. const cl = new ImmudbClient({ host: IMMUDB_HOST, port: IMMUDB_PORT });
  8. (async () => {
  9. await cl.login({ user: IMMUDB_USER, password: IMMUDB_PWD })
  10. const setAllReq: Parameters.SetAll = {
  11. kvsList: [
  12. { key: '1,2,3', value: '3,2,1' },
  13. { key: '4,5,6', value: '6,5,4' },
  14. ]
  15. }
  16. const setAllRes = await cl.setAll(setAllReq)
  17. console.log('success: setAll', setAllRes)
  18. })()

This feature is not yet supported or not documented. Do you want to make a feature request or help out? Open an issue on .Net sdk github projectTransactions - 图5 (opens new window)

If you’re using another development language, please read up on our immugwTransactions - 图6 (opens new window) option.

ExecAll

ExecAll permits many insertions at once. The difference is that is possible to specify a list of a mix of key value set, reference and zAdd insertions. The argument of a ExecAll is an array of the following types:

  • Op_Kv: ordinary key value item
  • Op_ZAdd: ZAdd option element
  • Op_Ref: Reference option element

It’s possible to persist and reference items that are already persisted on disk. In that case is mandatory to provide the index of the referenced item. This has to be done for:

  • Op_ZAdd
  • Op_Ref If zAdd or reference is not yet persisted on disk it’s possible to add it as a regular key value and the reference is done onFly. In that case if BoundRef is true the reference is bounded to the current transaction values.
  1. aOps := &schema.ExecAllRequest{
  2. Operations: []*schema.Op{
  3. {
  4. Operation: &schema.Op_Kv{
  5. Kv: &schema.KeyValue{
  6. Key: []byte(`notPersistedKey`),
  7. Value: []byte(`notPersistedVal`),
  8. },
  9. },
  10. },
  11. {
  12. Operation: &schema.Op_ZAdd{
  13. ZAdd: &schema.ZAddRequest{
  14. Set: []byte(`mySet`),
  15. Score: 0.4,
  16. Key: []byte(`notPersistedKey`)},
  17. },
  18. },
  19. {
  20. Operation: &schema.Op_ZAdd{
  21. ZAdd: &schema.ZAddRequest{
  22. Set: []byte(`mySet`),
  23. Score: 0.6,
  24. Key: []byte(`persistedKey`),
  25. AtTx: idx.Id,
  26. BoundRef: true,
  27. },
  28. },
  29. },
  30. },
  31. }
  32. idx , err = client.ExecAll(ctx, aOps)
  33. if err != nil {
  34. log.Fatal(err)
  35. }
  36. zscanOpts1 := &schema.ZScanRequest{
  37. Set: []byte(`mySet`),
  38. SinceTx: math.MaxUint64,
  39. NoWait: true,
  40. }
  41. list, err := client.ZScan(ctx, zscanOpts1)
  42. if err != nil{
  43. log.Fatal(err)
  44. }
  45. s, _ := json.MarshalIndent(list, "", "\t")
  46. fmt.Print(string(s))
  1. byte[] item1 = "execAll_key1".getBytes(StandardCharsets.UTF_8);
  2. byte[] item2 = "execAll_key2".getBytes(StandardCharsets.UTF_8);
  3. // Using execAll just for setting multiple KVs:
  4. TxMetadata txMd = immuClient.execAll(
  5. Arrays.asList( // The kvList.
  6. Pair.of(item1, item1),
  7. Pair.of(item2, item2)
  8. ),
  9. null, // No refList provided.
  10. null // No zaddList provided.
  11. );
  12. immuClient.execAll(
  13. null, // No kvList provided.
  14. Arrays.asList( // The refList.
  15. Pair.of("ref1".getBytes(StandardCharsets.UTF_8), item1),
  16. Pair.of("ref2".getBytes(StandardCharsets.UTF_8), item2)
  17. ),
  18. // The zaddList (even if it has one single entry).
  19. Collections.singletonList(Triple.of("set1", 1.0, "execAll_key1"))
  20. );

This feature is not yet supported or not documented. Do you want to make a feature request or help out? Open an issue on Python sdk github projectTransactions - 图7 (opens new window)

  1. import ImmudbClient from 'immudb-node'
  2. import Parameters from 'immudb-node/types/parameters'
  3. const IMMUDB_HOST = '127.0.0.1'
  4. const IMMUDB_PORT = '3322'
  5. const IMMUDB_USER = 'immudb'
  6. const IMMUDB_PWD = 'immudb'
  7. const cl = new ImmudbClient({ host: IMMUDB_HOST, port: IMMUDB_PORT });
  8. (async () => {
  9. await cl.login({ user: IMMUDB_USER, password: IMMUDB_PWD })
  10. const { id } = await cl.set({ key: 'persistedKey', value: 'persistedVal' })
  11. const setOperation = { kv: { key: 'notPersistedKey', value: 'notPersistedVal' } }
  12. const zAddOperation = {
  13. zadd: {
  14. set: 'mySet',
  15. score: 0.6,
  16. key: 'notPersistedKey',
  17. attx: 0,
  18. boundref: true
  19. }
  20. }
  21. const zAddOperation1 = {
  22. zadd: {
  23. set: 'mySet',
  24. score: 0.6,
  25. key: 'persistedKey',
  26. attx: id,
  27. boundref: true
  28. }
  29. }
  30. const execAllReq: Parameters.ExecAll = {
  31. operationsList: [
  32. setOperation,
  33. zAddOperation,
  34. zAddOperation1,
  35. ]
  36. }
  37. const execAllRes = await cl.execAll(execAllReq)
  38. console.log('success: execAll', execAllRes)
  39. })()

This feature is not yet supported or not documented. Do you want to make a feature request or help out? Open an issue on .Net sdk github projectTransactions - 图8 (opens new window)

If you’re using another development language, please read up on our immugwTransactions - 图9 (opens new window) option.

Tx Scan

TxScan permits iterating over transactions.

The argument of a TxScan is an array of the following types:

  • InitialTx: initial transaction id
  • Limit: number of transactions returned
  • Desc: order of returned transacations
  1. _, err = client.Set(ctx, []byte("key1"), []byte("val1"))
  2. if err != nil {
  3. log.Fatal(err)
  4. }
  5. _, err = client.Set(ctx, []byte("key2"), []byte("val2"))
  6. if err != nil {
  7. log.Fatal(err)
  8. }
  9. _, err = client.Set(ctx, []byte("key3"), []byte("val3"))
  10. if err != nil {
  11. log.Fatal(err)
  12. }
  13. txRequest := &schema.TxScanRequest{
  14. InitialTx: 2,
  15. Limit: 3,
  16. Desc: false,
  17. }
  18. txs , err := client.TxScan(ctx, txRequest)
  19. if err != nil {
  20. log.Fatal(err)
  21. }
  22. for _, tx := range txs.GetTxs() {
  23. fmt.Printf("retrieved in ASC tx %d \n", tx.Metadata.Id )
  24. }
  25. txRequest = &schema.TxScanRequest{
  26. InitialTx: 2,
  27. Limit: 3,
  28. Desc: true,
  29. }
  30. txs , err = client.TxScan(ctx, txRequest)
  31. if err != nil {
  32. log.Fatal(err)
  33. }

Then it’s possible to retrieve entries of every transactions:

  1. for _, tx := range txs.GetTxs() {
  2. for _, entry := range tx.Entries {
  3. item, err := client.GetAt(ctx, entry.Key[1:], tx.Metadata.Id)
  4. if err != nil {
  5. log.Fatal(err)
  6. }
  7. fmt.Printf("retrieved key %s and val %s\n", item.Key, item.Value)
  8. }
  9. }

Remember to strip the first byte in the key (key prefix). Remember that a transaction could contains sorted sets keys that should not be skipped.

  1. String key = "txtest-t2";
  2. byte[] val1 = "immuRocks!".getBytes(StandardCharsets.UTF_8);
  3. byte[] val2 = "immuRocks! Again!".getBytes(StandardCharsets.UTF_8);
  4. long initialTxId = 1;
  5. try {
  6. TxMetadata txMd = immuClient.set(key, val1);
  7. initialTxId = txMd.id;
  8. txMd = immuClient.set(key, val2);
  9. } catch (CorruptedDataException e) {
  10. Assert.fail("Failed at set.", e);
  11. }
  12. // This is a .txScan(initialTxId, limit, desc)
  13. List<Tx> txs = immuClient.txScan(initialTxId, 1, false);
  14. // We expect one Tx entry in this list.
  15. txs = immuClient.txScan(initialTxId, 2, false);
  16. // We expect two Tx entries in this list.

This feature is not yet supported or not documented. Do you want to make a feature request or help out? Open an issue on Python sdk github projectTransactions - 图10 (opens new window)

  1. import ImmudbClient from 'immudb-node'
  2. import Parameters from 'immudb-node/types/parameters'
  3. const IMMUDB_HOST = '127.0.0.1'
  4. const IMMUDB_PORT = '3322'
  5. const IMMUDB_USER = 'immudb'
  6. const IMMUDB_PWD = 'immudb'
  7. const cl = new ImmudbClient({ host: IMMUDB_HOST, port: IMMUDB_PORT });
  8. (async () => {
  9. await cl.login({ user: IMMUDB_USER, password: IMMUDB_PWD })
  10. for (let i = 0; i < 3; i++) {
  11. await cl.set({ key: `key${i}`, value: `val${i}` })
  12. }
  13. const txScanReq: Parameters.TxScan = {
  14. initialtx: 2,
  15. limit: 3,
  16. desc: false
  17. }
  18. const txScanRes = await cl.txScan(txScanReq)
  19. console.log('success: txScan', txScanRes)
  20. })()

This feature is not yet supported or not documented. Do you want to make a feature request or help out? Open an issue on .Net sdk github projectTransactions - 图11 (opens new window)

If you’re using another development language, please read up on our immugwTransactions - 图12 (opens new window) option.