Spring boot with multiple database connections - spring-boot

I made a simple SpringBoot REST application for testing purposes where the tables are in 2 databases, one is Mysql and one is Postgresql. To configure the 2 connections I used the instructions from here, at point 6 - "Multiple Databases in Spring Boot" and all seemed to be fine, the 2 connections were initiated but only the primary connection works.
So if the Mysql connection is annotated as #Primay only Mysql REST services work, on Postgresql the error for all tables is "org.hibernate.hql.internal.ast.QuerySyntaxException: <Entity_Name> is not mapped". But if I make a single change and set #Primary on the Postgresql connection then all Postgres tables are working and all Mysql tables give the same error(table not mapped).
So somehow I think the right connection is not autoselected based on the package.
UPDATE: I found another tutorial here using different database types, I followed the instructions but the result is the same, all tables in the secondary database give the error "org.hibernate.hql.internal.ast.QuerySyntaxException: <Entity_Name> is not mapped". I think the secondary connection is not used, somehow the primary one defaults on the wrong tables but I don't know why.
I uploaded this small Github project with my work.
https://github.com/victorqedu/MultipleSpringBootDS
UPDATE: In the DAO class a have autowired the constructor and #Autowire is setting the wrong EntityManager(I think this is the source of the problem), could I manually specify the right EntityManager?
#Autowired
public AntibiogramaAntibioticeDAOHibernateImpl(EntityManager theEntityManager) {
entityManager = theEntityManager;
}
I also tried the annotation #PersistenceContext on the EntityManager but the result is the same.
#PersistenceContext
private EntityManager entityManager;
I'm not sure the problem is EntityManagaer or the Session that I obtain from EntityManager.unwrap, seems to be little documentation about this...

