14 Tenant Isolation Using EclipseLink
14.3 Using Table-Per-Tenant Multi-Tenancy
Table-per-tenant multi-tenancy allows multiple tenants of an application to isolate their data in one or more tenant-specific tables. Multiple tenants’ tables can be in a shared schema, identified using a prefix or suffix naming pattern; or they can be in separate, tenant-specific schemas. Table-per-tenant entities can be mixed with other multi-tenant type entities within the same persistence unit.
The table-per-tenant multi-tenant type is used in conjunction with:
■ A tenant table discriminator that specifies the type of discriminator (schema or name with prefix or suffix)
■ A tenant ID to identify the user (configured per entity manager or at the entity manager factory, if isolating the table-per-tenant per persistence unit.)
A single application instance with a shared EntityManagerFactory for a persistence unit can be responsible for handling requests from multiple tenants.
Alternatively, separate EntityManagerFactory instances can be used for each tenant.
(This is required when using extensions per tenant.) In this case, tenant-specific schema and table names are defined in an eclipselink-orm.xml configuration file. A MetadataSource must be registered with a persistence unit. The MetadataSource is used to support additional persistence unit metadata provided from outside the application.
For information about MetadataSource, see Chapter 13, "Using an External MetaData Source." See also metadata-source in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
The table-per-tenant multi-tenant type enables individual tenant table(s) to be used at the entity level. A tenant context property must be provided on each entity manager after a transaction has started.
■ The table(s) (Table and SecondaryTable) for the entity are individual tenant tables based on the tenant context. Relationships within an entity that uses a join or a collection table are also assumed to exist within the table-per-tenant context.
■ Multi-tenant metadata can only be applied at the root level of the inheritance hierarchy when using a SINGLE_TABLE or JOINED inheritance strategy. Multi-tenant metadata can be specified in a TABLE_PER_CLASS inheritance hierarchy
14.3.1 Main Tasks for Using Table-Per-Tenant Multi-Tenancy
The following tasks provide instructions for using table-per-tenant multi-tenancy:
■ Task 1: Prerequisites
■ Task 2: Enable Table-Per-Tenant Multi-Tenancy
■ Task 3: Specify Tenant Table Discriminator
■ Task 4: Specify a Context Property at Runtime
14.3.1.1 Task 1: Prerequisites
To implement and use table-per-tenant multi-tenancy, you need:
■ EclipseLink 2.4 or later.
Download EclipseLink from
http://www.eclipse.org/eclipselink/downloads/.
Using Table-Per-Tenant Multi-Tenancy
Tenant Isolation Using EclipseLink 14-11
■ Any compliant Java Database Connectivity (JDBC) database, including Oracle Database, Oracle Database Express Edition (Oracle Database XE), or MySQL.
These instructions are based on Oracle Database XE 11g Release 2.
For the certification matrix, see
14.3.1.2 Task 2: Enable Table-Per-Tenant Multi-Tenancy
Table-per-tenant multi-tenancy can be enabled declaratively using the @Multitenant annotation; or in an Object Relational Mapping (ORM) XML file using the
<multitenant> element, or using annotations and XML together.
14.3.1.2.1 Using the @Multitenant and @TenantTableDiscriminator Annotations To use the
@Multitenant annotation, include the annotation with an @Entity or
@MappedSuperclass annotation and include the TABLE_PER_TENANT attribute.
For example:
@Entity
@Multitenant(TABLE_PER_TENANT ...)
public class Employee { }
The TABLE_PER_TENANT attribute states that clients have a dedicated table or tables (Table and SecondaryTable) associated with the entity.
14.3.1.2.2 Using the <multitenant> Element To use the <multitenant> element, include the element within an <entity> element. For example:
<entity class="model.Employee">
<multitenant type="TABLE_PER_TENANT">
...
</multitenant>
...
</entity>
14.3.1.3 Task 3: Specify Tenant Table Discriminator
The tenant table discriminator describes the type of table discriminator to use in a table-per-tenant multi-tenancy strategy. The tenant table discriminator is identified by a property. You can define your own identifier or use the default property:
org.eclipse.persistence.config.PersistenceUnitProperties.MULTITENANT_
PROPERTY_DEFAULT = "eclipselink.tenant-id"
The tenant table discriminator can be specified at the entity or mapped superclass level, and it must always be accompanied with a Multitenant(TABLE_PER_TENANT) specification. It is not sufficient to specify only a tenant table discriminator.
The tenant table discriminator is used together with an associated application context to indicate which table or tables an application tenant can access.
14.3.1.3.1 Using the @TenantTableDiscriminator Annotation Use the
@TenantTableDiscriminator annotation to specify which tables are associated with which tenants. The tenant table discriminator must include a type and a context property:
■ Use the type attribute to identify what type of discriminator to use:
Using Table-Per-Tenant Multi-Tenancy
– Use PREFIX to apply the tenant table discriminator as a prefix to all multi-tenant tables.
– Use SUFFIX to apply the tenant table discriminator as a suffix to all multi-tenant tables.
– Use SCHEMA to apply the tenant table discriminator as a schema to all
multi-tenant tables. This strategy requires appropriate database provisioning.
■ Use the contextProperty attributes to identify the user. The value of the context property is a tenant ID that identifies the user. This can be configured for an entity manager or, if you want to isolate the table-per-tenant per persistence unit, an entity manager factory.
For example:
@Entity
@Table(name=“EMP”)
@Multitenant(TABLE_PER_TENANT)
@TenantTableDiscriminator(type=SCHEMA, contextProperty="eclipselink-tenant.id") public class Employee {
...
}
14.3.1.3.2 Using the <tenant-table-discriminator> Element To use the
<tenant-table-discriminator> element, include the element within a <multitenant>
element and include the name and context-property attributes. For example:
<entity class="Employee">
<multitenant type="TABLE_PER_TENANT">
<tenant-table-discriminator type="SCHEMA"
context-property="eclipselink-tenant.id"/>
</multitenant>
<table name="EMP">
...
</entity>
14.3.1.4 Task 4: Specify a Context Property at Runtime
At runtime, specify the context property using a persistence unit definition passed to an entity manager factory or set on an individual entity manager. For example:
<persistence-unit name="multitenant">
...
<properties>
<property name="tenant.id" value="707"/>
...
</properties>
</persistence-unit>
To specify a context property at runtime programmatically:
HashMap properties = new HashMap();
properties.put(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, "707");
EntityManager em = Persistence.createEntityManagerFactory("multitenant-pu", properties).createEntityManager();
An entity manager property definition follows:
EntityManager em =
Persistence.createEntityManagerFactory("multitenant-pu").createEntityManager();
em.beginTransaction();
Using VPD Multi-Tenancy
Tenant Isolation Using EclipseLink 14-13 em.setProperty("other.tenant.id.property", "707");
em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, "707");
...
14.3.1.5 Task 5: Perform Operations and Queries
The tenant discriminator column is used at runtime through entity manager
operations and querying. The tenant discriminator column and value are supported through the following entity manager operations:
■ persist()
■ find()
■ refresh()
The tenant discriminator column and value are supported through the following queries:
■ Named queries
■ Update all
■ Delete all