您好,登錄后才能下訂單哦!
在數(shù)據(jù)庫層面大都采用讀寫分離技術(shù),就是一個Master數(shù)據(jù)庫,多個Slave數(shù)據(jù)庫。Master庫負責數(shù)據(jù)更新和實時數(shù)據(jù)查詢,Slave庫當然負責非實時數(shù)據(jù)查詢。因為在實際的應用中,數(shù)據(jù)庫都是讀多寫少(讀取數(shù)據(jù)的頻率高,更新數(shù)據(jù)的頻率相對較少),而讀取數(shù)據(jù)通常耗時比較長,占用數(shù)據(jù)庫服務器的CPU較多,從而影響用戶體驗。我們通常的做法就是把查詢從主庫中抽取出來,采用多個從庫,使用負載均衡,減輕每個從庫的查詢壓力。
廢話不多說,多數(shù)據(jù)源配置和主從數(shù)據(jù)配置原理一樣
1、首先配置 jdbc.properties 兩個數(shù)據(jù)庫 A 和 B
#============ 雙數(shù)據(jù)源 ======# #----------------------A servers--------------------------# A.driver=com.mysql.jdbc.Driver A.url=jdbc:mysql://localhost:3619/gps4?useUnicode=true&characterEncoding=utf8 A.username=gpsadmin A.password=1qaz&619 #----------------------B servers--------------------------# B.driver=com.mysql.jdbc.Driver B.url=jdbc:mysql://localhost:3619/gps6?useUnicode=true&characterEncoding=utf8 B.username=gpsadmin B.password=1qaz&619
2、配置 spring-mybatis.xml 文件【重要】
<!-- 引入配置文件 --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:resources/jdbc.properties" /> </bean> <!-- DBCP連接池 --> <!-- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> 初始化連接大小 <property name="initialSize" value="${initialSize}"></property> 連接池最大數(shù)量 <property name="maxActive" value="${maxActive}"></property> 連接池最大空閑 <property name="maxIdle" value="${maxIdle}"></property> 連接池最小空閑 <property name="minIdle" value="${minIdle}"></property> 獲取連接最大等待時間 <property name="maxWait" value="${maxWait}"></property> </``> --> <!-- 【重點】 A 數(shù)據(jù)源 --> <bean name="dataSourceA" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${A.driver}" /> <property name="url" value="${A.url}" /> <property name="username" value="${A.username}" /> <property name="password" value="${A.password}" /> </bean> <!-- 【重點】 B 數(shù)據(jù)源 --> <bean name="dataSourceB" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${B.driver}" /> <property name="url" value="${B.url}" /> <property name="username" value="${B.username}" /> <property name="password" value="${B.password}" /> </bean> <!--【重點】 雙數(shù)據(jù)源 配合 --> <bean id="dataSource" class="com.ifengSearch.common.database.DynamicDataSource"> <property name="defaultTargetDataSource" ref="dataSourceB"/> <property name="targetDataSources"> <map> <entry key="dataSourceA" value-ref="dataSourceA"/> <entry key="dataSourceB" value-ref="dataSourceB"/> </map> </property> </bean> <!-- 【重點】 加入 aop 自動掃描 DataSourceAspect 配置數(shù)據(jù)庫注解aop --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <bean id="manyDataSourceAspect" class="com.ifengSearch.common.database.DataSourceAspect" /> <aop:config> <!-- 掃描 注解的 數(shù)據(jù)源 --> <aop:aspect id="c" ref="manyDataSourceAspect"> <aop:pointcut id="tx" expression="execution(* com.ifengSearch.*.dao.*.*(..))"/> <aop:before pointcut-ref="tx" method="before"/> </aop:aspect> </aop:config> <!-- 配置數(shù)據(jù)連接 工廠 自動掃描mapping.xml文件 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!-- 自動掃描mapping.xml文件 --> <property name="mapperLocations" value="classpath:com/ifengSearch/*/mapping/*.xml"></property> </bean> <!-- DAO接口所在包名,Spring會自動查找其下的類 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.ifengSearch.*.dao" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> </bean> <!-- (事務管理)transaction manager, use JtaTransactionManager for global tx 事務 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>
3、編寫幾個java類動態(tài)調(diào)用數(shù)據(jù)源【重要】
a:自定義一個注解,負責動態(tài)調(diào)用數(shù)據(jù)源
package com.ifengSearch.common.database; import java.lang.annotation.*; /** * 設置 數(shù)據(jù)源 注解標簽的用法 寫上注解標簽, * 調(diào)用相應方法切換數(shù)據(jù)源咯(就跟你設置事務一樣) * 【也可以配置 主從數(shù)據(jù)庫】 * * @author flm * @2017年9月12日 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface DataSource { public static String dataSourceA = "dataSourceA"; // A數(shù)據(jù)源 public static String dataSourceB = "dataSourceB"; // B數(shù)據(jù)源 String value(); }
b、數(shù)據(jù)源的獲取 Object aop實現(xiàn) (反射)
package com.ifengSearch.common.database; import java.lang.reflect.Method; import org.apache.log4j.Logger; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.reflect.MethodSignature; /** * 數(shù)據(jù)源的獲取 * aop實現(xiàn) (反射) * @author flm * @2017年9月12日 */ public class DataSourceAspect{ private Logger log = Logger.getLogger(DataSourceAspect.class); public void before(JoinPoint point) { Object target = point.getTarget();// 攔截的實體類 String method = point.getSignature().getName();// 攔截的方法名稱 Class<?>[] classz = target.getClass().getInterfaces(); Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()) .getMethod().getParameterTypes();// 攔截的方法參數(shù)類型 try { Method m = classz[0].getMethod(method, parameterTypes); if (m != null && m.isAnnotationPresent(DataSource.class)) { DataSource data = m .getAnnotation(DataSource.class); DataSourceHolder.setDataSource(data.value()); log.info("數(shù)據(jù)源的獲取 DataSource: "+data.value()); } } catch (Exception e) { log.error("數(shù)據(jù)源的獲取 aop實現(xiàn) 出錯:"+e.getMessage()); } } }
c、DataSourceHolder 數(shù)據(jù)源操作 獲取數(shù)據(jù)源 幫助類
package com.ifengSearch.common.database; /** * 多數(shù)據(jù)源 * 數(shù)據(jù)源操作 獲取數(shù)據(jù)源 * @author flm * @2017年9月12日 */ public class DataSourceHolder { //線程本地環(huán)境 private static final ThreadLocal<String> dataSources = new ThreadLocal<String>(); //設置數(shù)據(jù)源 public static void setDataSource(String customerType) { dataSources.set(customerType); } //獲取數(shù)據(jù)源 public static String getDataSource() { return (String) dataSources.get(); } //清除數(shù)據(jù)源 public static void clearDataSource() { dataSources.remove(); } }
d、 我們還需要實現(xiàn)spring的抽象類AbstractRoutingDataSource,就是實現(xiàn)determineCurrentLookupKey方法:
package com.ifengSearch.common.database; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * 多數(shù)據(jù)源 * 獲取數(shù)據(jù)源(依賴于spring) * @author flm * @2017年9月12日 */ public class DynamicDataSource extends AbstractRoutingDataSource{ @Override protected Object determineCurrentLookupKey() { return DataSourceHolder.getDataSource(); } }
4、接下來就可以看結(jié)果了
我在dao層直接調(diào)用
public interface UserDao { /** * 登錄判斷 【數(shù)據(jù)源B】 */ @DataSource(value=DataSource.dataSourceB) public List<UserBean> getLoginUserList(@Param("loginName")String loginName,@Param("loginPwd")String loginPwd); /** * 查找上一級 服務商 【數(shù)據(jù)源A】 */ @DataSource(value=DataSource.dataSourceA) public UserBean getServerUser(@Param("u_last_id")Integer u_last_id); }
總結(jié)
以上所述是小編給大家介紹的Spring+Mybatis 實現(xiàn)aop數(shù)據(jù)庫讀寫分離與多數(shù)據(jù)庫源配置操作,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對億速云網(wǎng)站的支持!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。