Hasta la vista Mandantenfähigkeit?

Preview:

Citation preview

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

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

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

Auszug aus JSR 338: JPA 2.1

Section 2: Request

I . . .

I Support for multitenancy.

I . . .

,Bernd Muller, 5.11.2013 5/62

Hasta la vista Mandantenfahigkeit?

,Bernd Muller, 5.11.2013 6/62

Hasta la vista Mandantenfahigkeit?

Nein!

,Bernd Muller, 5.11.2013 6/62

Was bedeutet Mandantenfahigkeit?

— Hier nur die Datensicht —

,Bernd Muller, 5.11.2013 7/62

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

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

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

Die technische Sicht

I Daten eines Mandanten in . . .

Eigene DB EigenesSchema

GemeinsamesSchema

,Bernd Muller, 5.11.2013 9/62

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

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

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

Mandantenfahigkeit mit Hibernate

,Bernd Muller, 5.11.2013 13/62

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

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;    ...}

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();}

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

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

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

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

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    }}

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();}

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

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

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

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

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

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

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

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

Mandantenfahigkeit mit OpenJPA

,Bernd Muller, 5.11.2013 26/62

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

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

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

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

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

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

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

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

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

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

Interface DistributionPolicy

,Bernd Muller, 5.11.2013 32/62

Interface QueryTargetPolicy

,Bernd Muller, 5.11.2013 33/62

Interface FinderTargetPolicy

,Bernd Muller, 5.11.2013 34/62

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

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

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";

}

}

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

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

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

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

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

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

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

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

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

Mandantenfahigkeit mit EclipseLink

,Bernd Muller, 5.11.2013 44/62

,Bernd Muller, 5.11.2013 45/62

,Bernd Muller, 5.11.2013 48/62

,Bernd Muller, 5.11.2013 49/62

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

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

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

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

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

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

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

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

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

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 >

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"));

}

}

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

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

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

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

Fragen und Anmerkungen

,Bernd Muller, 5.11.2013 62/62

Recommended