Spring Boot 통합 Mybatis 구현 주종(다 중 데이터 원본)분리 방안 예시

본 고 는 Spring Boot 를 사용 하여 Mybatis 를 통합 하고 라 이브 러 리 분리 실현(다 중 데이터 원본 에 도 적용)을 소개 한다.이전 Spring Boot 통합 MyBatis 를 이 어 갑 니 다.페이지 별 플러그 인 PageHelper,유 니 버 설 Mapper,Druid 도 통합 된다.
Maven 프로젝트 를 새로 만 듭 니 다.최종 프로젝트 구 조 는 다음 과 같 습 니 다.

다 중 데이터 원본 을 sqlSession Factory 에 주입 합 니 다.
POM 은 다음 과 같은 의존 도 를 증가 시 킵 니 다.

<!--JSON-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.datatype</groupId>
      <artifactId>jackson-datatype-joda</artifactId>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.module</groupId>
      <artifactId>jackson-module-parameter-names</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.0.11</version>
    </dependency>
    <!--mybatis-->
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>1.1.1</version>
    </dependency>
    <!--mapper-->
    <dependency>
      <groupId>tk.mybatis</groupId>
      <artifactId>mapper-spring-boot-starter</artifactId>
      <version>1.1.0</version>
    </dependency>
    <!--pagehelper-->
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper-spring-boot-starter</artifactId>
      <version>1.1.0</version>
      <exclusions>
        <exclusion>
          <artifactId>mybatis-spring-boot-starter</artifactId>
          <groupId>org.mybatis.spring.boot</groupId>
        </exclusion>
      </exclusions>
    </dependency>

여기 서 주의해 야 할 것 은 프로젝트 는 my batis-spring-boot-starter 의 org.my batis.spring.boot.autoconfigure.Mybatis AutoConfiguration 을 확장 하여 다 중 데이터 원본 주입 을 실현 하 는 것 입 니 다.mybatis-spring-boot-starter:1.2.0 에서 이 클래스 는 기본 구조 함 수 를 취 소 했 기 때문에 이 프로젝트 는 1.1.0 버 전 을 사용 합 니 다.후속 버 전이 확장 개방 처 리 를 다시 할 지 주목 해 야 합 니 다.
여전히 낡은 방안 을 사용 하 는 이 유 는 개인 적 으로 개방 확장 이 합 리 적 이 라 고 생각 하기 때문에 미래의 버 전에 서 돌아 올 것 이 라 고 믿 습 니 다.
다른 방안 이 필요 하 다 면 참고 하 세 요.
홈 라 이브 러 리 설정 추가(application.yml)

druid:
  type: com.alibaba.druid.pool.DruidDataSource
  master:
    url: jdbc:mysql://192.168.249.128:3307/db-test?characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useUnicode=true
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: root
    initial-size: 5
    min-idle: 1
    max-active: 100
    test-on-borrow: true
  slave:
    url: jdbc:mysql://192.168.249.128:3317/db-test?characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: root
    initial-size: 5
    min-idle: 1
    max-active: 100
    test-on-borrow: true
데이터 원본 만 들 기

@Configuration
@EnableTransactionManagement
public class DataSourceConfiguration {

  @Value("${druid.type}")
  private Class<? extends DataSource> dataSourceType;

  @Bean(name = "masterDataSource")
  @Primary
  @ConfigurationProperties(prefix = "druid.master")
  public DataSource masterDataSource(){
    return DataSourceBuilder.create().type(dataSourceType).build();
  }

  @Bean(name = "slaveDataSource")
  @ConfigurationProperties(prefix = "druid.slave")
  public DataSource slaveDataSource1(){
    return DataSourceBuilder.create().type(dataSourceType).build();
  }
}

다 중 데이터 원본 을 sqlSession Factory 에 주입 합 니 다.
앞에서 언급 한 바 와 같이 mybatis-spring-boot-starter 를 확장 하 는 org.mybatis.spring.boot.autoconfigure.Mybatis AutoConfiguration 을 통 해 다 중 데이터 원본 주입 을 실현 합 니 다

@Configuration
@AutoConfigureAfter({DataSourceConfiguration.class})
public class MybatisConfiguration extends MybatisAutoConfiguration {

  private static Log logger = LogFactory.getLog(MybatisConfiguration.class);

  @Resource(name = "masterDataSource")
  private DataSource masterDataSource;
  @Resource(name = "slaveDataSource")
  private DataSource slaveDataSource;

  @Bean
  public SqlSessionFactory sqlSessionFactory() throws Exception {
    return super.sqlSessionFactory(roundRobinDataSouceProxy());
  }

  public AbstractRoutingDataSource roundRobinDataSouceProxy(){
    ReadWriteSplitRoutingDataSource proxy = new ReadWriteSplitRoutingDataSource();
    Map<Object,Object> targetDataResources = new ClassLoaderRepository.SoftHashMap();
    targetDataResources.put(DbContextHolder.DbType.MASTER,masterDataSource);
    targetDataResources.put(DbContextHolder.DbType.SLAVE,slaveDataSource);
    proxy.setDefaultTargetDataSource(masterDataSource);//   
    proxy.setTargetDataSources(targetDataResources);
    return proxy;
  }
}