This can be solved with Qualifier in a short description if you have multiple same type of beans(like EntityManager) you should use qualifier to wire them.
Therefore in your code you should
public AntibiogramaAntibioticeDAOHibernateImpl(
#Qualifier("primaryEntityManagerFactory") EntityManager theEntityManager)

Related

how to Resolve "could not initialize proxy - no session" error when using Spring repository

I'm working on a mutitenant project it maintains different schema for each tenant, followed Project
As we are dynamically switching the tenants so it looks like some configuration is missed which is closing the session or not keeping the session open to fetch the LAZY loaded objects. Which results in "could not initialize proxy - no session" error.
Please check below link to access the complete project and db schema scripts, please follow the steps given in Readme file.
Project
It will be helpful if someone can point out the issue in the code.
i tried to put service methods in #Transactional annotation but that didn't work.
I'm expecting it to make another call to the LAZY loaded object, This project is simplefied verson of the complex project, actually i have lot more lazy loaded objects.
Issue:-
I'm getting no Session error "could not initialize proxy [com.amran.dynamic.multitenant.tenant.entity.Tenant#1] - no Session"
at line 26 (/dynamicmultitenant/src/main/java/com/amran/dynamic/multitenant/tenant/service/ProductServiceImpl.java)
The issue is that your transaction boundaries are not correct. In TenantDatabaseConfig and MasterDatabaseConfig you've correctly added #EnableTransactionManagement, which will setup transactions when requested.
However - the outermost component that has an (implicit) #Transactional annotation is the ProductRepository (by virtue of it being implemented by the SimpleJpaRepository class - which has the annotation applied to it - https://github.com/spring-projects/spring-data-jpa/blob/864c7c454dac61eb602674c4123d84e63f23d766/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java#L95 )
and so your productRepository.findAll(); call will start a transaction, create a JPA session, run the query, close the session, close the transaction, which means that there is no longer any transaction / session open in which to perform the lazy-loading.
Therefore, your original attempt of
i tried to put service methods in #Transactional annotation but that didn't work.
IS the correct thing to do.
You don't say exactly what you tried to do, and where, but there are a few things that could have gone wrong. Firstly, make sure you're adding a org.springframework.transaction.annotation.Transactional and not a javax.transaction.Transactional annotation.
Secondly (and the more likely problem in this scenario), you'll need to configure the annotation with which transaction manager the transaction should be bound to, otherwise it may use an existing / new transaction created against the master DB connection, not the tenant one.
In this case, I think that:
#Service
#Transactional(transactionManager = "tenantTransactionManager")
public class ProductServiceImpl implements ProductService {
should work for you, and make all the methods of the service be bound to a transaction on the tenant DB connection.
EDIT: Answering a follow-up question:
can you please also suggest a better way to inject my tenantTransactionManager in all my service classes, as I don't want to mention tenantTxnManger in all service classes if there is any better way to do it ?
Yes, sure. You can create a meta-annotation that applies multiple other annotations, so you could create:
/**
* Marks class as being a service operating on a single Tenant
*/
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Service
#Transactional("tenantTransactionManager")
public #interface TenantService {
}
and then you can simply annotate your service classes with #TenantService instead of #Service:
#TenantService
public class ProductServiceImpl implements ProductService {

dynamically setting DataSource properties for Spring jdbc

I'm using spring jdbc and I want my application to connect to different DBMS as oracle,mySQL, SAS etc.
the application should work on different systems, so the connection properties are not priorly known.
Ideally, the user will be able to select connection type from a list and then set the connection properties (username,password...)
Can you please help me :)
Have a look at this post: http://examples.javacodegeeks.com/enterprise-java/spring/jdbc/spring-jdbctemplate-example/
There you can see the normal jdbctemplate use. As you can see the dao has got the datasource injected: you can basically do the same, but you need not to set the org.springframework.jdbc.datasource.DriverManagerDataSource properties in the applicationContext.xml. You will do it at runtime according to user choice. That basically means all the daos have to get the datasource needed params in input.
Hope this helps.

Testing Hibernate Mappings

I'm using Hibernate to map objects to a legacy schema which contains some ginormous tables via annotations (as XML files are so 2003). Since these classes are so large, yes I occasionally make an occasional typo, which Hibernate doesn't bother to tell me about until I try to run it.
Here's what I've tried:
One: Setting hbm2ddl.auto to "validate":
This causes the String values of the class to validate against varchar(255). Since many of the column types in the database are CHAR(n), this blows up. I would have to add the columnDefinition="CHAR(n)" to several hundred mappings.
Two: Using Unitils.
Importing these via Maven causes imports of dependency libraries which blow up other sections of code. Example: I'm using Hibernate 4.1, but Unitils imported Hibernate 3.2.5 and blew up a UserType.
So, is there another way to do this? I looked at the Unitils code to see if I could simply yank the sections I needed (I do that with apache-commons fairly often when I just need a single method), but that's not a simple task.
Hibernate is configured via a Spring application context.
Any ideas out there?
I would write tests against an in-memory database (HSQLDB, H2) using the Spring testing framework. You'll quickly see any mapping errors when you attempt to run queries against the tables.
The test class would look something like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=MyTestConfig.class)
#TransactionConfiguration(transactionManager="txMgr", defaultRollback=true)
public class MyTest {
#Autowired
private SessionFactory sessionFactory;
// class body...
}
I would configure Hibernate to auto-deploy the tables as part of the tests.

Jdbc Connection Pooling - using multiple schema known at runtime only

