多数据源顾名思义,一个项目用了两个或者两个以上的数据库。那为啥要配置多数据源呢?
在这里我因为是工作中项目需求,需求是将项目中一个大的功能模块的数据独立出来形成一个单独的数据库,因为这个功能模块的数据量贼大贼重要不便于管理且是领导提的要求,于是乎就着手配置了。
首先对于一个已经开发完成的企业级项目,对其中某个模块进行数据独立,无疑是新建个数据库进行单独存储,那么在SSH框架下必然就要配置两个数据源,这猛的一想,不就是配置两个数据源嘛,那还不简单,于是乎就在applicationContext.xml文件中又新加了一个数据库的dataSource。配置完成后仔细一想,那我岂不是要在每个执行数据库语句的函数中都要进行手动切换数据源吗?这种方法对于一个开发完成的拥有成百上千个sql语句执行函数的企业级项目来说无疑是个庞大工作量。所以这种方法直接就Out了。
显然,这种时候要从根源上解决问题。
我们先来定义两个模块:
模块一:是除了要独立的模块(数据存储在数据库1中)
模块二:是要独立的模块(数据存储在数据库2中)
我们需要有个默认的数据源(dateSource1)、一个sessionFactory1、一个ehcache1,我们需要规定在我们没有手动调用的情况下,所有的方法都是使用默认的数据源(dateSource1)、一个sessionFactory1、一个ehcache1去执行sql语句,即模块一只使用默认的数据源(dateSource1)、一个sessionFactory1、一个ehcache1。而模块二内的DaoImpl层我们进行注入sessionFactory2来进行切换数据源。这个时候我们只需在模块二内的所有DaoImpl层的类中加上一个sessionFactory2的注入语句即可。(前提条件:这个类需要继承HibernateDaoSupport类或HibernateDaoSupport继承类的类)
注入语句如下:
@Autowired
@Override
public void autowiredSetSessionFactory(@Qualifier("sessionFactorycm") SessionFactory sessionFactory) {
setSessionFactory(sessionFactory);
}
那么可想而知,我们需要配置的东西有:dateSource1、sessionFactory1、ehcache1 和dateSource2、sessionFactory2、ehcache2。
配置如下:
我的jdbc.properties
JDBC_URL2=jdbc\:mysql\://localhost\:3306/数据库2?useUnicode\=true&characterEncoding\=GBK
JDBC_URL=jdbc\:mysql\://localhost\:3306/数据库1?useUnicode\=true&characterEncoding\=GBK
JDBC_USER=root
JDBC_PASSWORD=root
配置两个ehcache
ehcache-shiro.xml(默认使用的ehcache)
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" name="shiroCache">
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
/>
</ehcache>
ehcache2.xml(需要手动配置到sessionFactory中的ehcache,这里将它配给了sessionFactory1具体看applicationContext.xml中的sessionFactory1的
<prop key="hibernate.cache.provider_configuration_file_resource_path">ehcache2.xml</prop>
)
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" name="shiroCache">
<cache name="GYCSCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"/>
</ehcache>
在这里要注意,既然一个项目配置了两个sessionFactory那么就必须要配置两个ehcache不然会出错。
配置applicationContext.xml
<!--数据源1-->
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${JDBC_DRIVER_CLASS}" />
<property name="jdbcUrl" value="${JDBC_URL}" />
<property name="user" value="${JDBC_USER}" />
<property name="password" value="${JDBC_PASSWORD}" />
<property name="maxPoolSize" value="5" />
<property name="minPoolSize" value="1" />
<property name="initialPoolSize" value="2" />
<property name="maxIdleTime" value="30" />
<property name="acquireIncrement" value="1" />
<property name="maxStatements" value="100" />
<property name="numHelperThreads" value="10" />
</bean>
<!--session工厂1-->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<!-- 配置Hibernate拦截器,自动填充数据的插入、更新时间 -->
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.jdbc.batch_size">20</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<prop key="hibernate.connection.provider_class">
org.hibernate.connection.C3P0ConnectionProvider
</prop>
<prop key="hibernate.connection.autocommit">true</prop>
<prop key="hibernate.connection.useUnicode">true</prop>
<prop key="hibernate.connection.characterEncoding">
UTF-8
</prop>
<prop key="hibernate.query.factory_class">
org.hibernate.hql.ast.ASTQueryTranslatorFactory
</prop>
<!-- 如果想使用 getcurrentSession() 方法,需要以下参数-->
<prop key="hibernate.current_session_context_class">
thread
</prop>
<prop key="hibernate.transaction.factory_class">
org.hibernate.transaction.JDBCTransactionFactory
</prop>
<prop key="hibernate.dialect">
${hibernate.dialect}
</prop>
<prop key="hibernate.show_sql">
${hibernate.show_sql}
</prop>
<prop key="hibernate.cache.use_query_cache">
${hibernate.cache.use_query_cache}
</prop>
<prop key="hibernate.cache.provider_class">
${hibernate.cache.provider_class}
</prop>
<prop key="hibernate.cache.provider_configuration_file_resource_path">ehcache2.xml</prop>
<prop key="hibernate.hbm2ddl.auto">
${hibernate.hbm2ddl.auto}
</prop>
<prop key="javax.persistence.validation.group.prepersist">javax.validation.groups.Default</prop>
<prop key="javax.persistence.validation.group.preupdate">javax.validation.groups.Default</prop>
<prop key="javax.persistence.validation.group.pre-remove"></prop>
</props>
</property>
<!-- hibernate validation -->
<property name="eventListeners">
<map>
<entry key="pre-update">
<bean class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener"/>
</entry>
<entry key="pre-insert">
<bean class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener"/>
</entry>
<entry key="pre-delete">
<bean class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener"/>
</entry>
</map>
</property>
<property name="packagesToScan" value="com.**.entity" />
</bean>
<!--数据源2-->
<bean id="dataSourcecm" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="driverClass" value="${JDBC_DRIVER_CLASS}" />
<property name="jdbcUrl" value="${JDBC_URL2}" />
<property name="user" value="${JDBC_USER}" />
<property name="password" value="${JDBC_PASSWORD}" />
<property name="maxPoolSize" value="5" />
<property name="minPoolSize" value="1" />
<property name="initialPoolSize" value="2" />
<property name="maxIdleTime" value="30" />
<property name="acquireIncrement" value="1" />
<property name="maxStatements" value="100" />
<property name="numHelperThreads" value="10" />
</bean>
<!--session工厂2-->
<bean id="sessionFactorycm"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<!-- 配置Hibernate拦截器,自动填充数据的插入、更新时间 -->
<property name="dataSource" ref="dataSourcecm" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.jdbc.batch_size">20</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<prop key="hibernate.connection.provider_class">
org.hibernate.connection.C3P0ConnectionProvider
</prop>
<prop key="hibernate.connection.autocommit">true</prop>
<prop key="hibernate.connection.useUnicode">true</prop>
<prop key="hibernate.connection.characterEncoding">
UTF-8
</prop>
<prop key="hibernate.query.factory_class">
org.hibernate.hql.ast.ASTQueryTranslatorFactory
</prop>
<!-- 如果想使用 getcurrentSession() 方法,需要以下参数-->
<prop key="hibernate.current_session_context_class">
thread
</prop>
<prop key="hibernate.transaction.factory_class">
org.hibernate.transaction.JDBCTransactionFactory
</prop>
<prop key="hibernate.dialect">
${hibernate.dialect}
</prop>
<prop key="hibernate.show_sql">
${hibernate.show_sql}
</prop>
<prop key="hibernate.cache.use_query_cache">
${hibernate.cache.use_query_cache}
</prop>
<prop key="hibernate.cache.provider_class">
${hibernate.cache.provider_class}
</prop>
<prop key="hibernate.hbm2ddl.auto">
${hibernate.hbm2ddl.auto}
</prop>
<prop key="javax.persistence.validation.group.prepersist">javax.validation.groups.Default</prop>
<prop key="javax.persistence.validation.group.preupdate">javax.validation.groups.Default</prop>
<prop key="javax.persistence.validation.group.pre-remove"></prop>
</props>
</property>
<!-- hibernate validation -->
<property name="eventListeners">
<map>
<entry key="pre-update">
<bean class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener"/>
</entry>
<entry key="pre-insert">
<bean class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener"/>
</entry>
<entry key="pre-delete">
<bean class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener"/>
</entry>
</map>
</property>
<property name="packagesToScan" value="com.**.entity" />
</bean>
<!--事务管理器2-->
<bean id="transactionManagercm" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactorycm"/>
</bean>
<!-- 配置事务通知属性 -->
<tx:advice id="transactionAdvicecm" transaction-manager="transactionManagercm">
<!-- 定义事务传播属性 -->
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="set*" propagation="REQUIRED"/>
<tx:method name="execute*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="search*" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切面 -->
<aop:config>
<aop:advisor pointcut="execution(* com.nuigl.gycs.*.*(..))" advice-ref="transactionAdvicecm"/>
</aop:config>
<!-- 数据源2配置 end -->
最后就是在模块二的dao层的每一个实现类中注入要切换的独立数据库
@Autowired
@Override
public void autowiredSetSessionFactory(@Qualifier("sessionFactorycm") SessionFactory sessionFactory) {
setSessionFactory(sessionFactory);
}
在这里再次强调一下,模块一、模块二的dao层的每一个实现类中一定要继承HibernateDaoSupport类或HibernateDaoSupport继承类的类,因为要设置SessionFactory所以要继承!!!
这就是我分库的整个过程思路和实现方法了,觉得有用的小伙伴们就点个赞吧!!!