hibernatemultitenancy-2011-02-16
TRANSCRIPT
![Page 1: HibernateMultitenancy-2011-02-16](https://reader035.vdocument.in/reader035/viewer/2022081821/54e96f5b4a795922038b4a1f/html5/thumbnails/1.jpg)
Multi-tenancy in Hibernate | Steve Ebersole
Multi-tenancy in HibernateSteve EbersoleHibernate Project Lead
![Page 2: HibernateMultitenancy-2011-02-16](https://reader035.vdocument.in/reader035/viewer/2022081821/54e96f5b4a795922038b4a1f/html5/thumbnails/2.jpg)
Multi-tenancy in Hibernate | Steve Ebersole
Agenda● What is multitenancy● Current options in Hibernate● Support in Hibernate 4● Q & A
![Page 3: HibernateMultitenancy-2011-02-16](https://reader035.vdocument.in/reader035/viewer/2022081821/54e96f5b4a795922038b4a1f/html5/thumbnails/3.jpg)
Multi-tenancy in Hibernate | Steve Ebersole
Separate SchemaApplication
CUSTOMER ( ID BIGINT, NAME VARCHAR, ...)
CUSTOMER ( ID BIGINT, NAME VARCHAR, ...)
![Page 4: HibernateMultitenancy-2011-02-16](https://reader035.vdocument.in/reader035/viewer/2022081821/54e96f5b4a795922038b4a1f/html5/thumbnails/4.jpg)
Multi-tenancy in Hibernate | Steve Ebersole
DiscriminatorApplication
CUSTOMER ( ID BIGINT, NAME VARCHAR, ... TENANT_ID VARCHAR)
![Page 5: HibernateMultitenancy-2011-02-16](https://reader035.vdocument.in/reader035/viewer/2022081821/54e96f5b4a795922038b4a1f/html5/thumbnails/5.jpg)
Multi-tenancy in Hibernate | Steve Ebersole
Current Options Discriminator● Hibernate filters● This approach can still leverage 2nd level cache● Application must be aware of tenant id
– Entity must expose tenantid attribute
– Application must set “tenant id” on creation
![Page 6: HibernateMultitenancy-2011-02-16](https://reader035.vdocument.in/reader035/viewer/2022081821/54e96f5b4a795922038b4a1f/html5/thumbnails/6.jpg)
Multi-tenancy in Hibernate | Steve Ebersole
Discriminator Entity@Entity@FilterDef( name=”tenantFilter”, parameters=@ParamDef( name="tenantId", type="string" ) )@Filters( @Filter( name=”tenantFilter”, condition=”tenant_id = :tenantId” ))public class Customer { @Id private Long id; @Column( name=”tenant_id”, nullable=false, updateable=false ) private String tenantId; ...}
@Entity@FilterDef( name=”tenantFilter”, parameters=@ParamDef( name="tenantId", type="string" ) )@Filters( @Filter( name=”tenantFilter”, condition=”tenant_id = :tenantId” ))public class Customer { @Id private Long id; @Column( name=”tenant_id”, nullable=false, updateable=false ) private String tenantId; ...}
![Page 7: HibernateMultitenancy-2011-02-16](https://reader035.vdocument.in/reader035/viewer/2022081821/54e96f5b4a795922038b4a1f/html5/thumbnails/7.jpg)
Multi-tenancy in Hibernate | Steve Ebersole
Discriminator Usagepublic void demonstrateUsageInDiscriminatorScenario() { // One thing that must be done on all sessions is to enable the tenantbased Hibernate filter // we defined before on the entity. This is usually best handled by some form of “request // interceptor” (HttpServletRequestFilter, etc) to make sure it is done uniformly
// Creating an entity Session session = openSession(); session.enableFilter( “tenantFilter” ).setParameter( “tenantId”, “sometenantidentifier” ); session.beginTransaction(); Customer customer = new Customer(); ... customer.setTenantId( “sometenantidentifier” ); session.persist( customer ); session.getTransaction().commit(); session.close();
// Querying Customers session = openSession(); session.enableFilter( “tenantFilter” ).setParameter( “tenantId”, “sometenantidentifier” ); session.beginTransaction(); Customer customer = (Customer) session.createQuery( “from Customer” ).uniqueResult(); session.getTransaction().commit(); session.close();}
public void demonstrateUsageInDiscriminatorScenario() { // One thing that must be done on all sessions is to enable the tenantbased Hibernate filter // we defined before on the entity. This is usually best handled by some form of “request // interceptor” (HttpServletRequestFilter, etc) to make sure it is done uniformly
// Creating an entity Session session = openSession(); session.enableFilter( “tenantFilter” ).setParameter( “tenantId”, “sometenantidentifier” ); session.beginTransaction(); Customer customer = new Customer(); ... customer.setTenantId( “sometenantidentifier” ); session.persist( customer ); session.getTransaction().commit(); session.close();
// Querying Customers session = openSession(); session.enableFilter( “tenantFilter” ).setParameter( “tenantId”, “sometenantidentifier” ); session.beginTransaction(); Customer customer = (Customer) session.createQuery( “from Customer” ).uniqueResult(); session.getTransaction().commit(); session.close();}
![Page 8: HibernateMultitenancy-2011-02-16](https://reader035.vdocument.in/reader035/viewer/2022081821/54e96f5b4a795922038b4a1f/html5/thumbnails/8.jpg)
Multi-tenancy in Hibernate | Steve Ebersole
Current Options – Separate Schema
● Custom ConnectionProvider to route calls to the correct JDBC connection
● Not safe with 2nd level cache● Application not aware of tenantid
![Page 9: HibernateMultitenancy-2011-02-16](https://reader035.vdocument.in/reader035/viewer/2022081821/54e96f5b4a795922038b4a1f/html5/thumbnails/9.jpg)
Multi-tenancy in Hibernate | Steve Ebersole
Separate Schema Entity@Entitypublic class Customer { @Id private Long id; ...}
@Entitypublic class Customer { @Id private Long id; ...}
![Page 10: HibernateMultitenancy-2011-02-16](https://reader035.vdocument.in/reader035/viewer/2022081821/54e96f5b4a795922038b4a1f/html5/thumbnails/10.jpg)
Multi-tenancy in Hibernate | Steve Ebersole
Separate Schema ConnectionProviderpublic class MyTenantAwareConnectionProvider implements ConnectionProvider { public static final String BASE_JNDI_NAME = "java:/comp/env/jdbc/";
public Connection getConnection() throws SQLException { final String tenantId = TenantContext.getTenantId() final String tenantDataSourceName = BASE_JNDI_NAME + tenantId; DataSource tenantDataSource = JndiHelper.lookupDataSource( tenantDataSourceName ); return tenantDataSource.getConnection(); }
public void closeConnection(Connection conn) throws SQLException { conn.close(); }
public boolean supportsAggressiveRelease() { // so long as the tenant identifier remains available in TenantContext throughout, we can // reacquire later return true; }
public void configure(Properties props) { // currently nothing to do here }
public close() { // currently nothing to do here }}
public class MyTenantAwareConnectionProvider implements ConnectionProvider { public static final String BASE_JNDI_NAME = "java:/comp/env/jdbc/";
public Connection getConnection() throws SQLException { final String tenantId = TenantContext.getTenantId() final String tenantDataSourceName = BASE_JNDI_NAME + tenantId; DataSource tenantDataSource = JndiHelper.lookupDataSource( tenantDataSourceName ); return tenantDataSource.getConnection(); }
public void closeConnection(Connection conn) throws SQLException { conn.close(); }
public boolean supportsAggressiveRelease() { // so long as the tenant identifier remains available in TenantContext throughout, we can // reacquire later return true; }
public void configure(Properties props) { // currently nothing to do here }
public close() { // currently nothing to do here }}
![Page 11: HibernateMultitenancy-2011-02-16](https://reader035.vdocument.in/reader035/viewer/2022081821/54e96f5b4a795922038b4a1f/html5/thumbnails/11.jpg)
Multi-tenancy in Hibernate | Steve Ebersole
Separate Schema Usagepublic void demonstrateUsageInSeparateSchemaScenario() { // The ConnectionProvider we saw earlier is registered with the SessionFactory as the means // for Hibernate to acquire Connections as needed for the Session. Here we must push the // tenantid to the TenantContext so it is available to the ConnectionProvider. This is usually // best handled by some form of “request interceptor” (HttpServletRequestFilter, etc) to make // sure it is done uniformly
TenantContext.setTenantId( “sometenantidentifier” );
// Creating an entity Session session = openSession(); session.beginTransaction(); Customer customer = new Customer(); ... session.persist( customer ); session.getTransaction().commit(); session.close();
// Querying Customers session = openSession(); session.beginTransaction(); Customer customer = (Customer) session.createQuery( “from Customer” ).uniqueResult(); session.getTransaction().commit(); session.close();}
public void demonstrateUsageInSeparateSchemaScenario() { // The ConnectionProvider we saw earlier is registered with the SessionFactory as the means // for Hibernate to acquire Connections as needed for the Session. Here we must push the // tenantid to the TenantContext so it is available to the ConnectionProvider. This is usually // best handled by some form of “request interceptor” (HttpServletRequestFilter, etc) to make // sure it is done uniformly
TenantContext.setTenantId( “sometenantidentifier” );
// Creating an entity Session session = openSession(); session.beginTransaction(); Customer customer = new Customer(); ... session.persist( customer ); session.getTransaction().commit(); session.close();
// Querying Customers session = openSession(); session.beginTransaction(); Customer customer = (Customer) session.createQuery( “from Customer” ).uniqueResult(); session.getTransaction().commit(); session.close();}
![Page 12: HibernateMultitenancy-2011-02-16](https://reader035.vdocument.in/reader035/viewer/2022081821/54e96f5b4a795922038b4a1f/html5/thumbnails/12.jpg)
Multi-tenancy in Hibernate | Steve Ebersole
Support in Hibernate 4● Exact API still under discussion[1]● Public API options:
– Session.setTenantId(String tenantId)
– Passed as part of opening a Session
● Transparently handled by Hibernate
[1] http://opensource.atlassian.com/projects/hibernate/browse/HHH5697