最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Spring AOP實現(xiàn)MySQL數(shù)據(jù)庫讀寫分離案例分析(附demo)

 更新時間:2017年01月01日 10:45:31   作者:徐劉根  
分布式環(huán)境下數(shù)據(jù)庫的讀寫分離策略是解決數(shù)據(jù)庫讀寫性能瓶頸的一個關(guān)鍵解決方案,這篇文章主要介紹了使用Spring AOP實現(xiàn)MySQL數(shù)據(jù)庫讀寫分離案例分析(附demo),有興趣的可以了解一下。

 一、前言

分布式環(huán)境下數(shù)據(jù)庫的讀寫分離策略是解決數(shù)據(jù)庫讀寫性能瓶頸的一個關(guān)鍵解決方案,更是最大限度了提高了應(yīng)用中讀取 (Read)數(shù)據(jù)的速度和并發(fā)量。

在進(jìn)行數(shù)據(jù)庫讀寫分離的時候,我們首先要進(jìn)行數(shù)據(jù)庫的主從配置,最簡單的是一臺Master和一臺Slave(大型網(wǎng)站系統(tǒng)的話,當(dāng)然會很復(fù)雜,這里只是分析了最簡單的情況)。通過主從配置主從數(shù)據(jù)庫保持了相同的數(shù)據(jù),我們在進(jìn)行讀操作的時候訪問從數(shù)據(jù)庫Slave,在進(jìn)行寫操作的時候訪問主數(shù)據(jù)庫Master。這樣的話就減輕了一臺服務(wù)器的壓力。

在進(jìn)行讀寫分離案例分析的時候。首先,配置數(shù)據(jù)庫的主從復(fù)制,MySQL5.6 數(shù)據(jù)庫主從(Master/Slave)同步安裝與配置詳解

當(dāng)然,只是簡單的為了看一下如何用代碼的方式實現(xiàn)數(shù)據(jù)庫的讀寫分離,完全不必要去配置主從數(shù)據(jù)庫,只需要兩臺安裝了 相同數(shù)據(jù)庫的機(jī)器就可以了。

二、實現(xiàn)讀寫分離的兩種方法

具體到開發(fā)中,實現(xiàn)讀寫分離常用的有兩種方式:

1、第一種方式是我們最常用的方式,就是定義2個數(shù)據(jù)庫連接,一個是MasterDataSource,另一個是SlaveDataSource。更新數(shù)據(jù)時我們讀取MasterDataSource,查詢數(shù)據(jù)時我們讀取SlaveDataSource。這種方式很簡單,我就不贅述了。

2、第二種方式動態(tài)數(shù)據(jù)源切換,就是在程序運行時,把數(shù)據(jù)源動態(tài)織入到程序中,從而選擇讀取主庫還是從庫。主要使用的技術(shù)是:Annotation,spring AOP ,反射。

下面會詳細(xì)的介紹實現(xiàn)方式。

三、Aop實現(xiàn)主從數(shù)據(jù)庫的讀寫分離案例

1、項目代碼地址

目前該Demo的項目地址:demo

2、項目結(jié)構(gòu)

上圖中,除了標(biāo)記的代碼,其他的主要是配置代碼和業(yè)務(wù)代碼。

3、具體分析

該項目是SSM框架的一個demo,Spring、Spring MVC和MyBatis,具體的配置文件不在過多介紹。

(1)UserContoller模擬讀寫數(shù)據(jù)

/**
 * Created by xuliugen on 2016/5/4.
 */
@Controller
@RequestMapping(value = "/user", produces = {"application/json;charset=UTF-8"})
public class UserController {

 @Inject
 private IUserService userService;

 //http://localhost:8080/user/select.do
 @ResponseBody
 @RequestMapping(value = "/select.do", method = RequestMethod.GET)
 public String select() {
  User user = userService.selectUserById(123);
  return user.toString();
 }

 //http://localhost:8080/user/add.do
 @ResponseBody
 @RequestMapping(value = "/add.do", method = RequestMethod.GET)
 public String add() {
  boolean isOk = userService.addUser(new User("333", "444"));
  return isOk == true ? "shibai" : "chenggong";
 }
}

模擬讀寫數(shù)據(jù),調(diào)用IUserService 。

