How to dynamically manage multiple datasources - java

Similar topics have been covered in other threads, but I couldn't find a definitive solution to my problem.
What we're trying to achieve is to design a web app which is able to:
read a datasource configuration at startup (an XML file containing multiple datasource definitions, which is placed outside the WAR file and it's not the application-context or hibernate configuration file)
create a session factory for each one of them (considering that each datasource is a database with a different schema)
switch at runtime to different datasources based on user input (users can select which datasource they want to use)
provide the correct dao object to manage user requests.
At the moment we have a DAO Manager object which is able to read the datasource configuration file and instantiate multiple session factories, saving them in a map. Each session factory is created with a configuration containing the proper hibernate mapping classes (different for each database schema). Moreover we have multiple DAO interfaces with their implementations, used to access "their database".
At this point we would need a way to get from the DAO Manager a specific DAO object, containing the right session factory attached, all based on the user request (basically a call from the above service containing the datasource id or a custom datasource object).
Ideally the service layer should use the DAO Manager to get a DAO object based on the datasource id (for instance), without worrying about it's actual implementation: the DAO Manager would take care of it, by creating the correct DAO object and injecting in it the right session factory, based on the datasource id.
My questions are:
Is this a good approach to follow?
How can I use Spring to dynamically inject in the DAO Manager multiple DAO implementations for each DAO interface?
Once the session factories are created, is there a way to let Spring handle them, as I would normally do with dependency injection inside the application-context.xml?
Would the 2nd Level Cache still work for each Session Factory?

Is this a good approach to follow?
It's probably the only possible approach. So, yes.
How can I use Spring to dynamically
inject in the DAO Manager multiple DAO
implementations for each DAO
interface?
Dynamically? I thought you wanted to do it at startup time. If so, just provide an accessor with a list or array:
public void setMyDaos(List<Mydao> daos){
this.daos = daos;
}
Once the session factories are
created, is there a way to let Spring
handle them, as I would normally do
with dependency injection inside the
application-context.xml?
This one's tough. I'd say you will probably have to store your sessionFactory bean in scope=session

Related

Spring bean creation lifecycle : Why having multiple interaction points?

I'm learning spring and I'm stuck with the bean lifecycle !
When creating a bean, spring gives us several maners to interact with it. We can use one or all of :
BeanFactoryPostProcessor
BeanPostProcessor#postProcessBeforeInitialization
#PostConstruct
InitializingBean#afterPropertiesSet
#Bean#initMethod
BeanPostProcessor#postProcessAfterInitialization
Spring calls them in the order above
My question is : why all these points of interaction ? and when to use each of them (the use case) ?
A BeanFactoryPostProcessor and a BeanPostProcessor are quite different beast and also apply to different things.
A BeanFactoryPostProcessor will operate on the metadata for a bean (I like to call it the recipe) and will post process that. A well know example is the PropertySourcesPlaceholderConfigurer which will inject/replace all #Value in configuration with the value. A BeanFactoryPostProcessor operates on the metadata and thus before any bean has been created.
The BeanPostProcessor can be applied to a bean and can even replace a bean. Spring AOP uses this quite a lot. An example is the PersistenceExceptionTranslationPostProcessor, when a bean has been created it will pass through this BeanPostProcessor and when it is annotated with #Persistence the bean will be replaced by a proxy. This proxy adds exception translation (i.e. it will convert JpaException and SQLException to the Spring DataAccessException). This is done in a BeanPostProcessor. And can be be done before the init-callbacks are called (the postProcessBeforeInitializationor after they have been called thepostProcessAfterInitialization). The PersistenceExceptionTranslationPostProcessorwill run in thepostProcessAfterInitialization` as it needs to be certain the bean has been initialized.
The ServletContextAwareProcessor will run right after the object has been created to inject the ServletContext as early as possible as the initializing of a bean might depend on it.
The 3 callbacks for initializing a bean are more or less the same but are called in sequence because they have been included in later versions. It starter with only an interface InitializingBean and init-method in xml (later also added to #Bean and the annotation support was added when annotations became a thing.
You need init methods to initialize a bean, you might want to check if all properties have been set (like a required datasource) or you might want to start something. A DataSource (especially a connection pool) is a good example to initialize. After all dependencies have been injected you want to start the pool so it will open the connections. Now as you probably cannot modify the code you want to use the init-method if you control the code you probably want to add #PostConstruct. If you are writing an framework that depends on Spring I would use the InitializingBean.
Next to those 3 init methods you also have the destruction counter-parts. The DisposableBean interface (and destroy-method) and the #PreDestroy annotation. Again when you stop your application you also want to close the connections in your connection pool and you want to probably call the close method on the DataSource. A perfect sample of a destruction callback.

Change current schema before using spring data Repository - Multi tenancy

I am using a multi tenant spring boot web application which reads some data from a database.
I have built schema per tenant model, implementing MultiTenantConnectionProvider and CurrentTenantIdentifierResolver to set connections based on the tenant. The tenant is resolved using a ThreadLocal variable, set in a Filter (built by extending OncePerRequestFilter).
However, I need to solve for a specific case where I do not get the tenant information at the filter. I can however, get the tenant information later while processing the request in a service, but by this time the entity manager is set (seems to be done by OpenSessionInViewFilter looking at spring sources) to use the default schema and all my queries fail because the default schema do not contain the data I need.
My question is, how do I set the entity manager to point to the tenant specific schema at service level, after the hibernate filter has already set the session? I could do whatever the filter (OpenSessionInViewFilter) is doing, something like the below:
EntityManager entityManager = entityManagerFactory.createEntityManager();
TransactionSynchronizationManager.bindResource(entityManager, new EntityManagerHolder(entityManager));
//unbind once I am done using the repositories
But I was thinking if this is the right way or if there is any other better, easier, documented way.
EntityManager entityManager = entityManagerFactory.createEntityManager();
TransactionSynchronizationManager.bindResource(entityManager, new
EntityManagerHolder(entityManager));
The above didn't work for me. However, I found a workaround - by running my task in a different thread (I just created a fixed thread pool executor and submitted my tasks) and setting the new tenant in a ThreadLocal object, I was able to achieve what I wanted. With the right CurrentTenantIdentifierResolver and MultiTenantConnectionProvider implementations, a connection to the expected tenant schema got established.

Can we have multiple dataSources to single database

I am having spring webservice application with oracle as a database. Right now i have datasource created using weblogic server. Also using eclipse linkg JPA to do both read and write transactions(insert,Read and update). Now we want to separate dataSources for read(read) and wrtie(insert or update) transactions.
My current dataSource is as followed:
JNDI NAME : jdbc/POI_DS
URL : jdbc:oracle:thin:#localhost:1521:XE
using this, I am doing both read and write transactions.
What if i do the following:
JNDI NAME : jdbc/POI_DS_READ
URL : jdbc:oracle:thin:#localhost:1521:XE
JNDI NAME : jdbc/POI_DS_WRITE
URL : jdbc:oracle:thin:#localhost:1521:XE
I knew that using XA datasource we can define multiple dataSources. Can I do same thing without XA dataSource. Does any one tried this kind of approach.
::UPDATE::
Thank you all for your responses I have implemented following solution.
I have taken the multiple database approach. where you will define multiple transactionManagers and managerFactory. I have taken only single non xa dataSource(JNDI) that is refereed in EntityManagerFactory Bean.
you can reefer following links here which are for multiple dataSources
Multiple DataSource Approach
defining #transactional value
Also explored on transaction managers org.springframework.transaction.jta.WebLogicJtaTransactionManager and org.springframework.orm.jpa.JpaTransactionManager as well.
There is an interesting article about this in Spring docs - Dynamic DataSource Routing. There is an example there, that allows you to basically switch data sources at runtime. It should help you. I'd gladly help you more, if you have any more specific questions.
EDIT: It tells, that the actual use is to have connection to multiple databases via one configuration, but you could manage to create different configs to one database with different params, as you'd need to.
I would suggest using Database "services". Each workload, read-only and read-write, would be using its own service to access the database. That way you can use AWR reports to get statistics for each service. You can also turn off read-write when you keep read-only up and running.
Here is a pointer to the Oracle Database documentation that talks about Services:
https://docs.oracle.com/database/121/ADMIN/create.htm#CIABBCAI
If you're using spring, you should be able to accomplish this without using 2 Datasources via spring #Transactional with the readonly property set to true. The reason why I suggest this is that you seem to be concerned about the transactionality only and this seems to be catered for in the spring framework?
I'd suggest something like this for your case:
#Transactional(readOnly = true)
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
// do something
}
// these settings have precedence for this method
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
// do something
}
}
Using this style, you should be able to split read only services from their write counterparts, or even have read and write service methods combined. But both of these do not use 2 datasources.
Code is from the Spring Reference
I am pretty sure that you need to address the problem on the database / connection url + properties layer.
I would google around for something like read write replication.
Related to your question with JPA and transaction. You are doomed when you are using multiple Datasources. Also XA datasources are not really a solution for that. The only thing they do for you is to ensure consistency over multi data source operations. XA Transaction do only span some sort of logical transaction over two transactions (one for each datasource). From the transaction isolation point of view (as long as your not using READ_UNCOMMITED) both datasources use their own transaction. This means the read data source would not see the changes made by the write transaction.

