81

Hasta la vista Mandantenfähigkeit?

Embed Size (px)

Citation preview

Page 1: Hasta la vista Mandantenfähigkeit?
Page 2: Hasta la vista Mandantenfähigkeit?

Vorstellung Referent

I Prof. Informatik (Ostfalia, HS Braunschweig/Wolfenbuttel)

I Buchautor (JSF, JPA, Seam, . . . )

I Mitglied EGs JSR 344 (JSF 2.2) und JSR 338 (JPA 2.1)

I Geschaftsfuhrer PMST GmbH

I . . .

,Bernd Muller, 5.11.2013 2/62

Page 3: Hasta la vista Mandantenfähigkeit?

Auszug aus JSR 342: Java EE 7

Section 2: Request. . .As a result, Java EE 7 products will be able to more easily operateon private or public clouds and deliver their functionality as aservice with support for features such as multitenancy andelasticity (horizontal scaling). Applications written for Java EE 7will be better able to take advantage of the benefits of a cloudenvironment.. . .Similarly, a single application can be used by multiple tenants withthe same security, isolation, and quality of service guarantees.. . .

,Bernd Muller, 5.11.2013 3/62

Page 4: Hasta la vista Mandantenfähigkeit?

Auszug aus JSR 342: Java EE 7 (cont’d)

Section 2: Request. . .This JSR may also establish a set of constraints that applicationsthat wish to take advantage of PaaS-specific features, such asmultitenancy, may have to obey and provide a way for applicationsto identify themselves as designed for cloud environments.. . .In particular, all resource manager-related APIs, such as JPA,JDBC and JMS, will be updated to enable multitenancy.. . .

,Bernd Muller, 5.11.2013 4/62

Page 5: Hasta la vista Mandantenfähigkeit?

Auszug aus JSR 338: JPA 2.1

Section 2: Request

I . . .

I Support for multitenancy.

I . . .

,Bernd Muller, 5.11.2013 5/62

Page 6: Hasta la vista Mandantenfähigkeit?

Hasta la vista Mandantenfahigkeit?

,Bernd Muller, 5.11.2013 6/62

Page 7: Hasta la vista Mandantenfähigkeit?

Hasta la vista Mandantenfahigkeit?

Nein!

,Bernd Muller, 5.11.2013 6/62

Page 8: Hasta la vista Mandantenfähigkeit?

Was bedeutet Mandantenfahigkeit?

— Hier nur die Datensicht —

,Bernd Muller, 5.11.2013 7/62

Page 9: Hasta la vista Mandantenfähigkeit?

Motivation

I Cloud-motiviert: XaaS (Iaas, PaaS, SaaS)

I Kontinuum: Isolated Data vs Shared Data

I Technische, kommerzielle und juristische Aspekte

,Bernd Muller, 5.11.2013 8/62

Page 10: Hasta la vista Mandantenfähigkeit?

Motivation

I Cloud-motiviert: XaaS (Iaas, PaaS, SaaS)

I Kontinuum: Isolated Data vs Shared Data

I Technische, kommerzielle und juristische Aspekte

,Bernd Muller, 5.11.2013 8/62

Page 11: Hasta la vista Mandantenfähigkeit?

Motivation

I Cloud-motiviert: XaaS (Iaas, PaaS, SaaS)

I Kontinuum: Isolated Data vs Shared Data

I Technische, kommerzielle und juristische Aspekte

,Bernd Muller, 5.11.2013 8/62

Page 12: Hasta la vista Mandantenfähigkeit?

Die technische Sicht

I Daten eines Mandanten in . . .

Eigene DB EigenesSchema

GemeinsamesSchema

,Bernd Muller, 5.11.2013 9/62

Page 13: Hasta la vista Mandantenfähigkeit?

Getrennte Datenbanken

I Einfachster Ansatz, um Daten zu isolierenI Gemeinsamer Anwendungs-Code, aber jeder Mandant hat

eigene DBI Metadaten verbinden Anwendung mit DB des MandantenI Java EE: Deployment-Frage, CDI-Erweiterung, . . .

Mandant0815

Mandant4711

Mandant1234

,Bernd Muller, 5.11.2013 10/62

Page 14: Hasta la vista Mandantenfähigkeit?

Gemeinsame Datenbank, verschiedene Schemata

I Mehrere Mandanten in derselben DatenbankI Jeder Mandant eigene Menge von Tabellen in

