How to use Spring to manage connection to multiple databases - java

I have read other topics but didn't find a good and clear answer
What I'm trying to is to develop a web app which is able to:
1) Log/track user events in a seperate UI database which we connect via hibernate with the same database schema (maybe save connectionString to the different oracle databases)
2) At runtime when you log in you can choose an environment to connect to one of the three different oracle databases that have the same schema (but not the same data)
3) provide the correct DataSource with username and password (where to get this sensitive data? I would not keep this stored somewhere in the application)
I'm fairly new to the Spring framework. I found this link which could be a first lead.
Any suggestions?
Also using Spring 3.1 or 3.2, JDBC to query to my oracle database and hibernate mapping to my UI database. This sounds quite confusing so I have a picture:
infrastructure

Just create different DAOs each with a separate persistence-unit attached to them.
In your persistence.xml you can have multiple persistence-unit's each connecting to a different database.
Example:
public class Dao1{
#PersistenceContext(unitName="Database1")
protected EntityManager entityManager;
public class Dao2{
#PersistenceContext(unitName="Database2")
protected EntityManager entityManager;
<?xml version="1.0" encoding="UTF-8"?>
<persistence 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_1_0.xsd"
version="1.0">
<persistence-unit name="Database1">
<exclude-unlisted-classes />
<properties>
</properties>
</persistence-unit>
<persistence-unit name="Database2">
<exclude-unlisted-classes />
<properties>
</properties>
</persistence-unit>
</persistence>

The link you have mentioned in your post says following:
1) create different data sources pointing to different schema.
2) extends AbstractRoutingDataSource and create your own data source, override determineCurrentLookupKey method which will provide value of key. in your case it will return whatever user choose from UI. also in the bean definition of your custom data source pass all the data source as map with key as option available at UI.
3) Now assign this data source into your session factory bean.

Related

StandAlone CDI + JTA Without JNDI

I am using CDI + DeltaSpike + Camel in a standalone app.
Here is my current setup :
persistence.xml
<persistence 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"
version="2.0">
<persistence-unit name="primary" transaction-type="RESOURCE_LOCAL">
<shared-cache-mode>DISABLE_SELECTIVE</shared-cache-mode>
</persistence-unit>
Custom properties on EntityManagerFactoryProducer:
properties.put("hibernate.connection.provider_class", "org.example.HikariConnectionProvider");
I'm using DeltaSpike JPA Transaction with (https://deltaspike.apache.org/documentation/jpa.html):
org.apache.deltaspike.jpa.api.transaction.TransactionScoped;
org.apache.deltaspike.jpa.api.transaction.Transactional;
I would like to use Infinispan to sync my app caches.
According to Infinispan doc:
"It is highly recommended that Hibernate is configured with JTA transactions"
How can I use JTA transactions ?
I tried to change "RESOURCE_LOCAL" to "JTA" but I don't understand what am I supposed to configure for :
hibernate.transaction.factory_class
hibernate.transaction.jta.platform
I am not using JNDI, and I am not in an application server.
Also, I would like to use #javax.transaction.Transactional instead of DeltaSpike.
Essentially, you are asking how to use most Java EE features without using a Java EE container.
Of course, there are JTA implementations like Atomikos you can embed in a "standalone" application.
On the other hand, it might be a lot easier to start with a full-blown Java EE environment and then ignore or exclude anything you don't need.
App servers are rather lightweight these days, and if a self-contained executable is a must-have for you, then have a look at WildFly Swarm or Payara Micro.

EntityManager in SSB null

