Spring AOP 를 사용 하여 MySQL 데이터베이스 읽 기와 쓰기 분리 사례 분석 실현(데모 첨부)
9662 단어 springaop읽 기와 쓰기 분리
분포 식 환경 에서 데이터 베 이 스 를 읽 고 쓰 는 분리 전략 은 데이터 베 이 스 를 읽 고 쓰 는 성능 병목 을 해결 하 는 관건 적 인 해결 방안 으로 응용 에서 데 이 터 를 읽 는 속도 와 병행 량 을 최대한 향상 시 켰 다.
데이터베이스 읽 기와 쓰기 분 리 를 할 때 우 리 는 먼저 데이터베이스 의 주종 설정 을 해 야 한다.가장 간단 한 것 은 Master 한 대 와 Slave 한 대(대형 사이트 시스템 이 라면 당연히 복잡 할 것 이다.여 기 는 가장 간단 한 상황 만 분석 했다)이다.주종 설정 을 통 해 데이터베이스 에서 같은 데 이 터 를 유 지 했 습 니 다.저 희 는 읽 기 작업 을 할 때 데이터베이스 Slave 에 접근 하고 쓰기 작업 을 할 때 주 데이터베이스 Master 에 접근 합 니 다.이렇게 하면 서버 한 대의 스트레스 를 줄 일 수 있다.
읽 기와 쓰기 분리 사례 분석 을 할 때우선,데이터베이스 의 주종 복 제 를 설정 합 니 다MySQL 5.6 데이터베이스 주종(Master/Slave)동기 화 설치 및 설정 상세 설명
물론 코드 로 데이터베이스 의 읽 기와 쓰기 분 리 를 어떻게 실현 하 는 지 간단하게 보기 위해 주종 데이터 베 이 스 를 설정 할 필요 가 없고 같은 데이터 베 이 스 를 설치 한 기계 두 대만 있 으 면 된다.
2.읽 기와 쓰기 의 분 리 를 실현 하 는 두 가지 방법
구체 적 으로 개발 과정 에서 읽 기와 쓰기 분 리 를 실현 하 는 데 자주 사용 되 는 두 가지 방식 이 있다.
1.첫 번 째 방식 은 우리 가 가장 자주 사용 하 는 방식 이다.바로 2 개의 데이터 베이스 연결 을 정의 하 는 것 이다.하 나 는 MasterDataSource 이 고 다른 하 나 는 SlaveDataSource 이다.데 이 터 를 업데이트 할 때 MasterDataSource 를 읽 고 데 이 터 를 조회 할 때 SlaveDataSource 를 읽 습 니 다.이런 방식 은 매우 간단 해서 나 는 군말 하지 않 겠 다.
2.두 번 째 방식 은 동적 데이터 원본 전환 입 니 다.프로그램 이 실 행 될 때 데이터 원본 을 프로그램 에 동적 으로 짜 서 메 인 라 이브 러 리 를 읽 을 지,라 이브 러 리 에서 읽 을 지 선택 하 는 것 입 니 다.주로 사용 되 는 기술 은 Annotation,spring AOP,반사 이다.
실현 방식 을 상세히 소개 하 겠 습 니 다.
3.Aop 은 주종 데이터베이스 의 읽 기와 쓰기 분리 사례 를 실현 한다.
1.프로젝트 코드 주소
현재 이 데모 의 프로젝트 주소:demo
2.프로젝트 구조
위의 그림 에서 표 시 된 코드 를 제외 하고 다른 것 은 주로 설정 코드 와 업무 코드 이다.
3.구체 적 인 분석
이 프로젝트 는 SSM 프레임 워 크 의 demo,Spring,Spring MVC,MyBatis 로 구체 적 인 프로필 은 많이 소개 되 지 않 습 니 다.
(1)UserContoller 아 날로 그 읽 기와 쓰기 데이터
/**
* 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";
}
}
아 날로 그 읽 기와 쓰기 데이터,IUserService 호출.(2)spring-db.xml 읽 기 데이터 원본 설정
<?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>
<!-- -->
<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}"/>
<!-- -->
</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}"/>
<!-- -->
</bean>
<!-- -->
<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 두 개의 데이터 원본 을 설정 하 였 으 나 SqlSession Factory Bean 에 게 맡 겨 관리 하 는 것 은 dataSource 뿐 입 니 다.그 중에서 사용 되 는 것 은 com.xuliugen.choosedb.demo.aspect.Choose DataSource 입 니 다.이것 은 데이터 베 이 스 를 선택 하 는 것 입 니 다.
<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>
데이터 베 이 스 를 설정 하 였 습 니 다.Choose DataSource 의 구체 적 인 코드 는 다음 과 같 습 니 다.(3)ChooseDataSource
/**
* ,
*/
public class ChooseDataSource extends AbstractRoutingDataSource {
public static Map<String, List<String>> METHOD_TYPE_MAP = new HashMap<String, List<String>>();
/**
* ,
* @return
*/
protected Object determineCurrentLookupKey() {
return DataSourceHandler.getDataSource();
}
//
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 의 구체 적 인 방법 인 AOP 차단
/**
* ( )
*/
@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,데이터 원본 의 Handler 클래스
package com.xuliugen.choosedb.demo.aspect;
/**
* Handler
*/
public class DataSourceHandler {
//
public static final ThreadLocal<String> holder = new ThreadLocal<String>();
/**
* 、 holder
*/
public static void putDataSource(String datasource) {
holder.set(datasource);
}
/**
* holer
*/
public static String getDataSource() {
return holder.get();
}
}
주요 코드 는 상술 한 바 와 같다.본문 코드:demo
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
thymeleaf로 HTML 페이지를 동적으로 만듭니다 (spring + gradle)지난번에는 에서 화면에 HTML을 표시했습니다. 이번에는 화면을 동적으로 움직여보고 싶기 때문에 입력한 문자를 화면에 표시시키고 싶습니다. 초보자의 비망록이므로 이상한 점 등 있으면 지적 받을 수 있으면 기쁩니다! ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.