(2)spring-db.xml讀寫數(shù)據(jù)源配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

 <bean id="statFilter" class="com.alibaba.druid.filter.stat.StatFilter" lazy-init="true">
  <property name="logSlowSql" value="true"/>
  <property name="mergeSql" value="true"/>
 </bean>

 <!-- 數(shù)據(jù)庫連接 -->
 <bean id="readDataSource" class="com.alibaba.druid.pool.DruidDataSource"
   destroy-method="close" init-method="init" lazy-init="true">
  <property name="driverClassName" value="${driver}"/>
  <property name="url" value="${url1}"/>
  <property name="username" value="root"/>
  <property name="password" value="${password}"/>
   <!-- 省略部分內(nèi)容 -->
 </bean>

 <bean id="writeDataSource" class="com.alibaba.druid.pool.DruidDataSource"
   destroy-method="close" init-method="init" lazy-init="true">
  <property name="driverClassName" value="${driver}"/>
  <property name="url" value="${url}"/>
  <property name="username" value="root"/>
  <property name="password" value="${password}"/>
  <!-- 省略部分內(nèi)容 -->
 </bean>

 <!-- 配置動態(tài)分配的讀寫 數(shù)據(jù)源 -->
 <bean id="dataSource" class="com.xuliugen.choosedb.demo.aspect.ChooseDataSource" lazy-init="true">
  <property name="targetDataSources">
   <map key-type="java.lang.String" value-type="javax.sql.DataSource">
    <!-- write -->
    <entry key="write" value-ref="writeDataSource"/>
    <!-- read -->
    <entry key="read" value-ref="readDataSource"/>
   </map>
  </property>
  <property name="defaultTargetDataSource" ref="writeDataSource"/>
  <property name="methodType">
   <map key-type="java.lang.String">
    <!-- read -->
    <entry key="read" value=",get,select,count,list,query"/>
    <!-- write -->
    <entry key="write" value=",add,create,update,delete,remove,"/>
   </map>
  </property>
 </bean>

</beans>

上述配置中,配置了readDataSource和writeDataSource兩個數(shù)據(jù)源,但是交給SqlSessionFactoryBean進(jìn)行管理的只有dataSource,其中使用到了:com.xuliugen.choosedb.demo.aspect.ChooseDataSource 這個是進(jìn)行數(shù)據(jù)庫選擇的。

<property name="methodType">
 <map key-type="java.lang.String">
  <!-- read -->
  <entry key="read" value=",get,select,count,list,query"/>
  <!-- write -->
  <entry key="write" value=",add,create,update,delete,remove,"/>
  </map>
</property>

配置了數(shù)據(jù)庫具體的那些是讀哪些是寫的前綴關(guān)鍵字。ChooseDataSource的具體代碼如下:

(3)ChooseDataSource

/**
 * 獲取數(shù)據(jù)源,用于動態(tài)切換數(shù)據(jù)源
 */
public class ChooseDataSource extends AbstractRoutingDataSource {

 public static Map<String, List<String>> METHOD_TYPE_MAP = new HashMap<String, List<String>>();

 /**
  * 實現(xiàn)父類中的抽象方法,獲取數(shù)據(jù)源名稱
  * @return
  */
 protected Object determineCurrentLookupKey() {
  return DataSourceHandler.getDataSource();
 }

 // 設(shè)置方法名前綴對應(yīng)的數(shù)據(jù)源
 public void setMethodType(Map<String, String> map) {
  for (String key : map.keySet()) {
   List<String> v = new ArrayList<String>();
   String[] types = map.get(key).split(",");
   for (String type : types) {
    if (StringUtils.isNotBlank(type)) {
     v.add(type);
    }
   }
   METHOD_TYPE_MAP.put(key, v);
  }
 }
}

(4)DataSourceAspect進(jìn)行具體方法的AOP攔截

/**
 * 切換數(shù)據(jù)源(不同方法調(diào)用不同數(shù)據(jù)源)
 */