I am trying to update a small alpha version of a enterprise application originally written in Java6. Now I want to use:
Java 7
JSF latest
Maven
EJB 3.2 with Glassfish
So far I can deploy my EAR file on Glassfish without problems. My webapp can be loaded, the first JSF pages navigate fine. And my JSF backing bean seems to also load my Stateless session beans fine. Debugging showed me, I can get from one SSB to another coming from my backing bean. The last and final step that I am missing is my entity manager and persistence.
My class is annoated with #Stateless and i am using:
#PersistenceContext(unitName = "myProjectPU")
protected EntityManager entityManager;
But the entity manager is null :(
My persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="myProjectPU" transaction-type="JTA">
<jta-data-source>jdbc/myProject</jta-data-source>
<properties>
<property name="javax.persistence.schema-generation.create-database-schemas" value="true" />
</properties>
</persistence-unit>
</persistence>
Any ideas? Does the persistence.xml have to be inside the ear maven module? Right now its in the ejb maven module, where my classes which use the entity manager reside.
Well finally I found the problem. Scrolling up in the glassfish logs showed that the nullpointer exception followed up an earlier exception that stated "No database selected". The problem was not in the code, but in the Glassfish JDBC Connection that I made. My ping worked fine and i thought the connection was ok. But you dont only have to add the mysql port and username and password. You also MUST change the default URL and add (additional properties in connection pool) the following value:
jdbc:mysql://localhost:3306/yourdatabase
before it was defaulted to:
jdbc:mysql://:3306/
Take also care that there are two parameters, Url and URL! After that not only the ping succeeded, but also the database connection with entity manager worked fine. :(

Hibernate entity manager looking for tables in different schemas

I am implementing jpa persistence using hiberante-entity manager in a java web project.
I have set following property in in persistence.xml.
<property name="hibernate.hbm2ddl.auto" value="update"/>
I have a schema for each user. For e.g i have a schema for user1 and one for user2.
If the table 'ABC' is present in user1 schema but not in user2 schema & I deploy the application and it uses user2 db credentials, i get the message 'user1.ABC' table found so the 'ABC' table is not created in user2 schema.
When i tried with following property in the persistence.xml file the table is created in the user2 schema.
<property name="hibernate.hbm2ddl.auto" value="create"/>
My question is
why hibernate is searching in another schema i.e user1 if the application is using user2 db credentials? and
I don't want to create the schema every time the server is started so how can i avoid using
the value 'create'.
EDIT: Below is my persistence.xml file
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name="XXXXXX" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>org.axonframework.saga.repository.jpa.SagaEntry</class>
<class>org.axonframework.saga.repository.jpa.AssociationValueEntry</class>
<properties>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
Thanks in advance
I am also facing the same issue, and after digging a lot, get to know that the bug is related to the Mysql Connector.
After changing MySql Connector 6.0.5 to 5.1.28 It works fine for me.
I hope It can help you. Cheers
Has the same problem.
After set <property name="hibernate.default_schema" value="MY_SCHEMA"/> the problem has been solved.
Check if you are calling user1 and user2 in your Hibernate Sessionfactory.
If you want to handle several schemas properly then use multi-tenant per schema also if you want to update/create/migrate/handle columns/tables/schemas/databases then use flyway or liquibase
REFERENCES
Multitenancy https://vladmihalcea.com/hibernate-database-schema-multitenancy/
Flyway https://flywaydb.org
Liquibase https://www.liquibase.org
The Hibernate documentation is clear about this, you need to enable multi-tenant operations as described in this answer and this example.
Basically you have to declare multiple persistence units and have each point to a different schema. Each can then use different login credentials as well.
Hibernate documentation link
To summarise:
Define your persistence unit
Define your mapping files per persistence unit
When using JPA add the following:
3. Specifying tenant identifier from SessionFactory
4. Implement a MultiTenantConnectionProvider

UTF - 8 with JPA and Glassfish 4.0

I am having difficulties with UTF-8 characters. This is a simple JSF project. I use JSF 2.2 and Glassfish 4.0
I have a method where I go:
em.persist(user);
When I debug
user.getName()
in this point, I can see the utf-8 characters in my IDE. Also I keep the string in a session - bean and I can see them on the browser fine as well.
Only when they are persisted to DB, they are persisted as: ?????
I can also edit the DB myself and save utf-8 characters. What I mean is, my SQL configuration is good for UTF-8.
The problem is somewhere in JPA.
This is what I have tried: ( all together: )
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="Persistence" transaction-type="JTA">
<jta-data-source>fus</jta-data-source>
<class>com.tugay.fup.core.model.User</class>
<properties>
<property name="javax.persistence.jdbc.url"
value="jdbc:mysql://localhost:3306/fus?useUnicode=yes&characterEncoding=UTF-8"/>
</properties>
</persistence-unit>
</persistence>
This is glassfish-web.xml:
<glassfish-web-app>
<parameter-encoding default-charset="UTF-8"/>
</glassfish-web-app>
And I am using EntityManager managed by container (transaction type = JTA)
So in JDBC connection pools in Glassfish I have:
jdbc:mysql://localhost:3306/fus?useUnicode=true&connectionCollation=utf8_general_ci&characterSetResults=utf8
for: property: URL...
However none of these help.
Still characters not persisted correctly.
When using Glassfish, you can set these properties as additional to your JDBC Connection Pools. Locate and view your database connection in Web Administration (Resources->JDBC Connection Pools->your.connection). In additional properties tab add (if there are not present yet) mentioned properties and restart your server:
//name, value
characterEncoding, UTF-8
characterSetResults, UTF-8
useUnicode, true
The result will be the same if parameters are added to URL, but this is more maintainable solution in my opinion.
This solved it:
jdbc:mysql://localhost:3306/fus?useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8
so this was wrong:
jdbc:mysql://localhost:3306/fus?useUnicode=true&connectionCollation=utf8_general_ci&characterSetResults=utf8

Log4j + OpenJPA = NoClassDefFoundError: javax/persistence/AttributeConverter

I'm trying to get log4j (I would also be happy to use any logging api as log as it is jpa persistent) use jpa appender.
My persistence.xml looks like this
<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<class>org.apache.camel.processor.interceptor.jpa.JpaTraceEventMessage</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackJsonAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.MarkerAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.MessageAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.StackTraceElementAttributeConverter</class>
<class>org.apache.logging.log4j.core.appender.db.jpa.converter.ThrowableAttributeConverter</class>
<class>com.xxxxxx.lab.logging.ReportEntity</class>
<properties>
<property name="openjpa.jdbc.DBDictionary" value="org.apache.openjpa.jdbc.sql.HSQLDictionary"/>
<!-- value="buildSchema" to runtime forward map the DDL SQL; value="validate" makes no changes to the database -->
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/>
<property name="openjpa.RuntimeUnenhancedClasses" value="supported"/>
</properties>
</persistence-unit>
As per apidocs:
Many of the return types of LogEvent methods (e.g., StackTraceElement,
Message, Marker, Throwable, ThreadContext.ContextStack, and
Map) will not be recognized by the JPA provider. In
conjunction with #Convert, you can use the converters in the
org.apache.logging.log4j.core.appender.db.jpa.converter package to
convert these types to database columns.
So I added all necessary classes, but it still throws:
java.lang.NoClassDefFoundError: javax/persistence/AttributeConverter
AttributeConverter seems something new in JPA2.1. Are you sure your project is using JPA2.1 instead of any prior version?
Just curious, why are you so insists to use JPA for log persistence? There are plenty JDBC-based solution which works well. I don't see any reason for using JPA solution unless you are going to make use of the logging related entities in your application.

Categories

Resources