읽 기와 쓰기 분리 실현(다 중 데이터 원본 분리)
여기 서 주요 한 사고방식 은 다음 과 같다.
1-서로 다른 데이터 소스 표 지 를 ThreadLocal 에 기록 합 니 다.
2-현재 service 방법 으로 어떤 라 이브 러 리 를 사용 하 는 지 설명 을 통 해 표시 합 니 다.
3-Spring AOP 를 통 해 차단 주 해 를 실현 하고 서로 다른 표 지 를 threadlocal 에 주입 합 니 다.
4-원본 을 가 져 올 때 threadlocal 의 서로 다른 표 지 를 통 해 서로 다른 sqlSession 을 제공 합 니 다.
표지 저장 ThreadLocal 의 실현

public class DbContextHolder {

  public enum DbType{
    MASTER,SLAVE
  }

  private static final ThreadLocal<DbType> contextHolder = new ThreadLocal<>();

  public static void setDbType(DbType dbType){
    if(dbType==null)throw new NullPointerException();
    contextHolder.set(dbType);
  }

  public static DbType getDbType(){
    return contextHolder.get()==null?DbType.MASTER:contextHolder.get();
  }

  public static void clearDbType(){
    contextHolder.remove();
  }

}

주해 실현

/**
 *       service   ,     slaves 
 * Created by Jason on 2017/3/6.
 */
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ReadOnlyConnection {
}
Spring AOP 의 주해 차단

@Aspect
@Component
public class ReadOnlyConnectionInterceptor implements Ordered {

  public static final Logger logger = LoggerFactory.getLogger(ReadOnlyConnectionInterceptor.class);

  @Around("@annotation(readOnlyConnection)")
  public Object proceed(ProceedingJoinPoint proceedingJoinPoint,ReadOnlyConnection readOnlyConnection) throws Throwable {
    try {
      logger.info("set database connection to read only");
      DbContextHolder.setDbType(DbContextHolder.DbType.SLAVE);
      Object result = proceedingJoinPoint.proceed();
      return result;
    }finally {
      DbContextHolder.clearDbType();
      logger.info("restore database connection");
    }
  }


  @Override
  public int getOrder() {
    return 0;
  }
}

표지 에 따라 다른 소스 를 얻 습 니 다.
여기 서 우 리 는 AbstractRouting DataSource 를 확장 하여 서로 다른 소스 를 얻 습 니 다.이것 은 Spring 이 제공 하 는 사용자 의 요청 에 따라 서로 다른 데이터 원본 을 변환 할 수 있 습 니 다.예 를 들 어 사용자 의 지역 언어 에 따라 서로 다른 데이터 베 이 스 를 선택 할 수 있 습 니 다.원본 코드 를 보면 determineCurrentLookupkey()를 통 해 돌아 오 는 서로 다른 key 를 통 해 sqlSession Factory 에 다른 소스 를 가 져 오 는 것 을 알 수 있 습 니 다.(앞에서 sqlSession Factory 에 여러 개의 소스 를 주입 하 는 방법 을 보 여 주 었 습 니 다)

public class ReadWriteSplitRoutingDataSource extends AbstractRoutingDataSource {

  @Override
  protected Object determineCurrentLookupKey() {
    return DbContextHolder.getDbType();
  }
}

읽 기와 쓰기 분리(다 중 데이터 원본)설정 이 완료 되 었 습 니 다.다음은 구체 적 인 실례 이다
사용 방식
Entity

@Table(name = "t_sys_dic_type")
public class DicType extends BaseEntity{

  String code;

  String name;

  Integer status;

  ...
}
Mapper

public interface DicTypeMapper extends BaseMapper<DicType> {
}
Service

@Service
public class DicTypeService {
  @Autowired
  private DicTypeMapper dicTypeMapper;

  @ReadOnlyConnection
  public List<DicType> getAll(DicType dicType){
    if (dicType.getPage() != null && dicType.getRows() != null) {
      PageHelper.startPage(dicType.getPage(), dicType.getRows());
    }
    return dicTypeMapper.selectAll();
  }

}

여기@ReadOnly Connection 주석 주의
Controller

@RestController
@RequestMapping("/dictype")
public class DicTypeController {
  @Autowired
  private DicTypeService dicTypeService;

  @RequestMapping(value = "/all")
  public PageInfo<DicType> getALL(DicType dicType){
    List<DicType> dicTypeList = dicTypeService.getAll(dicType);
    return new PageInfo<>(dicTypeList);
  }
}

mvn spring-boot:run 을 통 해 시작 하면 통과 할 수 있 습 니 다.http://localhost:9090/dictype/all 데이터 가 져 오기
배경 인쇄

c.a.d.m.ReadOnlyConnectionInterceptor  : set database connection to read only
라 이브 러 리 링크 에서 데 이 터 를 가 져 왔 음 을 설명 합 니 다.
비고:다 원 사 무 를 어떻게 보장 합 니까?
1-읽 기와 쓰기 분리 장면 에서 주종 라 이브 러 리 업 무 를 고려 하지 않 고 순 독 된 상하 문 에@ReadOnly Connection 탭 을 사용 합 니 다.다른 것 은 기본 라 이브 러 리 를 사용 합 니 다.
2-다 원 장면 에서 Spring 의@Transaction 은 다 원 의 사무 성 을 확보 할 수 있 습 니 다.
전송 문
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기