{
  "schema_version": 2,
  "id": "develop/clients/jedis/transpipe",
  "title": "Pipelines and transactions",
  "url": "https://redis.io/docs/latest/develop/clients/jedis/transpipe/",
  "summary": "Learn how to use Redis pipelines and transactions",
  "tags": [
    "docs",
    "develop",
    "stack",
    "oss",
    "rs",
    "rc",
    "oss",
    "kubernetes",
    "clients"
  ],
  "last_updated": "2026-09-08T15:41:24+01:00",
  "page_type": "content",
  "content_hash": "cc2ac59c7454375d97f1393e76eb67b6c1566c6c67bb1065e4f2d2ac5e5b8d16",
  "sections": [
    {
      "id": "execute-a-pipeline",
      "title": "Execute a pipeline",
      "role": "content",
      "text": "To execute commands in a pipeline, you first create a pipeline object\nand then add commands to it using methods that resemble the standard\ncommand methods (for example, `set()` and `get()`). The commands are\nbuffered in the pipeline and only execute when you call the `sync()`\nmethod on the pipeline object.\n\nThe main difference with the pipeline commands is that they return\n`Response<Type>` objects, where `Type` is the return type of the\nstandard command method. A `Response` object contains a valid result\nonly after the pipeline has finished executing. You can access the\nresult using the `Response` object's `get()` method.\n\nFoundational: Use pipelines to batch multiple commands together and reduce network round trips\n\n**Difficulty:** Beginner\n\n**Available in:** Java (Synchronous - Jedis)\n\n##### Java (Synchronous - Jedis)\n\n[code example]"
    },
    {
      "id": "execute-a-transaction",
      "title": "Execute a transaction",
      "role": "content",
      "text": "A transaction works in a similar way to a pipeline. Create a\ntransaction object with the `multi()` command, call command methods\non that object, and then call the transaction object's\n`exec()` method to execute it. You can access the results\nfrom commands in the transaction using `Response` objects, as\nyou would with a pipeline. However, the `exec()` method also\nreturns a `List<Object>` value that contains all the result\nvalues in the order the commands were executed (see\n[Watch keys for changes](#watch-keys-for-changes) below for\nan example that uses the results list).\n\nFoundational: Use transactions to execute multiple commands atomically without interruption from other clients\n\n**Difficulty:** Beginner\n\n**Available in:** Java (Synchronous - Jedis)\n\n##### Java (Synchronous - Jedis)\n\n[code example]"
    },
    {
      "id": "watch-keys-for-changes",
      "title": "Watch keys for changes",
      "role": "content",
      "text": "Redis supports *optimistic locking* to avoid inconsistent updates\nto different keys. The basic idea is to watch for changes to any\nkeys that you use in a transaction while you are processing the\nupdates. If the watched keys do change, you must restart the updates\nwith the latest data from the keys. See\n[Transactions](https://redis.io/docs/latest/develop/using-commands/transactions)\nfor more information about optimistic locking.\n\nThe code below reads a string\nthat represents a `PATH` variable for a command shell, then appends a new\ncommand path to the string before attempting to write it back. If the watched\nkey is modified by another client before writing, the transaction aborts.\nNote that you should call read-only commands for the watched keys synchronously on\nthe usual client object (called `jedis` in our examples) but you still call commands\nfor the transaction on the transaction object.\n\nFor production usage, you would generally call code like the following in\na loop to retry it until it succeeds or else report or log the failure.\n\nOptimistic locking: Use WATCH to monitor keys for changes and retry transactions when conflicts occur\n\n**Difficulty:** Intermediate\n\n**Available in:** Java (Synchronous - Jedis)\n\n##### Java (Synchronous - Jedis)\n\n[code example]"
    }
  ],
  "examples": [
    {
      "id": "execute-a-pipeline-ex0",
      "language": "java",
      "code": "// Make sure you close the pipeline after use to release resources\n        // and return the connection to the pool.\n        try (AbstractPipeline pipe = jedis.pipelined()) {\n\n            for (int i = 0; i < 5; i++) {\n                pipe.set(String.format(\"seat:%d\", i), String.format(\"#%d\", i));\n            }\n\n            pipe.sync();\n        }\n\n        try (AbstractPipeline pipe = jedis.pipelined()) {\n\n            Response<String> resp0 = pipe.get(\"seat:0\");\n            Response<String> resp3 = pipe.get(\"seat:3\");\n            Response<String> resp4 = pipe.get(\"seat:4\");\n\n            pipe.sync();\n\n            // Responses are available after the pipeline has executed.\n            System.out.println(resp0.get()); // >>> #0\n            System.out.println(resp3.get()); // >>> #3\n            System.out.println(resp4.get()); // >>> #4\n\n\n        }",
      "section_id": "execute-a-pipeline"
    },
    {
      "id": "execute-a-transaction-ex0",
      "language": "java",
      "code": "try ( AbstractTransaction trans = jedis.multi()) {\n\n           trans.incrBy(\"counter:1\", 1);\n           trans.incrBy(\"counter:2\", 2);\n           trans.incrBy(\"counter:3\", 3);\n\n           trans.exec();\n        }\n        System.out.println(jedis.get(\"counter:1\")); // >>> 1\n        System.out.println(jedis.get(\"counter:2\")); // >>> 2\n        System.out.println(jedis.get(\"counter:3\")); // >>> 3",
      "section_id": "execute-a-transaction"
    },
    {
      "id": "watch-keys-for-changes-ex0",
      "language": "java",
      "code": "// Set initial value of `shellpath`.\n        jedis.set(\"shellpath\", \"/usr/syscmds/\");\n\n        // Start the transaction and watch the key we are about to update.\n        try (AbstractTransaction trans = jedis.transaction(false)) { // create a Transaction object without sending MULTI command\n            trans.watch(\"shellpath\"); // send WATCH command(s)\n            trans.multi(); // send MULTI command\n\n            String currentPath = jedis.get(\"shellpath\");\n            String newPath = currentPath + \":/usr/mycmds/\";\n\n            // Commands added to the `trans` object\n            // will be buffered until `trans.exec()` is called.\n            Response<String> setResult = trans.set(\"shellpath\", newPath);\n            List<Object> transResults = trans.exec();\n\n            // The `exec()` call returns null if the transaction failed.\n            if (transResults != null) {\n                // Responses are available if the transaction succeeded.\n                System.out.println(setResult.get()); // >>> OK\n\n                // You can also get the results from the list returned by\n                // `trans.exec()`.\n                for (Object item: transResults) {\n                    System.out.println(item);\n                }\n                // >>> OK\n\n                System.out.println(jedis.get(\"shellpath\"));\n                // >>> /usr/syscmds/:/usr/mycmds/\n            }\n        }",
      "section_id": "watch-keys-for-changes"
    }
  ]
}
