天天看點

基于Spring+SpringMvc+Hibernate的多資料源配置分庫

多資料源顧名思義,一個項目用了兩個或者兩個以上的資料庫。那為啥要配置多資料源呢?

在這裡我因為是工作中項目需求,需求是将項目中一個大的功能子產品的資料獨立出來形成一個單獨的資料庫,因為這個功能子產品的資料量賊大賊重要不便于管理且是上司提的要求,于是乎就着手配置了。

首先對于一個已經開發完成的企業級項目,對其中某個子產品進行資料獨立,無疑是建立個資料庫進行單獨存儲,那麼在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是以要繼承!!!

這就是我分庫的整個過程思路和實作方法了,覺得有用的小夥伴們就點個贊吧!!!