I am working on an engine that is doing the following:
gets data provider info from DB (that tells me to what database & schema details to connect to get my data)
use that info to connect to the database and get my data, that later I use to build some XML content.
The standard setup to handle and isolate database connection management would be to create a DataSource bean (I'm using Spring to wire my components) and inject that in my ProviderConfigDao (loads connection config) and ContentDao (loads data using connection details loaded previously). This would nicely isolate the handling of the connections from the actual code, thus the DAO classes not needing to know how and when a connection is created/opened/closed etc.
This setup doesn't work unfortunately, as when I create my connection, I need to be able to specify the database schema. I don't know all the different schemas from the beginning, so I can't create a set of DataSource objects to cover all of them, thus the DataSource object must be created at runtime and it's creation hidden from the users.
The only solution I can think of is:
Have another class/interface (DataSourceProvider) having one method:
//Gets the connection URL as parameter (which includes the schema name).
DataSource getDataSource(String url);
Add a bean in Spring config to provide a custom implementation for it that manages creation of DataSource objects for each schema.
Inject that object to my DAO classes instead of the DataSource object.
It's not a bad solution, but I was wondering if there is maybe support for something like this already in some open source package ... I'd rather use something already done and tested then reinvent the wheel.
Cheers,
Stef.
there's a JDBC Utils to get all the metada from a database org.springframework.jdbc.support.JdbcUtils
parameters:
DataSource
Implementation of org.springframework.jdbc.support.DatabaseMetaDataCallback

EntityManager Lifecycle when using Oracle's Virtual Private Database

I had a few questions all related to the way an entity manager is created and used in an application with respect to Virtual Private Databases, which is a feature in Oracle DB which enables Row Level Security.
In a session bean, we generally have the entity manager as a member, and its generally injected by the container. How is this entity manager managed by the container - I mean, if we want to implement a Virtual Private Database then we have to make sure that the Virtual Private Database-context remains valid for the entire user session, and we do not have to set this context everytime before we fire a query. (to include more verbiage here : a session bean implements a couple of functions and each of these functions uses the same entity manager; now, it should not be the case that we set the Virtual Private Database everytime in each of these functions which do some DB manipulations).
Further to #1, since the entity manager is cached in the session bean, do we need to explicitly close the entity manager in any scenario? (like we do for JDBC connections?)
Also, I was wondering what should be the use case(or design criteria) for using a JTA or a non-JTA datasource. Is the way we create an entity manager dependant on this?
To add w.r.t the requirement on VPD:
It would be nice if the container managed EM can somehow be made to enforce the VPD per user. Note that EM is injected in here, so there should be a mechanism to set the VPD on the connection(and later retrieve the same connection for 'this' user in 'this' session).
Without an injected EM, i think using a reference to EMF and then setting the properties for the EM can be done. Something like :
((org.eclipse.persistence.internal.jpa.EntityManagerImpl)em.getDelegate()).setProperties
It would be an overkill, if the VPD is set everytime before the query is fired, rather the connection should 'maintain' the VPD context during the user's session and later release the connection (after clearing the VPD) back to the pool.
In a session bean, an injected entity manager is container managed and by default transaction scoped.
This means when you call any method on the session bean and a transaction is started, the persistence context of the entity manager starts. When the transaction is committed or rollbacked it ends. There is thus no scenario in which you have to explicitly close the entity manager.
Furthermore, when there already is a transaction in progress, this is joined by default and when there already is a persistence context attached to said transaction it's propagated instead of a new one being created.
Stateful session beans have another option, and that's the extended persistence context. This one is coupled to the scope of the stateful bean instead of to individual transactions. You still don't have to do any closing yourself here.
Then, you can also inject an EntityManagerFactory (using #PersistenceUnit) and then get an entity manager from it: In that case you'll have an application managed entity manager. In this case you'll have to explicitly close it.
JTA datasources (transactional datasources) are by default used with container managed entity managers. The container takes care of everything here. non-JTA datasources are for situations where you need separate connections to a DB, possibly outside any running transaction, on which you can set auto commit mode, commit, rollback, etc your self.
These two different datasource types can be defined in orm.xml for a persistence unit. If you define a persistence unit with a non-JTA datasource, you typically create an entity manager for it using a factory and then manage everything your self.
Update:
Regarding the Virtual Private Database, what you seem to need here is a user specific connection per entity manager, but the normal way of doing things is coupling a persistence unit to a general data source. I guess what could be needed here is a datasource that's aware of the user's context when a connection is requested.
If you completely bypass the container and even largely bypass the JPA abstraction, you could go directly to Hibernate. It has providers that you can register globally like DriverManagerConnectionProvider and DatasourceConnectionProvider. If you provide your own implementations for these with a setter for the actual connection, you can ask these back from a specific entity manager instance just prior to using it, and then set your own connection in it.
It's doable, but needless to say a bit hacky. Hopefully someone else can give a more 'official' answer. Best would of course if Oracle provided an official plug-in for e.g. EclipseLink to support this. This document hints that it does:
TopLink / EclipseLink : Support filtering data through their
#AdditionalCriteria annotation and XML. This allows an arbitrary JPQL
fragment to be appended to all queries for the entity. The fragment
can contain parameters that can be set through persistence unit or
context properties at runtime. Oracle VPD is also supported, include
Oracle proxy authentication and isolated data.
See also How to use EclipseLink JPA with Oracle Proxy Authentication.

Resources