Configure multiple data sources

Source: Internet
Author: User
In our project, we encountered the following problem: our project needs to connect multiple databases, and different customers access different databases as needed during each access. We used to configure a data source in spring and hibernate frameworks, so the datasource attribute of sessionfactory always points to this data source.
And remains unchanged. All Dao accesses the database through this data source when using sessionfactory. But now, due to the needs of the project, our Dao is accessing
Sessionfactory has to switch between multiple data sources, and the problem arises: how to make sessionfactory perform data persistence according to the customer's
Can I dynamically switch different data sources? Can we solve this problem through a few modifications in the Spring framework? Is there any design pattern that can be used? I first thought about configuring all datasource in spring applicationcontext. These datasource may be of different types,
For example, different databases, such as Oracle, SQL Server, and MySQL, may also be different data sources: for example
Org. Apache. commons. DBCP. basicdatasource, org. springframework. JNDI. jndiobjectfactorybean provided by spring, etc.
Sessionfactory then sets the datasource attribute to different data sources based on each request of the customer to achieve the purpose of switching the data source. However, I soon found a problem: Resource contention occurs when multiple users access the database concurrently. This is a fault caused by the singleton mode. As we all know,
When we use the Spring framework, the beans registered in beanfactory basically use the singleton mode, that is, when spring is started,
These beans are loaded into the memory, and each bean has only one object throughout the project. Because only one object exists, all attributes of the object,
More accurately, instance variables act like static variables (in fact, "static" and "Singleton" are often very similar,
We often use "static" to implement "Singleton "). To solve this problem, sessionfactory has only one object in the entire project,
Its instance variable datasource has only one, just like a static variable. If different users constantly modify the datasource value,
It is inevitable that multiple users will compete for a variable, posing a risk to the system.
Through the above analysis, the key to solving the problem of multi-data source access is concentrated in sessionfactory, when executing data persistence, it can go through a piece of code
Dynamically switch data sources based on customer needs and solve resource contention issues. Solution to the Problem (1) I used the decorator design mode to solve this problem. My idea is locked on this datasource. If sessionfactory points to the datasource, you can connect to the customer according to the customer's needs.
The real data source is the function of dynamically switching the data source. So what should we do? Modify the datasource
Source code? This is obviously not a good solution. We hope that our modifications will be separated from the original datasource code. Based on the above analysis,
Using the decorator mode in the gof design mode should be the best solution we can choose. What is the "decorator mode "?
To put it simply, when we need to modify the original functions, but we do not want to directly modify the original code, design a decorator to be embedded outside the original code.
When we use decorator, it is exactly the same as the original class. Some functions of decorator have been modified to the functions we need to modify. The structure of the decorator mode. We originally needed to modify some functions of all the specific component classes in the diagram, but instead of directly modifying their code, we added a decorator to them.
Both the decorator and the specific component class inherit abstractcomponent, so it looks the same as the specific component class,
That is to say, when we use decorator, it is like using concretecomponenta or concretecomponentb,
Even customer programs that use concretecomponenta or concretecomponentb do not know that their classes have been changed to decorator,
However, the decorator has modified some methods of the specific component class, And the execution results of these methods are different.
(2) The design of the multidatasource class now returns to our problem. We need to change the datasource function, but do not want to modify any code in the datasource.
Datasource is all classes that implement the javax. SQL. datasource interface.
Org. Apache. commons. DBCP. basicdatasource, org. springframework. JNDI. jndiobjectfactorybean provided by spring, etc,
These classes cannot be modified, but cannot be modified one by one to dynamically allocate data sources. At the same time,
We also hope that the sessionfactory of datasource will not feel this change at all. The decorator mode is the design mode to solve this problem. First, write a decorator class named multidatasource to dynamically switch the data source. In the configuration file
The datasource attribute is changed from a specific datasource to multidatasource. Compared with the original decorator mode, abstractcomponent is an abstract class, but here we can replace this abstract class with an interface,
That is, the datasource interface, and concretecomponent is the implementation classes of datasource, such as basicdatasource and jndiobjectfactorybean.
Multidatasource encapsulates the specific datasource and implements Dynamic Data Source switching:
Public class multidatasource implements datasource {private datasource = NULL; Public multidatasource (datasource) {This. datasource = datasource;}/* (non-javadoc) * @ see javax. SQL. datasource # getconnection () */public connection getconnection () throws sqlexception {return getdatasource (). getconnection ();} // The method that other datasource interfaces should implement public datasource getdatasource () {return this. datasource;} public void setdatasource (datasource) {This. datasource = datasource ;}}
When sending a request, the customer puts the CENAME in the request, and then calls the data source name in the request
When new multidatasource (datasource) is used, the customer can be notified of the data source required by multidatasource, so that the data source can be dynamically switched.
But careful friends will find this is a problem in the case of Singleton, because multidatasource has only one object in the system, and its instance variable datasource
There is only one static variable. Because of this, the singleton mode makes many design patterns have to be changed,
This will be discussed in detail in my Singleton change our design patterns. So how can we design it in the singleton mode?
(3) multidatasource in singleton Mode
In Singleton mode, datasource may be different every time we call the multidatasource method,
Therefore, we cannot place datasource In the instance variable datasource. The simplest way is to add a parameter to the getdatasource () method,
Tell the multidatasource which datasource I actually call:
Java code
   1. public DataSource getDataSource(String dataSourceName){   
   2.         log.debug("dataSourceName:"+dataSourceName);  
   3.         try{  
   4.             if(dataSourceName==null||dataSourceName.equals("")){  
   5.                 return this.dataSource;  
   6.             }  
   7.             return (DataSource)this.applicationContext.getBean(dataSourceName);  
   8.         }catch(NoSuchBeanDefinitionException ex){  
   9.             throw new DaoException("There is not the dataSource
  10.         }  
  11.     }  
It is worth mentioning that all the data sources I need have been registered in the spring configuration file, and the datasourcename is its corresponding ID.
XML Code
   1. <bean id="dataSource1"  
   2.     class="org.apache.commons.dbcp.BasicDataSource"> 
   3.     <property name="driverClassName"> 
   4.         <value>oracle.jdbc.driver.OracleDrivervalue> 
   5.     property>
   6.     ......  
   7. bean> 
   8. <bean id="dataSource2" 
   9.     class="org.apache.commons.dbcp.BasicDataSource"> 
  10.     <property name="driverClassName"> 
  11.         <value>oracle.jdbc.driver.OracleDrivervalue>
  12.     property>  
  13.     ......  
  14. bean>  
To obtain spring applicationcontext, The multidatasource class
The Org. springframework. Context. applicationcontextaware interface must be implemented and the implementation method is as follows:
Java code
   1. private ApplicationContext applicationContext = null;   
   2. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  
   3.         this.applicationContext = applicationContext;  
   4.     }  
In this way, we can get the datasource through this. applicationcontext. getbean (datasourcename.
(4) passing CENAME through a thread
Looking at the above design, the multidatasource still cannot run, because when a user sends a request, what database does he need to connect to, and the data source name is placed in the request,
To pass the data source name in the request to multidatasource, it must pass through bus and Dao, that is, to pass the data source name to multidatasource,
The CENAME parameter must be added to all methods of bus and Dao, which we do not want to see.
It is a good design to write a class and skip bus and Dao and pass it directly to multidatasource through a thread:
Java code
   1. public class SpObserver {   
   2.     private static ThreadLocal local = new ThreadLocal();  
   3.     public static void putSp(String sp) {  
   4.         local.set(sp);  
   5.     }  
   6.     public static String getSp() {  
   7.         return (String)local.get();  
   8.     }  
   9. }  
Make a filter and call spobserver. petsp (datasourcename) every time the customer sends a request ),
Pass the CENAME in the request to the spobserver object. Finally, modify the multidatasource method getdatasource ():
Java code
   1. public DataSource getDataSource(){   
   2.         String sp = SpObserver.getSp();  
   3.         return getDataSource(sp);  
   4.     }  
The complete multidatasource code is included in the attachment.
(5) dynamically add data sources
The above solution solves the problem of dynamic data source allocation, but you may ask: The data sources in the solution are all configured in spring applicationcontext,
What if I dynamically Add a data source while the program is running? This is indeed a problem, and we have encountered it in our project.
Spring applicationcontext is loaded when the project is started. After loading, how can we dynamically load new beans into applicationcontext?
I thought it would be nice to solve this problem using spring's own method. Fortunately, after checking the source code of spring, I found this code,
After compiling the dynamicloadbean class, you can call the loadbean () method to load the beans in one or more configuration files to applicationcontext.
. Objects are directly loaded without using the configuration file. They are also available in spring source code. Interested friends can study them on their own.
(6) Configure in spring
After completing all these designs, I will end up with another question. We should make the following configuration in Spring:
XML Code
   1. <bean id="dynamicLoadBean" class="com.htxx.service.dao.DynamicLoadBean">bean>  
   2. <bean id="dataSource" class="com.htxx.service.dao.MultiDataSource"> 
   3.         <property name="dataSource"> 
   4.             <ref bean="dataSource1" /> 
   5.         property> 
   6.     bean> 
   7.     <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
   8.         <property name="dataSource"> 
   9.             <ref bean="dataSource" /> 
  10.         property> 
  11.         ......  
  12.     bean> 
The datasource attribute should actually be defaultdatasource, that is, when spring is started and when the customer does not specify a data source
The specified default data source.
What are the advantages of this solution compared with other solutions?
First, this solution is completely implemented under the Spring framework, and the data source is still configured in the spring configuration file,
Sessionfactory still configures its datasource attribute, and it does not even know the datasource change.
The only difference is that a multidatasource is added between the real datasource and sessionfactory.
Secondly, the implementation is simple and easy to maintain. Although I have said so many things, this solution is actually an analysis,
The code we need to write is only multidatasource and spobserver.
The multidatasource class only needs to write the getdatasource () and getdatasource (SP) methods,
The spobserver class is simpler. The simpler the implementation, the smaller the possibility of errors, and the higher the maintainability.
Finally, this solution can make a single data source compatible with multiple data sources. This solution does not affect the writing of bus and Dao at all.
If our project is developed with a single data source at the beginning, as the project progresses, it needs to be changed to multiple data sources,
You only need to modify the spring configuration and modify the MVC layer to write the required data source name in the request. The change is complete.
If your project wants to change the data source, you only need to modify the configuration file. In this way, more flexibility will be added for our projects.
Note: An error occurs when the dynamicloadbean In the instance runs in the Web environment. You need to change the abstractapplicationcontext in the class
 org.springframework.context.ConfigurableApplicationContext。 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.