JPA : Multitenancy

On occasion you need to share a data model with other user-groups or other applications and where the model is persisted to the same structure of datastore. There are three ways of handling this with DataNucleus.

  • Separate Database per Tenant - have a different database per user-group/application.
  • Separate Schema per Tenant - as the first option, except use different schemas.
  • Same Database/Schema but with a Discriminator in affected Table(s) - this is described below.

Multitenancy via Discriminator in Table

Applicable to RDBMS, HBase, MongoDB, Neo4j, Cassandra

If you specify the persistence property datanucleus.tenantId as an identifier for your user-group/application then DataNucleus will know that it needs to provide a tenancy discriminator to all primary tables of persisted classes. This discriminator is then used to separate the data of the different user-groups.

By default this will add a column TENANT_ID to each primary table, of String-based type. You can control this by specifying extension metadata for each persistable class

<class name="MyClass">
     <extension vendor-name="datanucleus" key="multitenancy-column-name" value="TENANT"/>
     <extension vendor-name="datanucleus" key="multitenancy-column-length" value="24"/>

In all subsequent use of DataNucleus, any "insert" to the primary "table"(s) will also include the TENANT column value. Additionally any query will apply a WHERE clause restricting to a particular value of TENANT column.

If you have enabled multi-tenancy as above but want to disable multitenancy on a class, just specify the following metadata

<class name="MyClass">
     <extension vendor-name="datanucleus" key="multitenancy-disable" value="true"/>

Note that the Tenant ID can be set in one of three ways.

  • Per EMF : just set the persistence property datanucleus.tenantId when you start up the EMF and all access for this EMF will use this Tenant ID
  • Per EM : set the persistence property datanucleus.tenantId when you start up the PMF as the default Tenant ID and set a property on any EntityManager that you want a different Tenant ID specifying for. Like this
    EntityManager em = emf.createEntityManager();
    ... // All operations will apply to default tenant specified in persistence property for EMF
    EntityManager em1 = emf.createEntityManager();
    em1.setProperty("datanucleus.tenantId", "John");
    ... // All operations will apply to tenant "John"
    EntityManager em2 = emf.createEntityManager();
    em2.setProperty("datanucleus.tenantId", "Chris");
    ... // All operations will apply to tenant "Chris"
  • Per datastore access : When creating the EMF set the persistence property datanucleus.tenantProvider and set it to an instance of
    public interface MultiTenancyProvider
        String getTenantId(ExecutionContext ec);
    Now the programmer can set a different Tenant ID for each datastore access, maybe based on some session variable for example?.