How do I connect to multiple databases with one persistence unit? - java

I am using JPA with Hibernate as my JPA provider. My application need to connect to database defined in persistence.xml (default persistence unit) grab multiple configured systems from table and create for each of them EntityManagerFactory (systems differ only in connection params, dialect and driver).
Is it possible to do it with "template" persistence unit? For now I'm using different copy persistence unit for each system but it's seems senseless.

You probably need to write your own JCA compliant connector that wraps the distinct DB connectors and expose that via JPA:

Related

Spring multi tenancy

I have two databases: Oracle and PostgreSQL where I have multiple schemas - one per each customer. I need to have an opportunity to route datasources by web request. I tried to use Spring's AbstractRoutingDatasource but it works only with single dialect. Are there any other solutions for this task?
I found a solution. You can explicity tell Hibernate which dialect to choose using hibernate.dialect property. So you can implement your own dialect extends org.hibernate.dialect.Dialect class, override all public methods and delegate calls to specific dialects. The good thing is Hibernate calls this (Dialect's) methods before performing any database requests. In my specific case I've implemented a custom dialect with map of dialects I need for my project and now I can use the same repositories and freely choose Postgresql, Oracle or MySQL depending on logged in user

Multitenancy in Hibernate using both Schema and Database

The application has 2 separate databases, say:
DB1
DB2
and database of different companies are split across these 2 databases, like:
DB1
Company 1
Company 2
Company 3
Company 4
DB2
Company 5
Company 6
Company 7
Company 8
How can such a scenario be configured in hibernate?
All the examples refer either to Schema based multitenancy or Database multitenancy.
Is there any way to configure such a scenario?
To do that you should create two sessionFactory Bean in your config file. and in your DAO layer you call it using qualifier annotation.
You're going to have to create your own implementation of MultiTenantConnectionProvider that handles both database and schema level multitenancy. That should be the path of least resistance.
Here's some slightly outdated info about fighting with spring, hibernate and custom multitenancy: Setting up a MultiTenantConnectionProvider using Hibernate 4.2 and Spring 3.1.1
I will get strategy with separate database and in ConnectionProvider override method getConnection() to set schema.
I this case I can change databases and select specyfic schema for tenant.

Global Transaction with Teradata

I am using Oracle and Teradata both databases in my Java based project. I want to setup global transaction so that I can perform operations on both the Database under one transaction.
For global transactions such as JTA or atomikos database must have XA driver support. But as my findings Teradata doesn't have XA driver.
So now how could I setup the global transaction and performance operations on both database under 1 transaction?
why would you want to do that?
If you use terradata as a data warehouse, you could feed it in a separate, asynchronous process.
That being said, you don't strictly need an XA driver to run as part of a JTA transaction. Of course, not doing so leads you to make some compromise, especially in case of recovery.
All JTA-aware transaction managers I know have the notion of Last Resource Commit (or LRC, check this page for more details). You could configure your Teradata datasource as LRC.
Resources
Bitronix config
Atomikos config
If you use oracle and the teradata database, you need to configure the oracle database gateway to support distributed transactions. In that you will not use XA, but you will use distributed transactions with two-phase commit.

Understanding Persistence.xml in JPA

I am trying to understand the following things:
When I make an EJB project and deploys it to Glassfish do I set up JDBC resources/connection pools at the administrator center of Glassfish or do I add all the different properites for username, password etc in the persistence.xml? I don't understand one bit of that.
I do not understand why we have both JDBC resource and JDBC Connection pool either. What is it and what is the difference between them? Could somebody explain me these things or/and provide some good link about the persistence.xml file and the part around it?
It's better to define a JDBC resource rather than putting the information in the persistence.xml. In this way you are going to take advantage of connection pooling. You are going to define the JNDI name you provided for the JDBC resource in the persistence.xml.
What is it and what is the difference between them
Below I pasted some parts of the Glassfish 3.x help. Check it out. It's really helpful
JDBC connection pool
A JDBC connection pool contains a group of JDBC connections that are created when the connection pool is registered
JDBC resource
A Java DataBase Connectivity (JDBC) resource (data source) provides applications with the means of connecting to a database. Typically, the administrator creates a JDBC resource for each database accessed by the applications deployed in a domain; however, more than one JDBC resource can be created for a database.
Applications get a database connection from a connection pool by looking up a data source on the Java Naming and Directory Interface (JNDI) API tree and then requesting a connection. The connection pool associated with the data source provides the connection to the application.
Think of the data source(JDBC) resource as a factory for a facade of some type of data service(Connection Pool). In this case it implicitly gets a connection from the pool and provides it to your application.
An example persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="WebApplication2PU" transaction-type="JTA">
<jta-data-source>jdbc/sample</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties/>
</persistence-unit>
</persistence>
This line is the JNDI name I gave to my JDBC resourse:
<jta-data-source>jdbc/sample</jta-data-source>
You dont need to define anything related to the database connection in your persistence.xml this way...just the JNDI name of the resource
When you configure a data source in your application server, all you need to set in persistence.xml is the JNDI name of that data source.
I found this in the book that I read to learn Spring and Hibernate. The book name is Professional Java for Web Applications written by Nicholas S. Williams. I think this will be helpful for many people.
Creating the Persistence Configuration:
To use the entities you create, you must define a persistence unit. Doing so is simple. Create a
persistence.xml file not dissimilar from a deployment descriptor, but with far fewer options
to worry about. The root element of a persistence configuration file is <persistence>. This
element may contain one or more <persistence-unit> elements. No other elements are
within <persistence>. <persistence-unit> has two attributes: name specifies the name of
the persistence unit and transaction-type indicates whether this persistence unit uses Java
Transaction API (JTA) transactions or standard local transactions.
You must specify a name, which is how you locate the persistence unit in code. If not specified,
transaction-type defaults to JTA in a Java EE application server and RESOURCE_LOCAL in a Java
SE environment or simple Servlet container. However, to prevent unexpected behavior it’s best to
always set this value explicitly instead of relying on a default value.
<persistence-unit> contains the following inner elements. None of them are required (so
<persistence-unit> may be empty); however, you must specify whichever elements you use in the
following order:
<description> contains a useful description for this persistence unit. Although it makes
reading the persistence file easier, it has no semantic value.
<provider> specifies the fully qualified class name of the javax.persistence.spi
.PersistenceProvider implementation used for this persistence unit. By default, when you
look up the persistence unit, the API will use the first JPA provider on the classpath. You
can include this element to mandate a specific JPA provider.
You can use either <jta-data-source> or <non-jta-data-source> (but not both) to
use a JNDI DataSource resource. You may use <jta-data-source> only if
transaction-type is JTA; likewise you may use <non-jta-data-source> only
if transaction-type is RESOURCE_LOCAL. Specifying a DataSource causes the persistence
unit to use that DataSource for all entity operations.
<mapping-file> specifies the classpath-relative path to an XML mapping file. If you don’t
specify any <mapping-file>, the provider looks for orm.xml. You may specify multiple
<mapping-file> elements to use multiple mapping files.
You can use one or more <jar-file> elements to specify a JAR file or JAR files that the
JPA provider should scan for mapping-annotated entities. Any #Entity, #Embeddable,
#javax.persistence.MappedSuperclass, or #javax.persistence.Converter classes
found are added to the persistence unit.
You can use one or more <class> elements to indicate specific #Entity, #Embeddable,
#MappedSuperclass, or #Converter classes that should be added to the persistence unit.
You must annotate the class or classes with JPA annotations.
Using <exclude-unlisted-classes /> or <exclude-unlisted-classes>true</exclude-unlisted-classes> indicates that the provider should ignore classes not
specified with <jar-file> or <class>. Omitting <exclude-unlisted-classes> or using
<exclude-unlisted-classes>false</exclude-unlisted-classes> causes the JPA
provider to scan the classpath location of the persistence file for JPA-annotated classes. If
persistence.xml is located in a JAR file, that JAR file (and only that JAR file) is scanned
for classes. If persistence.xml is located in a directory-based classpath location (such as /
WEB-INF/classes), that directory (and only that directory) is scanned for classes. Prior to
Hibernate 4.3.0 and Spring Framework 3.2.5, specifying this element with the value false
was incorrectly interpreted as true.
<shared-cache-mode> indicates how entities are cached in the persistence unit (if the JPA
provider supports caching, which is optional). NONE disables caching, whereas ALL enables
caching for all entities. ENABLE_SELECTIVE means that only entities annotated #javax
.persistence.Cacheable or #Cacheable(true) (or marked as cacheable in orm.xml)
are cached. DISABLE_SELECTIVE results in caching of all entities except those annotated
#Cacheable(false) (or marked as non-cacheable in orm.xml). The default value,
UNSPECIFIED, means that the JPA provider decides what the effective default is. Hibernate
ORM defaults to ENABLE_SELECTIVE, but relying on this is not portable.
<validation-mode> indicates if and how Bean Validation should be applied to entities.
NONE means that Bean Validation is not enabled, whereas CALLBACK makes the provider
validate all entities on insert, update, and delete. AUTO has an effective value of CALLBACK
if a Bean Validation provider exists on the classpath and an effective value of NONE if no
Bean Validation provider exists on the classpath. If you enable validation, the JPA provider
configures a new Validator to validate your entities. If you have configured a special
Spring Framework Validator with your custom localized error codes, the JPA provider
ignores it. As such, it’s best to set the validation mode to NONE and use Bean Validation
before your persistence layer is invoked.
<properties> provides a way to specify other JPA properties, including standard JPA
properties (such as JDBC connection string, username, and password, or schema generation
settings) as well as provider-specific properties (such as Hibernate settings). You specify
one or more properties using nested elements, each with a name and value
attribute.
Nicholas S. Williams, Professional Java for Web Applications, (Indianapolis, Indiana: John Wiley & Sons, Inc., 2014), pg 584-585

Are there any in-memory JDBC databases that support XA distributed transactions?

I want to use an in-memory database to test my application, but it needs to support XA distributed transactions. My first idea for an in-memory database was HSQLDB, but it appears not to support XA. Are there any?
Looks like H2 supports this.
Both H2 database and HSQLDB support it, couldn't find any other java embedded databases even in 2019. But it's not correctly implemented in either of them: the transaction is rolled back as soon as the client disconnects. According to the X/Open spec, when a database prepares a transaction, its data should be persistently stored and must be available to be committed later.
In H2 the XA code is unmaintained.
If you want an XA-supporting database for your tests, you can use Postgres using the TestContainers project:
#ClassRule
public static PostgreSQLContainer container = new PostgreSQLContainer<>("postgres:12.1")
.withCommand("postgres -c max_prepared_transactions=10");
Then create a datasource like this:
PGXADataSource dataSource = new PGXADataSource();
dataSource.setURL(container.getJdbcUrl());
dataSource.setUser(container.getUsername());
dataSource.setPassword(container.getPassword());
dataSource.setDatabaseName(container.getDatabaseName());

Categories

Resources