如何在应用启动之后灵活切换数据源的关键点:
将SessionFactory接口中的dataSource配置为AbstractRoutingDataSource的instance,sessionFactory在获取datasource的时候会执行AbstractRoutingDataSource的determineCurrentLookupKey()方法,
所以用户要想定制自己切换数据源方式就要继承AbstractRoutingDataSource,然后实现determineCurrentLookupKey()方法。废话不多说,我们马上看例子:
1.简单映射类:User.java
1 package com.eg.model; 2 3 import javax.persistence.Column; 4 import javax.persistence.Entity; 5 import javax.persistence.Id; 6 import javax.persistence.Table; 7 8 @Entity 9 @Table(name = "user") 10 public class User implements Cloneable{ 11 private String user_id; 12 private String name; 13 private String age; 14 15 public User() { 16 } 17 18 @Id 19 @Column(name = "user_id", unique = true, nullable = false, length = 36) 20 public String getUser_id() { 21 return user_id; 22 } 23 24 public void setUser_id(String user_id) { 25 this.user_id = user_id; 26 } 27 28 @Column(name = "name", length = 20) 29 public String getName() { 30 return name; 31 } 32 33 public void setName(String name) { 34 this.name = name; 35 } 36 37 @Column(name = "age", length = 20) 38 public String getAge() { 39 return age; 40 } 41 42 public void setAge(String age) { 43 this.age = age; 44 } 45 46 }
2.DAO层: UserDao.java
1 package com.eg.dao; 2 3 import org.springframework.stereotype.Repository; 4 5 import com.eg.model.User; 6 7 @Repository 8 public class UsertDao extends BaseHibernateDao<User> { 9 10 }
3.Dao层基类: BaseHibernateDao.java
1 package com.eg.dao; 2 3 4 import org.apache.commons.logging.Log; 5 import org.apache.commons.logging.LogFactory; 6 import org.springframework.orm.hibernate3.support.HibernateDaoSupport; 7 8 import java.util.List; 9 10 public class BaseHibernateDao<T> extends HibernateDaoSupport 11 { 12 /** 13 * 操作的领域对象的类型 14 */ 15 protected Class<T> entityClass; 16 17 protected Log log = (Log) LogFactory.getLog(this.getClass()); 18 19 20 /** 21 * 执行HQL查询 22 */ 23 public List find(String hql) 24 { 25 return this.getHibernateTemplate().find(hql); 26 } 27 28 }
4.Service层: UserService.java
1 package com.eg.service; 2 3 import java.util.List; 4 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.stereotype.Service; 7 8 import com.eg.dao.UsertDao; 9 import com.eg.model.User; 10 11 @Service("userService") 12 public class UserService { 13 private UsertDao userDao; 14 @Autowired 15 public UserService(UsertDao dao) { 16 this.userDao = dao; 17 } 18 19 public List<User> findAll() { 20 return userDao.find("from Test"); 21 } 22 }
5.两个数据库的配置文件:jdbc.properties
#-----------------------------postgresql datasource1---------------------------------------------#
platform.driverClassName=org.postgresql.Driver
platform.url=jdbc:postgresql://localhost:5432/platform
platform.username=postgres
platform.password=root
platform.timeBetweenEvictionRunsMillis=3600000
platform.minEvictableIdleTimeMillis=21600000
#-----------------------------mysql datasource2--------------------------------------------------#
business.driverClassName=com.mysql.jdbc.Driver
business.url=jdbc:mysql://localhost:3306/platform
business.username=root
business.password= root
business.timeBetweenEvictionRunsMillis=3600000
business.minEvictableIdleTimeMillis=21600000
hiber.dialect=org.hibernate.dialect.MySQL5Dialect
6.容器bean注册文件: bean.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 5 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> 6 7 8 <context:component-scan base-package="com.eg.*"></context:component-scan> 9 10 <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 11 <property name="locations"> 12 <list> 13 <value>classpath:jdbc.properties</value> 14 </list> 15 </property> 16 </bean> 17 18 <bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 19 <property name="url" value="${platform.url}"/> 20 <property name="driverClassName" value="${platform.driverClassName}"/> 21 <property name="username" value="${platform.username}"/> 22 <property name="password" value="${platform.password}"/> 23 <property name="timeBetweenEvictionRunsMillis" value="${platform.timeBetweenEvictionRunsMillis}"></property> 24 <property name="minEvictableIdleTimeMillis" value="${platform.minEvictableIdleTimeMillis}"></property> 25 26 </bean> 27 <bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 28 <property name="url" value="${business.url}"/> 29 <property name="driverClassName" value="${business.driverClassName}"/> 30 <property name="username" value="${business.username}"/> 31 <property name="password" value="${business.password}"/> 32 <property name="timeBetweenEvictionRunsMillis" value="${business.timeBetweenEvictionRunsMillis}"></property> 33 <property name="minEvictableIdleTimeMillis" value="${business.minEvictableIdleTimeMillis}"></property> 34 </bean> 35 36 <bean id="dataSource" class="com.eg.dbsource.DynamicDataSource"> 37 <!-- 默认数据库 --> 38 <property name="defaultTargetDataSource" ref="dataSource1"/> 39 <property name="targetDataSources" > 40 <!-- 将多个数据源配在这里,我们将通过改变key值来控制切换 --> 41 <map key-type="java.lang.String"> 42 <entry key="db1" value-ref="dataSource1"/> 43 <entry key="db2" value-ref="dataSource2"/> 44 </map> 45 </property> 46 </bean> 47 48 <!-- Hibernate Session工厂 --> 49 <bean id="sessionFactory" 50 class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 51 <property name="dataSource" ref="dataSource"/> 52 <property name="packagesToScan"> 53 <list> 54 <value>com.eg.model</value>s 55 </list> 56 </property> 57 <property name="hibernateProperties"> 58 <props> 59 <prop key="hibernate.dialect"> 60 ${hiber.dialect} 61 <!--org.hibernate.dialect.Oracle10gDialect--> 62 </prop> 63 <prop key="hibernate.show_sql">true</prop> 64 <prop key="hibernate.jdbc.batch_size">50</prop> 65 <prop key="hibernate.cache.use_query_cache">false</prop> 66 </props> 67 </property> 68 </bean> 69 70 <!-- Hibernate 模板 --> 71 <bean id="hibernateTemplate" 72 class="org.springframework.orm.hibernate3.HibernateTemplate"> 73 <property name="sessionFactory" ref="sessionFactory"/> 74 </bean> 75 76 </beans>
7.继承AbstractRoutingDataSource,并实现其determineCurrentLookupKey方法:DynamicDataSource.java
1 package com.eg.dbsource; 2 3 4 import java.sql.SQLFeatureNotSupportedException; 5 import java.util.logging.Logger; 6 7 import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; 8 9 public class DynamicDataSource extends AbstractRoutingDataSource 10 { 11 protected Object determineCurrentLookupKey() { 12 String type = CustomerContextHolder.getCustomerType(); 13 return type; 14 } 15 16 public Logger getParentLogger() throws SQLFeatureNotSupportedException { 17 return null; 18 } 19 20 }
8. 数据源控制器:CustomerContextHolder.java
1 package com.eg.dbsource; 2 3 public class CustomerContextHolder 4 { 5 private static final ThreadLocal contextHolder = new ThreadLocal(); 6 7 public static void setCustomerType(String customerType) 8 { 9 contextHolder.set(customerType); 10 } 11 12 public static String getCustomerType() 13 { 14 return (String) contextHolder.get(); 15 } 16 17 public static void clearCustomerType() 18 { 19 contextHolder.remove(); 20 } 21 }
9.来测试一下吧:ContextSimulation.java
1 package com.eg.spring.simulation; 2 3 import java.util.List; 4 5 import org.springframework.context.ApplicationContext; 6 import org.springframework.context.support.ClassPathXmlApplicationContext; 7 8 import com.eg.dbsource.CustomerContextHolder; 9 import com.eg.model.User; 10 import com.eg.service.UserService; 11 12 public class ContextSimulation { 13 public static void main(String[] args) { 14 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); 15 UserService testService = (UserService)context.getBean("testService"); 16 17 CustomerContextHolder.setCustomerType("db1"); 18 List<User> l = testService.findAll(); 19 20 CustomerContextHolder.setCustomerType("db2"); 21 l = testService.findAll(); 22 System.out.println(l.size() +" "+ l.get(0).getName() + " " + l.get(0).getAge()); 23 } 24 }