{
  "id": "write-behind",
  "title": "Write-behind caching",
  "url": "https://redis.io/docs/latest/operate/oss_and_stack/stack-with-enterprise/gears-v1/python/recipes/write-behind/",
  "summary": "Write-behind and write-through caching between Redis and other databases (SQL or NoSQL).",
  "tags": [
    "docs",
    "operate",
    "stack"
  ],
  "last_updated": "2026-04-01T08:10:08-05:00",
  "page_type": "content",
  "content_hash": "17149cf2e1b96812045870402b0802c2ba27af0f605f7cf2ae4cb4fff0084471",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "Write-behind is a caching strategy in which the cache layer itself connects to the backing database. This means that your applications need only ever connect to your cache layer, and the cache then reads from or updates the backing database as needed. Redis currently supports write-behind caching in [Redis Software]().\n\nHere's how these caching patterns work:\n\n1. Your application uses the cache for reads and writes.\n1. The cache syncs any changed data to the backing database asynchronously.\n\n<!-- ### Read-through caching\n\n1. Your application reads from the cache. If there's a cache hit, the data is returned.\n1. If there's cache miss, the cache retrieves the data from your backing database (think Oracle, PostgreSQL, etc.). The data is then stored in the cache and returned. -->"
    },
    {
      "id": "install-the-write-behind-recipe",
      "title": "Install the write-behind recipe",
      "role": "setup",
      "text": "The write-behind recipe comes with two types of dependencies:\n\n- Drivers to connect to the backend database\n- Python libraries for the RedisGears functions\n\nIn most cases all of these can be provisioned to RedisGears before the functions are uploaded.\nHowever, root access for the driver on the host is required in some cases, for example with Oracle drivers."
    },
    {
      "id": "install-oracle-driver-optional",
      "title": "Install Oracle driver (optional)",
      "role": "setup",
      "text": "If you want to do write-behind with an Oracle database:\n\n1. [Download the Oracle driver](https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html).\n1. On each RS node in the cluster, follow the installation instructions on the download page for the Oracle driver."
    },
    {
      "id": "import-requirements",
      "title": "Import requirements",
      "role": "content",
      "text": "1. Install [Python 3](https://www.python.org/downloads/).\n1. To install the [gears-cli](https://pypi.org/project/gears-cli/), run: \n    [code example]\n\n1. Download [rgsync offline package](https://redislabs.com/download-center/modules/).\n1. Import the requirements:\n\n    [code example]\n\n    \nYou can be more efficient and import only the requirements you need, but rgsync is always required and can be combined with one or more of these packages according to your backend database:\n\n- redisgears-requirement-v1-snowflake-sqlalchemy-linux-\\<os>-x64.zip\n- redisgears-requirement-v1-PyMySQL-linux-\\<os>-x64.zip\n- redisgears-requirement-v1-cx-Oracle-linux-\\<os>-x64.zip\n- redisgears-requirement-v1-cassandra-driver-linux-\\<os>-x64.zip\n\nThis list can be different or more extensive in newer versions.\nThe `module.json` file in the module package lists the dependencies for the module.\n\n    \n\n1. From the CLI of a node or of a client that is connected to the database, check that the requirements were imported successfully with: \n\n    [code example]\n\n    To connect to the database from a client, run:\n\n    [code example]\n\n    This command returns a list of all available requirements."
    },
    {
      "id": "register-the-functions",
      "title": "Register the functions",
      "role": "content",
      "text": "The following is a RedisGears recipe that shows how to use the write-behind pattern to map data from Redis hashes to MySQL tables.\n\nThe recipe maps all Redis hashes with the prefix <nobr>`person:<id>`</nobr> to the MySQL table `persons`, with `<id>` being the primary key and mapped to the `person_id` column.\nSimilarly, it maps all hashes with the prefix <nobr>`car:<id>`</nobr> to the `cars` table.\n\n[code example]\n\nGo to the [rgsync website](https://pypi.org/project/rgsync/) to get the replication options and the configuration options for the database and mapping.\n\n1. Create a Python file with the configuration mapping according to your specific needs.\n1. Run `gears-cli` with your custom file:\n\n    [code example]"
    },
    {
      "id": "write-behind-caching-with-redisgears",
      "title": "Write-behind caching with RedisGears",
      "role": "content",
      "text": "[RGSync](https://github.com/RedisGears/rgsync) is a RedisGears recipe that uses the write-behind pattern to synchronize Redis data structures to a backing data store (Oracle, MySQL, Cassandra, and Snowflake are currently supported).\n\nHere's how you can create a write-behind function using the `RGSync` recipe against MySQL. This function will synchronize a set of fields in a Redis hash to the columns in a MySQL row. The key name for the Redis hash must have the form `{name}:{id}`, where `id` is the primary key for the row we want to keep in sync with. So, for example, suppose our hashes look like this:\n\n[code example]\n\nThe data in this hash would correspond to a row with ID of 5. But we need to define the mapping from our hash field to our columns. In our function, we do this using a Python dictionary:\n\n[code example]\n\nThis is saying that the `last_name` field in our hash should be synchronized with the 'last' field in our row. So, now we're ready to write our RedisGears function.\n\nFirst, load the necessary libraries and connect to MySQL:\n\n[code example]\n\nNext, create a connector object, specifying the table name and the name of the column storing the primary key:\n\n[code example]\n\nAfter that, define your field-column mappings:\n\n[code example]\n\nFinally, use these initialized objects to create an `RGWRiteBehind` object:\n\n[code example]\n\nNotice here that you can version this function registration with the `version` argument, as newer versions with the same `name` will replace the old one.\n\nIf you've placed all of this code into a file (`example.py`), then you can load it into your Redis deployment using the [`gears-cli`](https://github.com/RedisGears/gears-cli) tool:\n\n[code example]"
    },
    {
      "id": "secret-management",
      "title": "Secret management",
      "role": "content",
      "text": "You may not want to store database credentials in your RedisGears functions. To avoid this, you can pass these credentials as module parameters and then reference them from your functions.\n\nThe code below shows how to reference these credentials when creating a backing database connection.\n\n[code example]\n\nNotice that for each credential, we define a Python function that returns the specified module parameter. We then provide each function reference when we instantiate `MySqlConnection`.\n\nThis code references three parameters: `MySqlUser`, `MySqlPassword`, and `MySqlDB`. In Redis Software, you can set these parameters using the `rladmin` tool. The command to set these parameters takes the following form:\n\n[code example]\n\nTo set the `MySqlPassword` parameter to \"Password123!\" on a database named \"user-api\", you would run the this `rladmin` command:\n\n[code example]\n\nOnce a connection is successfully established, RedisGears will not attempt to reconnect until a disconnect occurs.\nThis means that updates to the parameters that store the secrets will not take effect immediately,\nbut they will be used for all subsequent connection attempts."
    }
  ],
  "examples": [
    {
      "id": "import-requirements-ex0",
      "language": "sh",
      "code": "pip install gears-cli",
      "section_id": "import-requirements"
    },
    {
      "id": "import-requirements-ex1",
      "language": "sh",
      "code": "# gears-cli import-requirements \\\n        --host HOST [ --port PORT ] --password PASSWORD \\\n        --requirements-path rgsync-99.99.99.linux-bionic-x64.zip",
      "section_id": "import-requirements"
    },
    {
      "id": "import-requirements-ex2",
      "language": "sh",
      "code": "redis-cli RG.PYDUMPREQS",
      "section_id": "import-requirements"
    },
    {
      "id": "import-requirements-ex3",
      "language": "sh",
      "code": "redis-cli -h <FQDN_of_node> -p <host> [-a <password>]",
      "section_id": "import-requirements"
    },
    {
      "id": "register-the-functions-ex0",
      "language": "sh",
      "code": "from rgsync import RGWriteBehind\nfrom rgsync.Connectors import MySqlConnector, MySqlConnection\n\n'''\nCreate MySQL connection object\n'''\nconnection = MySqlConnection('demouser', 'Password123!', 'localhost:3306/test')\n\n'''\nCreate MySQL persons connector\npersons - MySQL table to put the data\nperson_id - primary key\n'''\npersonConnector = MySqlConnector(connection, 'persons', 'person_id')\n\npersonsMappings = {\n\t'first_name':'first',\n\t'last_name':'last',\n\t'age':'age'\n}\n\nRGWriteBehind(GB, keysPrefix='person', mappings=personsMappings, connector=personConnector, name='PersonsWriteBehind', version='99.99.99')\n\n'''\nCreate MySQL car connector\ncars - MySQL table to put the data\ncar_id - primary key\n'''\ncarConnector = MySqlConnector(connection, 'cars', 'car_id')\n\ncarsMappings = {\n\t'id':'id',\n\t'color':'color'\n}\n\nRGWriteBehind(GB, keysPrefix='cars', mappings=carsMappings, connector=carConnector, name='CarsWriteBehind', version='99.99.99')",
      "section_id": "register-the-functions"
    },
    {
      "id": "register-the-functions-ex1",
      "language": "sh",
      "code": "gears-cli run --host <host> --port <post> --password <password> <yourfile>.py",
      "section_id": "register-the-functions"
    },
    {
      "id": "write-behind-caching-with-redisgears-ex0",
      "language": "sh",
      "code": "redis.cloud:6379> HSET person:5 first_name Marek last_name Michalski age 27\n(integer) 2",
      "section_id": "write-behind-caching-with-redisgears"
    },
    {
      "id": "write-behind-caching-with-redisgears-ex1",
      "language": "py",
      "code": "personsMappings = {\n\t'first_name':'first',\n\t'last_name':'last',\n\t'age':'age'\n}",
      "section_id": "write-behind-caching-with-redisgears"
    },
    {
      "id": "write-behind-caching-with-redisgears-ex2",
      "language": "py",
      "code": "from rgsync import RGWriteBehind\nfrom rgsync.Connectors import MySqlConnector, MySqlConnection\n\nconnection = MySqlConnection('myapplication', 'Password123!', 'localhost:3306/test')",
      "section_id": "write-behind-caching-with-redisgears"
    },
    {
      "id": "write-behind-caching-with-redisgears-ex3",
      "language": "py",
      "code": "personConnector = MySqlConnector(mySqlConnection, 'persons', 'id')",
      "section_id": "write-behind-caching-with-redisgears"
    },
    {
      "id": "write-behind-caching-with-redisgears-ex4",
      "language": "py",
      "code": "personsMappings = {\n\t'first_name':'first',\n\t'last_name':'last',\n\t'age':'age'\n}",
      "section_id": "write-behind-caching-with-redisgears"
    },
    {
      "id": "write-behind-caching-with-redisgears-ex5",
      "language": "py",
      "code": "RGWriteBehind(GB,\n              name='PersonsWriteBehind',\n              version='1',\n              connector=personsConnector,\n              keysPrefix='person',\n              mappings=personsMappings)",
      "section_id": "write-behind-caching-with-redisgears"
    },
    {
      "id": "write-behind-caching-with-redisgears-ex6",
      "language": "sh",
      "code": "gears-cli --host <host>\n          --port <post>\n          --password <password>\n          example.py\n          REQUIREMENTS rgsync",
      "section_id": "write-behind-caching-with-redisgears"
    },
    {
      "id": "secret-management-ex0",
      "language": "py",
      "code": "def User():\n\treturn configGet('MySqlUser')\ndef Password():\n\treturn configGet('MySqlPassword')\ndef DB():\n\treturn configGet('MySqlDB')\n\nconnection = MySqlConnection(User, Password, DB)",
      "section_id": "secret-management"
    },
    {
      "id": "secret-management-ex1",
      "language": "sh",
      "code": "rladmin tune db [DB-NAME] module_name rg module_config_params \"[PARAM-NAME] [PARAM-VALUE]\"",
      "section_id": "secret-management"
    },
    {
      "id": "secret-management-ex2",
      "language": "sh",
      "code": "rladmin tune db user-api module_name rg module_config_params \"MySqlPassword Password123!\"",
      "section_id": "secret-management"
    }
  ]
}