Schema, getrennt vonanderen Schemata

Mandant0815

Mandant4711

Mandant1234

,Bernd Muller, 5.11.2013 11/62

Page 15: Hasta la vista Mandantenfähigkeit?

Gemeinsame Datenbank, gemeinsames Schema

I Selbe Datenbank und selbes Schema, um Daten fur alleMandanten zu halten

I Spalte mit Mandanten-ID (Diskriminator) bindet Datensatzan Mandant

Mandant Produkt Anzahl

0815

4711

1234.....

Mandant Kunde Adresse

0815

4711

1234.....

Mandant Lieferung Datum

0815

4711

1234

3826427

8327423

8832173

2013-07-04

2013-06-23

2013-01-01..... ..... .....

,Bernd Muller, 5.11.2013 12/62

Page 16: Hasta la vista Mandantenfähigkeit?

Mandantenfahigkeit mit Hibernate

,Bernd Muller, 5.11.2013 13/62

Page 17: Hasta la vista Mandantenfähigkeit?

Mandantenfahigkeit mit Hibernate – Die Alternativen

I Discriminator und Hibernate Filter

I Hibernate Shards

I Separate Schemata mit Multitenancy-APII Informationsquellen:

I http://relation.to/Bloggers/MultitenancyInHibernate

I https://community.jboss.org/wiki/Multi-tenancyDesign mitReferenz auf PDF, das im Folgenden verwendet wird

I Video http://vimeo.com/20296211I Hibernate Repository und Dokumentation

,Bernd Muller, 5.11.2013 14/62

Page 18: Hasta la vista Mandantenfähigkeit?

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 19: Hasta la vista Mandantenfähigkeit?

Multi-tenancy in Hibernate | Steve Ebersole

