Data Storage

Last modified: September 19, 2024

Introduction

Data storage is the data foundation of the Mendix Runtime. Data storage does the following:

  • Connects to supported relational databases
  • Stores and retrieves entities and associations from the domain model
  • Translates XPath and OQL queries to SQL queries
  • Handles security transparently and effectively

Supported Databases

For apps deployed to Mendix Cloud, Mendix uses a PostgreSQL database for storing the data defined in the app domain model(s).

If you are deploying to a different infrastructure, you will need to provide your own database. See System Requirements for the list of supported databases.

Databases and Apps

Each app has its own database which is described in the domain models of the modules in the app.

This section explains why you cannot share a database between apps, and gives alternative methods to share data.

Database Table Names

Your app refers to entities using their names and modules. However, the database table holding the data for each entity is linked to the entity in the domain model by a unique identifier. For example, an Order entity in your app may be given an ID 807106d1-c0a8-4ef5-a387-2073cdee6d55. If you delete an entity and create a new entity with the same name, it will be give a different ID as the model will see it as a new entity.

The ID will remain attached to this entity within your app so that you can create multiple branches and deploy new versions of your app while using the same database. This allows you to change the entity in the domain model, renaming it for example, and the app will know that it is still the same entity.

However, if you export your module and import it to another app, the entities in the new app will be given new IDs. Since the ID is used to confirm the relationship between tables in the database and your domain model, you will get a completely different database table when you deploy your app, even though the domain model is the same. This also applies to restoring data to one app when it was backed up from a different app.

Consequence of Sharing a Database

Imagine you have an order handling app, Order Processing, which uses an MyModule.Order entity with the ID 807106d1-c0a8-4ef5-a387-2073cdee6d55.

You now create a second app, Order Viewer, which you want to use to view your orders. You export the domain model from Order Processing and import it into Order Viewer. However, the MyModule.Order entity in this new app will be given a different ID, for example 836a64f6-6e70-4f69-ba30-ed3876fd33b9.

You now try to deploy Order Viewer to use the same database as Order Processing. Because, the Order entity has a different ID, the Mendix Runtime will see the two tables as being different. The existing table mymodule$order will be deleted and a new mymodule$order table will be created linked to the new ID.

How to Share Data

If you want to share data between apps, you should set up a microservices architecture. In short, identify one app which you want to use to store the data. This app will now do all the creating, reading, updating, and deleting of the data. It will publish an API to allow other apps to access the data using, for example, OData or Data Hub. Other apps can then consume this API to use the data. This ensures that there is only one source for the data and that it is kept consistent.

An alternative is to copy the data to another app, for example using the Database Replication module. This however, will be a snapshot of your data at the time you replicate it and changes to the data made in the original app will not be reflected in your new app.

Database Transactions and Locking

Database Record Locks

Mendix does not use read locks on the database. Therefore, object reads can always be performed. A database write lock is put in place for the first object commit. If there are overlapping update transactions on the same object, the first update transaction puts a write lock on the database object. The next update transaction waits until the first one finishes before executing. However, if the first update process takes an inordinate amount of time, it may cause a timeout.

When users or microflows make changes to database records, all changes will execute in a transaction. Write locks are placed on individual records the moment they are committed. Until this point no locks will be placed on the data. For more information on the differences between transaction commits and object commits, see the How Commits Work section in Commit Object(s).

When the record gets locked, as long as the transaction is executing, no other users or processes are able to change the data. The uncommitted information is not visible for others. The changed data becomes available for other users to read only after the transaction completes. While the transaction is running, other users are able to read and change the previously persisted version of the data. Any changes from other processes will be applied when the transaction completes and the initial write lock is lifted, overwriting the previous changes.

Transaction Isolation

To ensure data validity and improve database performance in a multiuser environment, Mendix isolates concurrent database transactions. Isolation is done by using the Read Committed isolation level. This is the default isolation setting for PostgreSQL databases. Mendix relies on the implementation of Read Committed in the database. If you use a different database, the results of Read Committed might vary due to a different implementation of the isolation level.

For more information on how Read Committed works in PostgreSQL, see PostgreSQL Read Committed documentation.