@Aspect
@Component
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class DataSourceAspect {

 protected Logger logger = LoggerFactory.getLogger(this.getClass());

 @Pointcut("execution(* com.xuliugen.choosedb.demo.mybatis.dao.*.*(..))")
 public void aspect() {
 }

 /**
  * 配置前置通知,使用在方法aspect()上注冊的切入點
  */
 @Before("aspect()")
 public void before(JoinPoint point) {
  String className = point.getTarget().getClass().getName();
  String method = point.getSignature().getName();
  logger.info(className + "." + method + "(" + StringUtils.join(point.getArgs(), ",") + ")");
  try {
   for (String key : ChooseDataSource.METHOD_TYPE_MAP.keySet()) {
    for (String type : ChooseDataSource.METHOD_TYPE_MAP.get(key)) {
     if (method.startsWith(type)) {
      DataSourceHandler.putDataSource(key);
     }
    }
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

(5)DataSourceHandler,數(shù)據(jù)源的Handler類

package com.xuliugen.choosedb.demo.aspect;

/**
 * 數(shù)據(jù)源的Handler類
 */
public class DataSourceHandler {

 // 數(shù)據(jù)源名稱線程池
 public static final ThreadLocal<String> holder = new ThreadLocal<String>();

 /**
  * 在項目啟動的時候?qū)⑴渲玫淖x、寫數(shù)據(jù)源加到holder中
  */
 public static void putDataSource(String datasource) {
  holder.set(datasource);
 }

 /**
  * 從holer中獲取數(shù)據(jù)源字符串
  */
 public static String getDataSource() {
  return holder.get();
 }
}

主要代碼,如上所述。

本文代碼:demo

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • MyBatis利用攔截器實現(xiàn)數(shù)據(jù)脫敏詳解

    MyBatis利用攔截器實現(xiàn)數(shù)據(jù)脫敏詳解

    現(xiàn)代網(wǎng)絡(luò)環(huán)境中,敏感數(shù)據(jù)的處理是至關(guān)重要的,敏感數(shù)據(jù)包括個人身份信息、銀行賬號、手機(jī)號碼等,所以本文主要為大家詳細(xì)介紹了MyBatis如何利用攔截器實現(xiàn)數(shù)據(jù)脫敏,希望對大家有所幫助
    2023-11-11
  • Java WebService 簡單實例(附實例代碼)

    Java WebService 簡單實例(附實例代碼)

    本篇文章主要介紹了Java WebService 簡單實例(附實例代碼), Web Service 是一種新的web應(yīng)用程序分支,他們是自包含、自描述、模塊化的應(yīng)用,可以發(fā)布、定位、通過web調(diào)用。有興趣的可以了解一下
    2017-01-01
  • Spring?Boot?+?Spring?Batch?實現(xiàn)批處理任務(wù)的詳細(xì)教程

    Spring?Boot?+?Spring?Batch?實現(xiàn)批處理任務(wù)的詳細(xì)教程

    這篇文章主要介紹了Spring?Boot+Spring?Batch實現(xiàn)批處理任務(wù),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • Spring Boot使用JSR-380進(jìn)行校驗的示例

    Spring Boot使用JSR-380進(jìn)行校驗的示例

    這篇文章主要介紹了Spring Boot使用JSR-380進(jìn)行校驗,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • Java Netty HTTP服務(wù)實現(xiàn)過程解析

    Java Netty HTTP服務(wù)實現(xiàn)過程解析

    這篇文章主要介紹了Java Netty HTTP服務(wù)實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-08-08
  • SpringBoot參數(shù)驗證10個技巧值得收藏

    SpringBoot參數(shù)驗證10個技巧值得收藏

    Spring Boot提供了內(nèi)置的驗證注解,可以幫助簡單、快速地對輸入字段進(jìn)行驗證,例如檢查 null 或空字段、強制執(zhí)行長度限制、使用正則表達(dá)式驗證模式以及驗證電子郵件地址,那么在Spring Boot應(yīng)用中如何做好參數(shù)校驗工作呢,本文提供了10個小技巧感興趣的朋友一起看看吧
    2023-08-08
  • Java基礎(chǔ)之多線程的三種實現(xiàn)方式

    Java基礎(chǔ)之多線程的三種實現(xiàn)方式

    這篇文章主要介紹了Java基礎(chǔ)之多線程的三種實現(xiàn)方式,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • SpringBoot+Vue+Redis實現(xiàn)單點登錄(一處登錄另一處退出登錄)

    SpringBoot+Vue+Redis實現(xiàn)單點登錄(一處登錄另一處退出登錄)

    小編接到一個需求,需要實現(xiàn)用戶在瀏覽器登錄后,跳轉(zhuǎn)到其他頁面,當(dāng)用戶在其它地方又登錄時,前面用戶登錄的頁面退出登錄,這篇文章主要介紹了SpringBoot+Vue+Redis實現(xiàn)單點登錄,需要的朋友可以參考下
    2019-12-12
  • RocketMQ producer同步發(fā)送單向發(fā)送源碼解析

    RocketMQ producer同步發(fā)送單向發(fā)送源碼解析

    這篇文章主要為大家介紹了RocketMQ producer同步發(fā)送單向發(fā)送源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • Java實現(xiàn)根據(jù)sql動態(tài)查詢并下載數(shù)據(jù)到excel

    Java實現(xiàn)根據(jù)sql動態(tài)查詢并下載數(shù)據(jù)到excel

    這篇文章主要為大家詳細(xì)介紹了如何使用Java實現(xiàn)根據(jù)sql動態(tài)查詢并下載數(shù)據(jù)到excel的功能,文中的示例代碼講解詳細(xì),有需要的可以參考下
    2024-04-04

最新評論

丹巴县| 乾安县| 巫溪县| 彩票| 方山县| 观塘区| 昭苏县| 和田县| 东乡族自治县| 论坛| 嘉义县| 富平县| 永宁县| 界首市| 和顺县| 县级市| 廉江市| 柏乡县| 岗巴县| 望奎县| 苏尼特左旗| 朔州市| 施甸县| 云林县| 曲阳县| 都昌县| 垫江县| 宾阳县| 潼关县| 高陵县| 闸北区| 湖州市| 常宁市| 彭水| 中山市| 濉溪县| 瑞安市| 湟中县| 建湖县| 资源县| 茶陵县|