Slice is activated via the following property settings:
The basic configuration property is
<property name="openjpa.BrokerFactory" value="slice"/>
This critical configuration activates a specialized object management kernel that can work against multiple databases.
Each database slice is identified by a logical name unique within a
persistent unit. The list of the slices is specified by
openjpa.slice.Names
property.
For example, specify three slices named "One"
,
"Two"
and "Three"
as follows:
<property name="openjpa.slice.Names" value="One, Two, Three"/>
This property is not mandatory. If this property is not specified then
the configuration is scanned for logical slice names. Any property
"abc"
of the form openjpa.slice.XYZ.abc
will
register a slice with logical
name "XYZ"
.
The order of the names is significant when no openjpa.slice.Master
property is not specified. The persistence unit is then scanned to find
all configured slice names and they are ordered alphabetically.
Each database slice properties can be configured independently.
For example, the
following configuration will register two slices with logical name
One
and Two
.
<property name="openjpa.slice.One.ConnectionURL" value="jdbc:mysql:localhost//slice1"/> <property name="openjpa.slice.Two.ConnectionURL" value="jdbc:mysql:localhost//slice2"/>
Any OpenJPA specific property can be configured per slice basis.
For example, the following configuration will use two different JDBC
drivers for slice One
and Two
.
<property name="openjpa.slice.One.ConnectionDriverName" value="com.mysql.jdbc.Driver"/> <property name="openjpa.slice.Two.ConnectionDriverName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
Any property if unspecified for a particular slice will be defaulted by corresponding OpenJPA property. For example, consider following three slices
<property name="openjpa.slice.One.ConnectionURL" value="jdbc:mysql:localhost//slice1"/> <property name="openjpa.slice.Two.ConnectionURL" value="jdbc:mysql:localhost//slice2"/> <property name="openjpa.slice.Three.ConnectionURL" value="jdbc:oracle:localhost//slice3"/> <property name="openjpa.ConnectionDriverName" value="com.mysql.jdbc.Driver"/> <property name="openjpa.slice.Three.ConnectionDriverName" value="oracle.jdbc.Driver"/>
In this example, Three
will use slice-specific
oracle.jdbc.Driver
driver while slice
One
and Two
will use
the driver com.mysql.jdbc.Driver
as
specified by openjpa.ConnectionDriverName
property value.
A connection pool may also be used with Slice by using the openjpa.ConnectionProperties
property.
For example to use commons-dbcp with Derby you might use the following properties :
<property name="openjpa.BrokerFactory" value="slice"/> <property name="openjpa.ConnectionDriverName" value="org.apache.commons.dbcp.BasicDataSource"/> <property name="openjpa.slice.Names" value="One,Two"/> <property name="openjpa.slice.Master" value="Two"/> <property name="openjpa.slice.One.ConnectionProperties" value="Url=jdbc:derby:target/database/openjpa-slice1;create=true, DriverClassName=org.apache.derby.jdbc.EmbeddedDriver"/> <property name="openjpa.slice.Two.ConnectionProperties" value="Url=jdbc:derby:target/database/openjpa-slice2;create=true, DriverClassName=org.apache.derby.jdbc.EmbeddedDriver"/> <property name="openjpa.jdbc.DBDictionary" value="derby"/>
Be aware that you need to set the DBDictionary when using commons-dbcp.
Slice needs to determine which slice will persist a new instance.
The application can only decide this policy (for example,
all PurchaseOrders before April 30 goes to slice One
,
all the rest goes to slice Two
). This is why
the application has to implement
org.apache.openjpa.slice.DistributionPolicy
and
specify the implementation class in configuration
<property name="openjpa.slice.DistributionPolicy" value="com.acme.foo.MyOptimialDistributionPolicy"/>
The interface org.apache.openjpa.slice.DistributionPolicy
is simple with a single method. The complete listing of the
documented interface follows:
public interface DistributionPolicy { /** * Gets the name of the slice where a given instance will be stored. * * @param pc The newly persistent or to-be-merged object. * @param slices name of the configured slices. * @param context persistence context managing the given instance. * * @return identifier of the slice. This name must match one of the * configured slice names. * @see DistributedConfiguration#getSliceNames() */ String distribute(Object pc, List<String> slices, Object context); }
While implementing a distribution policy the most important thing to
remember is collocation constraint.
Because Slice can not establish or query any cross-database relationship, all the
related instances must be stored in the same database slice.
Slice can determine the closure of a root object by traversal of
cascaded relationships. Hence user-defined policy has to only decide the
database for the root instance that is the explicit argument to
EntityManager.persist()
call.
Slice will ensure that all other related instances that get persisted by cascade
are assigned to the same database slice as that of the root instance.
However, the user-defined distribution policy must return the
same slice identifier for the instances that are logically related but
not cascaded for persist.
The entities that are enumerated in openjpa.slice.ReplicatedTypes
property can be stored in multiple slices as identical copies.
Specify the implementation class of ReplicationPolicy
in configuration as
<property name="openjpa.slice.ReplicationPolicy" value="com.acme.foo.MyReplicationPolicy"/>