multiple session factory objects for single database in an hibernate based java application

My question is very simple. and when I search on StackOverFlow I get several answers. But really I was not satisfied with them.
Q. What we can create more than one sessionFactory in Hibernate.
Ans And Its true We can create.As in my app i am able to da same.
Q.Now question arise why we should not create more than one session factory in an app.??
and what are the merits and demerits of having more than one session factory.
Thanks Guys
Why only one sessionFactory object per database in Hibernate ?
Here we can explain what is SessionFactory..
• SessionFactory is an interface, which is available in “org.hibernate” package.
• Session factory is long live multithreaded object.
• Usually one session factory should be created for one database.
• When you have multiple databases in your application you should create multiple SessionFactory object.
• Assume the scenario that you are using one database called mysql in your application then following is the way to create the SessionFactory object :
Configuration cfg=new Configuration(); // Empty object will be created.
cfg=cfg.configure();
Here when you called configure() method It looks for hibernate-cfg.xml and for Hibernate mapping file filled with all the properties defined in the configuration documents and mapping documents.
SessionFactory sc=cfg.buildSessionFactory();
• SessionFactory object will be created once and will be used by multiple users for long time.
• Session Factory object is the factory for session objects.
If you are using two databases called mysql and oracle in your hibernate application then you need to
build 2 SessionFactory objects:
Configuration cfg=new Configuration();
Configuration cfg1=cfg.configure(“mysql.cfg.xml”);
SessionFactory sf1=cfg1.builed SessionFactory();
Configuration cfg2=cfg.configure(“oracle.cfg.xml”);
SessionFactory sf2=cfg2.builed SessionFactory();
When we are using more than one database in our application than we use the HibernateUtil class which is implemented based on singleton design pattern which insures that one and only one sessionFactory object will be created for entire application.Session factory objects are to be implemented using the singleton design pattern. Instances of SessionFactory are thread-safe and typically shared throughout an application. Because creation of a SessionFactory is an extremely expensive process which involves parsing hibernate configuration/mapping properties and creating database connection pool .Creating a database connection pool requires establishing database connections (i.e creating Connection objects) which has overhead due to the time taken to locate the DB server. So if you create a SessionFactory for every request , it implies that you are not using database connection pool to serve your request. So creating number of instances will make our application heavy weight. But the session objects are not thread safe. So in short it is - SessionFactory objects are one per application and Session objects are one per client.
It is always recommended that there is one session factory per database, per JVM. Having multiple instances of session factory can lead to performance problems as well as abnormal behavior of transactions.
When you have multiple database instances used in your application you will need multiple hibernet.cfg.xml file (if you use xml based configuration) , where in each hibernet.cfg.xml file you will have to mention separate tag which will consist the database configurations.
But it is really not recommend to have multiple instances of session factory unless have any stern business requirement or need, because it will degrade the application performance.

designing a hibernate dao

I am using following code
TestDAO {
Session session = null;
public TestDAO() {
this.session = HibernateUtil.getSessionFactory().getCurrentSession();
}
//...more code create,update ...
//each method starts a transcation using "tx= session.beginTransaction();"
}
1)Now should i commit the transcation using tx.commit for a fetch operation too or only for save/update operation??
2)Should i create a seperate instance of TestDAO every time i need?Or should i create a singleton class that returns a single instance of DAO everytme?Will this have a problem?
You don't need tx.commit() for fetch operation. That is only needed for any save, update or delete. Close the session after data fetching.
If your application connect to only one database then use of single DAO is better. Spring framework encourages this. You will find more details about this on the following link
Don't repeat the DAO!
Transactions should not be the responsibility of the DAO, those really need to be controlled at a higher level. A DAO should be something that does queries and updates without being aware of the bigger picture, calls to DAOs can be grouped within an object like a Spring service or EJB session bean which is responsible for deciding what needs to go together in a transaction. This makes your DAO code more reusable since it doesn't have to know as much about the context in which it's operating.
Look at how Spring does it (in the sample applications like petstore that come with Spring), or better, look at the King/Bauer Hibernate-JPA book, which has a chapter on creating DAOs.

Categories

Resources