Discriminator ­ Usagepublic void demonstrateUsageInDiscriminatorScenario() {    // One thing that must be done on all sessions is to enable the tenant­based 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”, “some­tenant­identifier” );    session.beginTransaction();    Customer customer = new Customer();    ...    customer.setTenantId( “some­tenant­identifier” );    session.persist( customer );    session.getTransaction().commit();    session.close();

    // Querying Customers    session = openSession();    session.enableFilter( “tenantFilter” ).setParameter( “tenantId”, “some­tenant­identifier” );    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 tenant­based 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”, “some­tenant­identifier” );    session.beginTransaction();    Customer customer = new Customer();    ...    customer.setTenantId( “some­tenant­identifier” );    session.persist( customer );    session.getTransaction().commit();    session.close();

    // Querying Customers    session = openSession();    session.enableFilter( “tenantFilter” ).setParameter( “tenantId”, “some­tenant­identifier” );    session.beginTransaction();    Customer customer = (Customer) session.createQuery( “from Customer” ).uniqueResult();    session.getTransaction().commit();    session.close();}

Page 20: Hasta la vista Mandantenfähigkeit?

Beispiel: Entity Kunde mit Filterdefinition

@Entity

@FilterDef(name = "kundeMandantFilter",

parameters = @ParamDef(name = "mandant",

type = "string"))

@Filter(name = "kundeMandantFilter",

condition = "mandant = :mandant")

public class Kunde implements Serializable {

@Id @GeneratedValue

private Integer id;

...

private String mandant;

,Bernd Muller, 5.11.2013 17/62

Page 21: Hasta la vista Mandantenfähigkeit?

Verwendung des Filters

session.enableFilter("kundeMandantFilter")

.setParameter("mandant", MANDANT_1 );

Query query = session.createQuery(

"FROM " + Kunde.class.getSimpleName ());

Assert.assertEquals (2,

((List <Kunde >) query.list ()). size ());

session.enableFilter("kundeMandantFilter")

.setParameter("mandant", MANDANT_2 );

Assert.assertEquals (1,

((List <Kunde >) query.list ()). size ());

,Bernd Muller, 5.11.2013 18/62

Page 22: Hasta la vista Mandantenfähigkeit?

Fazit Diskriminator und Filter

I Scheint aufwendig (verglichen mit Alternativen)

I Definition aus Handbuch:”A filter criteria allows you to define

a restriction clause similar to the existing where attribute ...“

I Verwendung in Where-Clause, nicht bei Schreibvorgangen

I Ahnlich DB-Views

I Wird von JBoss nicht weiter als Mandantenfahigkeitpropagiert

I Evtl. Missbrauch der Filter-Idee?

,Bernd Muller, 5.11.2013 19/62

Page 23: Hasta la vista Mandantenfähigkeit?

Hibernate Shards

I Eigenes Hibernate-Unterprojekt Shards

I Erlaubt”Horizontal Partitioning“ d.h. Verteilung von

Datensatzen auf mehrere Datenbanken

I Siehe http://www.hibernate.org/subprojects/shards.html

I Scheinbar nicht mehr weiterentwickelt

I Kein GA-Release, Beta datiert von 2007

I Also: besser nicht verwenden

,Bernd Muller, 5.11.2013 20/62

Page 24: Hasta la vista Mandantenfähigkeit?

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 25: Hasta la vista Mandantenfähigkeit?

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     // tenant­id 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( “some­tenant­identifier” );

    // 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     // tenant­id 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( “some­tenant­identifier” );

    // 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 26: Hasta la vista Mandantenfähigkeit?

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/HHH­5697

Page 27: Hasta la vista Mandantenfähigkeit?

Manual (4.2): 16.3. Multi-tenancy in Hibernate

I Konfiguration mit Property hibernate.multiTenancy

I org.hibernate.MultiTenancyStrategy ist Enum mit

I NONE

(the default) No multi-tenancy is expected. . . .I SCHEMA

Correlates to the separate schema approach. . . . Additionally, a...MultiTenantConnectionProvider must be specified.

I DATABASE

Correlates to the separate database approach. . . . Additionally,a ...MultiTenantConnectionProvider must be specified.

I DISCRIMINATOR

Correlates to the partitioned (discriminator) approach. . . . Thisstrategy is not yet implemented in Hibernate as of 4.0 and 4.1.Its support is planned for 5.0.

,Bernd Muller, 5.11.2013 24/62

Page 28: Hasta la vista Mandantenfähigkeit?

Manual (4.2): 16.3. Multi-tenancy in Hibernate

I Konfiguration mit Property hibernate.multiTenancyI org.hibernate.MultiTenancyStrategy ist Enum mit

I NONE

(the default) No multi-tenancy is expected. . . .I SCHEMA

Correlates to the separate schema approach. . . . Additionally, a...MultiTenantConnectionProvider must be specified.

I DATABASE

Correlates to the separate database approach. . . . Additionally,a ...MultiTenantConnectionProvider must be specified.

I DISCRIMINATOR

Correlates to the partitioned (discriminator) approach. . . . Thisstrategy is not yet implemented in Hibernate as of 4.0 and 4.1.Its support is planned for 5.0.

,Bernd Muller, 5.11.2013 24/62

Page 29: Hasta la vista Mandantenfähigkeit?

Manual (4.2): 16.3. Multi-tenancy in Hibernate

I Konfiguration mit Property hibernate.multiTenancyI org.hibernate.MultiTenancyStrategy ist Enum mit

I NONE

(the default) No multi-tenancy is expected. . . .

I SCHEMA

Correlates to the separate schema approach. . . . Additionally, a...MultiTenantConnectionProvider must be specified.

I DATABASE

Correlates to the separate database approach. . . . Additionally,a ...MultiTenantConnectionProvider must be specified.

I DISCRIMINATOR

Correlates to the partitioned (discriminator) approach. . . . Thisstrategy is not yet implemented in Hibernate as of 4.0 and 4.1.Its support is planned for 5.0.

,Bernd Muller, 5.11.2013 24/62

Page 30: Hasta la vista Mandantenfähigkeit?

Manual (4.2): 16.3. Multi-tenancy in Hibernate

I Konfiguration mit Property hibernate.multiTenancyI org.hibernate.MultiTenancyStrategy ist Enum mit

I NONE

(the default) No multi-tenancy is expected. . . .I SCHEMA

Correlates to the separate schema approach. . . . Additionally, a...MultiTenantConnectionProvider must be specified.

I DATABASE

Correlates to the separate database approach. . . . Additionally,a ...MultiTenantConnectionProvider must be specified.

I DISCRIMINATOR

Correlates to the partitioned (discriminator) approach. . . . Thisstrategy is not yet implemented in Hibernate as of 4.0 and 4.1.Its support is planned for 5.0.

,Bernd Muller, 5.11.2013 24/62

Page 31: Hasta la vista Mandantenfähigkeit?

Manual (4.2): 16.3. Multi-tenancy in Hibernate

I Konfiguration mit Property hibernate.multiTenancyI org.hibernate.MultiTenancyStrategy ist Enum mit

I NONE

(the default) No multi-tenancy is expected. . . .I SCHEMA

Correlates to the separate schema approach. . . . Additionally, a...MultiTenantConnectionProvider must be specified.

I DATABASE

Correlates to the separate database approach. . . . Additionally,a ...MultiTenantConnectionProvider must be specified.

I DISCRIMINATOR

Correlates to the partitioned (discriminator) approach. . . . Thisstrategy is not yet implemented in Hibernate as of 4.0 and 4.1.Its support is planned for 5.0.

,Bernd Muller, 5.11.2013 24/62

Page 32: Hasta la vista Mandantenfähigkeit?

Manual (4.2): 16.3. Multi-tenancy in Hibernate

I Konfiguration mit Property hibernate.multiTenancyI org.hibernate.MultiTenancyStrategy ist Enum mit

I NONE

(the default) No multi-tenancy is expected. . . .I SCHEMA

Correlates to the separate schema approach. . . . Additionally, a...MultiTenantConnectionProvider must be specified.

I DATABASE

Correlates to the separate database approach. . . . Additionally,a ...MultiTenantConnectionProvider must be specified.

I DISCRIMINATOR

Correlates to the partitioned (discriminator) approach. . . . Thisstrategy is not yet implemented in Hibernate as of 4.0 and 4.1.Its support is planned for 5.0.

,Bernd Muller, 5.11.2013 24/62

Page 33: Hasta la vista Mandantenfähigkeit?

Stand heute (4.3.0.Beta3)

I Die (fur Hibernate 4) genannte MethodeSession.setTenantId() existiert nicht

I Die Unit-Tests fur Separate Schema verwenden 2Datenbanken nicht 2 Schemata

I Keine Realisierung fur Separate Schema moglich,evtl. Problem des Autors /

,Bernd Muller, 5.11.2013 25/62

Page 34: Hasta la vista Mandantenfähigkeit?

Mandantenfahigkeit mit OpenJPA

,Bernd Muller, 5.11.2013 26/62

Page 35: Hasta la vista Mandantenfähigkeit?

OpenJPAs Teilprojekt Slice

I Keine direkte Mandantenfahigkeit, sondern

I Verteilte Persistenz mit Slice

I Slice:”Slice is a module for distributed persistence in

OpenJPA. Slice enables an application developed for a singledatabase to adapt to a distributed, horizontally partitioned,possibly heterogeneous, database environment. This all occurswithout any change in the original application code or thedatabase schema. See how to leverage this flexibility for yourown applications, especially those destined for the cloud orSoftware as a Service.“

,Bernd Muller, 5.11.2013 27/62

Page 36: Hasta la vista Mandantenfähigkeit?

OpenJPAs Teilprojekt Slice

I Keine direkte Mandantenfahigkeit, sondern

I Verteilte Persistenz mit Slice

I Slice:”Slice is a module for distributed persistence in

OpenJPA. Slice enables an application developed for a singledatabase to adapt to a distributed, horizontally partitioned,possibly heterogeneous, database environment. This all occurswithout any change in the original application code or thedatabase schema. See how to leverage this flexibility for yourown applications, especially those destined for the cloud orSoftware as a Service.“

,Bernd Muller, 5.11.2013 27/62

Page 37: Hasta la vista Mandantenfähigkeit?

Slice’ Features

I Transparency

I Scaling

I Distributed Query

I Data Distribution

I Data Replication

I Heterogeneous Database

I Distributed Transaction

I Collocation Constraint

Damit kann man fast alles machen, auch Mandantenfahigkeit

,Bernd Muller, 5.11.2013 28/62

Page 38: Hasta la vista Mandantenfähigkeit?

Slice’ Features

I Transparency

I Scaling

I Distributed Query

I Data Distribution

I Data Replication

I Heterogeneous Database

I Distributed Transaction

I Collocation Constraint

Damit kann man fast alles machen, auch Mandantenfahigkeit

,Bernd Muller, 5.11.2013 28/62

Page 39: Hasta la vista Mandantenfähigkeit?

Wie funktioniert’s ?

I Anwendung(-slogik) bleibt unverandert (im Idealfall /einfachsten Fall)

I JPAs zugrundeliegende logische Datenbank wird durch Mengehorizontal partitionierter realer Datenbanken aufgeteilt

I Heterogene Datenbanken moglich

I Flexible Verteilung bzw. Redundanz der Daten durchCallback-Methoden sehr flexibel steuerbar (nur diese Klassenzusatzlich)

,Bernd Muller, 5.11.2013 29/62

Page 40: Hasta la vista Mandantenfähigkeit?

Wie funktioniert’s ?

I Anwendung(-slogik) bleibt unverandert (im Idealfall /einfachsten Fall)

I JPAs zugrundeliegende logische Datenbank wird durch Mengehorizontal partitionierter realer Datenbanken aufgeteilt

I Heterogene Datenbanken moglich

I Flexible Verteilung bzw. Redundanz der Daten durchCallback-Methoden sehr flexibel steuerbar (nur diese Klassenzusatzlich)

,Bernd Muller, 5.11.2013 29/62

Page 41: Hasta la vista Mandantenfähigkeit?

Wie funktioniert’s ?

I Anwendung(-slogik) bleibt unverandert (im Idealfall /einfachsten Fall)

I JPAs zugrundeliegende logische Datenbank wird durch Mengehorizontal partitionierter realer Datenbanken aufgeteilt

I Heterogene Datenbanken moglich

I Flexible Verteilung bzw. Redundanz der Daten durchCallback-Methoden sehr flexibel steuerbar (nur diese Klassenzusatzlich)

,Bernd Muller, 5.11.2013 29/62

Page 42: Hasta la vista Mandantenfähigkeit?

Wie funktioniert’s ?

I Anwendung(-slogik) bleibt unverandert (im Idealfall /einfachsten Fall)

I JPAs zugrundeliegende logische Datenbank wird durch Mengehorizontal partitionierter realer Datenbanken aufgeteilt

I Heterogene Datenbanken moglich

I Flexible Verteilung bzw. Redundanz der Daten durchCallback-Methoden sehr flexibel steuerbar (nur diese Klassenzusatzlich)

,Bernd Muller, 5.11.2013 29/62

Page 43: Hasta la vista Mandantenfähigkeit?

Konfiguration in persistence.xml

<property name="openjpa.BrokerFactory" value="slice" />

<property name="openjpa.slice.Names"

value="mandant1 ,mandant2 ,mandant3" />

<property name="openjpa.slice.Master" value="mandant1" />

<property name="openjpa.slice.Lenient" value="true" />

<property name="openjpa.ConnectionDriverName"

value="org.postgresql.Driver"/>

<property name="openjpa.slice.mandant1.ConnectionURL"

value="jdbc:postgresql: // localhost/bank1"/>

<property name="openjpa.slice.mandant2.ConnectionURL"

value="jdbc:postgresql: // localhost/bank2"/>

<property name="openjpa.slice.mandant3.ConnectionDriverName"

value="com.mysql.jdbc.Driver" />

<property name="openjpa.slice.mandant3.ConnectionURL"

value="jdbc:mysql: // localhost/bank3" />,

Bernd Muller, 5.11.2013 30/62

Page 44: Hasta la vista Mandantenfähigkeit?

Weitere Konfiguration

<property name="openjpa.slice.DistributionPolicy"

value="de.jpainfo.DistributionPolicyMandant"/>

<property name="openjpa.slice.QueryTargetPolicy"

value="de.jpainfo.QueryPolicyMandant"/>

<property name="openjpa.slice.FinderTargetPolicy"

value="de.jpainfo.FinderPolicyMandant"/>

,Bernd Muller, 5.11.2013 31/62

Page 45: Hasta la vista Mandantenfähigkeit?

Interface DistributionPolicy

,Bernd Muller, 5.11.2013 32/62

Page 46: Hasta la vista Mandantenfähigkeit?

Interface QueryTargetPolicy

,Bernd Muller, 5.11.2013 33/62

Page 47: Hasta la vista Mandantenfähigkeit?

Interface FinderTargetPolicy

,Bernd Muller, 5.11.2013 34/62

Page 48: Hasta la vista Mandantenfähigkeit?

Beispiel: Ein einfacher Kunde

@Entity

public class Kunde {

@Id @GeneratedValue

private Integer id;

private String vorname;

private String nachname;

@Temporal(TemporalType.DATE)

private Date geburtsdatum;

...

,Bernd Muller, 5.11.2013 35/62

Page 49: Hasta la vista Mandantenfähigkeit?

Beispiel: Verteilung nach Entity-Typ

public class DistributionPolicyMandant

implements DistributionPolicy {

public String distribute(Object entity ,

List <String > slices ,

Object context) {

if (entity instanceof Kunde) {

return "mandant1";

} else {

return "mandant2";

}

}

,Bernd Muller, 5.11.2013 36/62

Page 50: Hasta la vista Mandantenfähigkeit?

Beispiel: Verteilung nach Anwendungsdaten

public class DistributionPolicyMandant

implements DistributionPolicy {

public String distribute(Object entity ,

List <String > slices , Object context) {

if (entity instanceof Kunde) {

char anfangsbuchstabe =

((Kunde) entity ). getNachname (). toCharArray ()[0];

if (’A’ <= anfangsbuchstabe

&& anfangsbuchstabe < ’M’) {

return "mandant1";

} else if (’M’ <= anfangsbuchstabe

&& anfangsbuchstabe < ’T’) {

return "mandant2";

} else {

return "mandant3";

}

} else {

return "default";

}

}

Page 51: Hasta la vista Mandantenfähigkeit?

Beispiel: Verteilung mit zusatzlichem Mandanten-Property

public class DistributionPolicyMandant

implements DistributionPolicy {

public String distribute(Object entity ,

List <String > slices ,

Object context) {

if (entity instanceof Kunde) {

// ’mandant ’ Property der Entity -Klasse

return (( Kunde) entity ). getMandant ();

} else {

return "default";

}

}

,Bernd Muller, 5.11.2013 38/62

Page 52: Hasta la vista Mandantenfähigkeit?

Assoziationen

I @OneToOne, @OneToMany, @ManyToOne, @ManyToMany mitCascadierungsoption PERSIST automatisch im selben Slice,Distibution-Policy wird ignoriert

I Damit Queries effizient auf einer Datenbank

I Join uber mehrere Datenbanken wird nicht unterstutzt

,Bernd Muller, 5.11.2013 39/62

Page 53: Hasta la vista Mandantenfähigkeit?

Queries

public class QueryPolicyMandant implements

QueryTargetPolicy {

public String [] getTargets(String query ,

Map <Object , Object > params , String language ,

List <String > slices , Object context) {

return ...

}

}

I Abhangig von query und params entscheiden, welche Sliceszu verwenden sind

,Bernd Muller, 5.11.2013 40/62

Page 54: Hasta la vista Mandantenfähigkeit?

Queries (cont’d)

I Auch order by moglich

I In jeder DB auf SQL-Ebene sortiert

I Dann Merge-Sort in VM

I Aggregate (COUNT, MIN, MAX, SUM) moglich, AVG nicht

,Bernd Muller, 5.11.2013 41/62

Page 55: Hasta la vista Mandantenfähigkeit?

Queries (cont’d)

I Auch order by moglich

I In jeder DB auf SQL-Ebene sortiert

I Dann Merge-Sort in VM

I Aggregate (COUNT, MIN, MAX, SUM) moglich, AVG nicht

,Bernd Muller, 5.11.2013 41/62

Page 56: Hasta la vista Mandantenfähigkeit?

Queries (cont’d)

I Auch order by moglich

I In jeder DB auf SQL-Ebene sortiert

I Dann Merge-Sort in VM

I Aggregate (COUNT, MIN, MAX, SUM) moglich, AVG nicht

,Bernd Muller, 5.11.2013 41/62

Page 57: Hasta la vista Mandantenfähigkeit?

Queries (cont’d)

I Auch order by moglich

I In jeder DB auf SQL-Ebene sortiert

I Dann Merge-Sort in VM

I Aggregate (COUNT, MIN, MAX, SUM) moglich, AVG nicht

,Bernd Muller, 5.11.2013 41/62

Page 58: Hasta la vista Mandantenfähigkeit?

Replication-Policy

I Analog zu Distribution-Policy mit String[]

I Sinnvoll fur Aufzahlungstypen (z.B. Enums Wahrung,Nationalitat)

I Oder naturlich fur einfache Replikationsmechanismen

,Bernd Muller, 5.11.2013 42/62

Page 59: Hasta la vista Mandantenfähigkeit?

Fazit OpenJPA

I Allgemeine Moglichkeit Entity-Daten zu verteilen

I Kann fur Mandantenfahigkeit verwendet werden

I Keine Aussagen uber Performanz und Verwendbarkeit beistark verflochtenen Objektmodellen

I Reihe von Einschrankungen: AVG(), Join uber mehrereDatenbanken, . . .

I Ist ein Versuch wert

,Bernd Muller, 5.11.2013 43/62

Page 60: Hasta la vista Mandantenfähigkeit?

Mandantenfahigkeit mit EclipseLink

,Bernd Muller, 5.11.2013 44/62

Page 61: Hasta la vista Mandantenfähigkeit?

,Bernd Muller, 5.11.2013 45/62

Page 62: Hasta la vista Mandantenfähigkeit?
Page 63: Hasta la vista Mandantenfähigkeit?
Page 64: Hasta la vista Mandantenfähigkeit?

,Bernd Muller, 5.11.2013 48/62

Page 65: Hasta la vista Mandantenfähigkeit?

,Bernd Muller, 5.11.2013 49/62

Page 66: Hasta la vista Mandantenfähigkeit?

Beispiel: Ein Kunde kann mehrere Konten haben ...

@Entity

@Multitenant

public class Kunde {

@Id @GeneratedValue

private Integer id;

private String vorname;

private String nachname;

@Temporal(TemporalType.DATE)

private Date geburtsdatum;

@OneToMany(mappedBy = "kunde",

cascade = CascadeType.ALL)

private List <Konto > konten;

...

,Bernd Muller, 5.11.2013 50/62

Page 67: Hasta la vista Mandantenfähigkeit?

Das Konto

@Entity

@Multitenant

public class Konto {

@Id

@GeneratedValue(strategy = GenerationType.SEQUENCE ,

generator = "KontoSeq")

@SequenceGenerator(name = "KontoSeq",

sequenceName="KontoSeq", allocationSize = 5,

initialValue = 1000000)

private Integer kontonummer;

private BigDecimal kontostand;

@ManyToOne

@JoinColumn(name = "kunde")

private Kunde kunde;

...

,Bernd Muller, 5.11.2013 51/62

Page 68: Hasta la vista Mandantenfähigkeit?

Verwendung: persistence.xml oder programmatisch

<?xml version="1.0" encoding="UTF-8" ?>

<persistence ...>

...

<properties >

<property name="eclipselink.tenant-id"

value="007"/>

Map <String , String > props =

new HashMap <String , String >();

props.put("eclipselink.tenant -id", "Mandant -1");

EntityManagerFactory emf = Persistence

.createEntityManagerFactory("bank", props );

EntityManager em = emf.createEntityManager ();

,Bernd Muller, 5.11.2013 52/62

Page 69: Hasta la vista Mandantenfähigkeit?

Verwendung: persistence.xml oder programmatisch

<?xml version="1.0" encoding="UTF-8" ?>

<persistence ...>

...

<properties >

<property name="eclipselink.tenant-id"

value="007"/>

Map <String , String > props =

new HashMap <String , String >();

props.put("eclipselink.tenant -id", "Mandant -1");

EntityManagerFactory emf = Persistence

.createEntityManagerFactory("bank", props );

EntityManager em = emf.createEntityManager ();

,Bernd Muller, 5.11.2013 52/62

Page 70: Hasta la vista Mandantenfähigkeit?

Verwendung: Lesen

I Transparente Verwendung

...

props.put("eclipselink.tenant -id", "Mandant -1");

...

List <Kunde > list = em

.createQuery("Select k from Kunde k",

Kunde.class)

.getResultList ();

...

Kunde kunde = em.find(Kunde.class , <pk >));

...

,Bernd Muller, 5.11.2013 53/62

Page 71: Hasta la vista Mandantenfähigkeit?

Alternativen@Entity

@Multitenant

@Multitenant(MultitenantType.SINGLE_TABLE)

@TenantDiscriminatorColumn(name = "mandant")

@TenantDiscriminatorColumn(name = "mandant",

primaryKey = true)

@TenantDiscriminatorColumn(name = "mandant",

discriminatorType = DiscriminatorType.INTEGER)

public class Kunde { ...

I Nur beiden ersten Annotationen zwingend, sinvolle Defaultsexistieren (Convention over Configuration)

I Default fur Spaltenname: TENANT IDI Mehrere Diskriminatorspalten mit

@TenantDiscriminatorColumnsI DDL-Generierung funktioniert

,Bernd Muller, 5.11.2013 54/62

Page 72: Hasta la vista Mandantenfähigkeit?

Gemappter Tenant

I Muss read-only sein

@Entity

@Multitenant

@TenantDiscriminatorColumn(name = "mandant")

public class KundeMapped {

@Id @GeneratedValue

private Integer id;

...

// Die gemappte Diskriminatorspalte:

@Column(insertable = false , updatable = false)

private String mandant;

...

,Bernd Muller, 5.11.2013 55/62

Page 73: Hasta la vista Mandantenfähigkeit?

Gemappter Tenant

I Muss read-only sein

@Entity

@Multitenant

@TenantDiscriminatorColumn(name = "mandant")

public class KundeMapped {

@Id @GeneratedValue

private Integer id;

...

// Die gemappte Diskriminatorspalte:

@Column(insertable = false , updatable = false)

private String mandant;

...

,Bernd Muller, 5.11.2013 55/62

Page 74: Hasta la vista Mandantenfähigkeit?

Alternativen

@Entity

@Multitenant(MultitenantType.TABLE_PER_TENANT)

@TenantTableDiscriminator(type =

TenantTableDiscriminatorType.SCHEMA)

public class Kunde {

...

I Default: Tabelle mit Suffix der Tenant-Id

I Mehrere Schemata moglich mit type = SCHEMA

I Keine DDL-Generierung

,Bernd Muller, 5.11.2013 56/62

Page 75: Hasta la vista Mandantenfähigkeit?

Verwendung in Java-EE

<persistence ...>

<persistence-unit name="tenant-1" transaction-type="JTA">

<jta-data-source >jdbc/__default </jta-data-source >

<properties >

<property name="eclipselink.tenant-id"

value="Mandant-1"/>

...

</properties >

</persistence-unit >

<persistence-unit name="tenant-2" transaction-type="JTA">

<jta-data-source >jdbc/__default </jta-data-source >

<properties >

<property name="eclipselink.tenant-id"

value="Mandant-2"/>

...

</properties >

</persistence-unit >

</persistence >

Page 76: Hasta la vista Mandantenfähigkeit?

Verwendung in Java EE (cont’d)

@Singleton

@Startup

public class KundeService {

@PersistenceContext(unitName = "tenant -1")

EntityManager em1;

@PersistenceContext(unitName = "tenant -2")

EntityManager em2;

@PostConstruct

public void init (){

em1.persist(new Kunde("Barth", "Mario", "1.11.1972"));

em1.persist(new Kunde("Michael", "Mittermeier", "3.4.1966"));

em2.persist(new Kunde("Anke", "Engelke", "21.12.1965"));

em2.persist(new Kunde("Dieter", "Nuhr", "29.10.1960"));

}

}

Page 77: Hasta la vista Mandantenfähigkeit?

Alternative: Qualifier mit CDI

public class DatabaseProducer {

@Produces

@PersistenceContext(unitName = "tenant -1")

@Tenant1PC

private EntityManager em1;

@Produces

@PersistenceContext(unitName = "tenant -2")

@Tenant2PC

private EntityManager em2;

}

I Verwendung: @Inject mit QualifierI Mit eigener CDI-Erweiterung vollig transparent und flexibel

verwendbar,

Bernd Muller, 5.11.2013 59/62

Page 78: Hasta la vista Mandantenfähigkeit?

Fazit EclipseLink

I Am weitesten fortgeschritten

I Mit Annotationen: a la Java-EE

I Alle drei (vier!) Alternativen werden unterstutzt

,Bernd Muller, 5.11.2013 60/62

Page 79: Hasta la vista Mandantenfähigkeit?

Vergleich/Einschatzung der drei Provider

I Achtung: meine personliche Meinung!

I Und gilt nur fur Mandantenfahigkeit!

I Hibernate: im Augenblick besser nicht verwenden

I OpenJPA: verwendbar

I EclipseLink: scheint rund, ausgereift und verwendbar

,Bernd Muller, 5.11.2013 61/62

Page 80: Hasta la vista Mandantenfähigkeit?

Vergleich/Einschatzung der drei Provider

I Achtung: meine personliche Meinung!

I Und gilt nur fur Mandantenfahigkeit!

I Hibernate: im Augenblick besser nicht verwenden

I OpenJPA: verwendbar

I EclipseLink: scheint rund, ausgereift und verwendbar

,Bernd Muller, 5.11.2013 61/62

Page 81: Hasta la vista Mandantenfähigkeit?

Fragen und Anmerkungen

,Bernd Muller, 5.11.2013 62/62