spring boot + mybatis + mysql + mycat 动态分离 四

4 篇文章 0 订阅
3 篇文章 0 订阅

主题思路是:

       通过aop技术,根据请求后台的方式进行切换datasource 源,是写还是读数据。

1、上篇博文说明了mysql 的动态分离。现在需要整合spring boot 进行整合搭建服务,demo项目

2、回忆下mybatis ,一般都是把mybatis 做dao层。

首先需要引入pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mycat.demo</groupId>
  <artifactId>damayicDemo</artifactId>
  <version>0.0.1-SNAPSHOT</version>
   <parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.0.4.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
   </parent>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
		</dependency>
           <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>1.23</version>
        </dependency>
        <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.62</version>
</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.0.23</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

2、配置application.yml  读写对象

spring:
  datasource:
    ###可读数据源
    select:
      jdbc-url: jdbc:mysql://nginx.fandong.com:8066/testdb
      driver-class-name: com.mysql.jdbc.Driver
      username: user
      password: user
    ####可写数据源  
    update:
      jdbc-url: jdbc:mysql://nginx.fandong.com:8066/testdb
      driver-class-name: com.mysql.jdbc.Driver
      username: root
      password: root
    type: com.alibaba.druid.pool.DruidDataSource

3、配置datasource 源

/**
 * 
 */
package com.dynamic.demo.config;

import javax.sql.DataSource;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author fandong
 *
 */
@Configuration
public class DataSourceConfig {

	@Bean(name="selectDataSource")
	@ConfigurationProperties(prefix = "spring.datasource.select")
	public DataSource dataSource1() {
		return DataSourceBuilder.create().build();
	}
	
	@Bean(name="updateDataSource")
	@ConfigurationProperties(prefix = "spring.datasource.update")
	public DataSource  dataSource2() {
		return DataSourceBuilder.create().build();
	}
}

4、缓存数据源

/**
 * 
 */
package com.dynamic.demo.config;

import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

/**
 * @author fandong
 *
 */
@Component
@Lazy(false)
public class DataSourceContextHolder {
	private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
	// 设置数据源类型
	public static void setDbType(String dbType) {
		contextHolder.set(dbType);
	}

	public static String getDbType() {
		return contextHolder.get();
	}

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

5、使用AbstractRoutingDataSource 进行路由当前的数据源。

package com.dynamic.demo.config;

import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;

@Component
@Primary
public class DynamicDataSource extends AbstractRoutingDataSource {
	@Autowired
	@Qualifier("selectDataSource")
	private DataSource selectDataSource;

	@Autowired
	@Qualifier("updateDataSource")
	private DataSource updateDataSource;

	/**
	 * 这个是主要的方法,返回的是生效的数据源名称
	 */
	@Override
	protected Object determineCurrentLookupKey() {
		System.out.println("DataSourceContextHolder:::" + DataSourceContextHolder.getDbType());
		return DataSourceContextHolder.getDbType();
	}

	/**
	 * 配置数据源信息
	 */
	@Override
	public void afterPropertiesSet() {
		Map<Object, Object> map = new HashMap<>();
		map.put("selectDataSource", selectDataSource);
		map.put("updateDataSource", updateDataSource);
		setTargetDataSources(map);
		setDefaultTargetDataSource(updateDataSource);
		super.afterPropertiesSet();
	}
}

6、使用aop 在进行方法执行时进行拦截

package com.dynamic.demo.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.dynamic.demo.config.DataSourceContextHolder;


// 使用AOP动态切换不同的数据源
@Aspect
@Component
@Lazy(false)
@Order(0) // Order设定AOP执行顺序 使之在数据库事务上先执行
public class SwitchDataSourceAOP {
	// 这里切到你的方法目录
	@Before("execution(* com.dynamic.demo.service.*.*(..))")
	public void process(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		if (methodName.startsWith("get") || methodName.startsWith("count") || methodName.startsWith("find")
				|| methodName.startsWith("list") || methodName.startsWith("select") || methodName.startsWith("check")) {
			DataSourceContextHolder.setDbType("selectDataSource");
		} else {
			// 切换dataSource
			DataSourceContextHolder.setDbType("updateDataSource");
		}
	}
}

---调用过程

      1、 首先把两个数据源进行实例化。

      2、在调用select、update 方法是使用aop进行拦截,获取拦截的方法名称判断调用哪个数据实例,将数据实例key添加到ThreadLocal 中。

    3、 在AbstractRoutingDataSource 调用 determineTargetDataSource 方法进行获取当前的实例。

           在determineTargetDataSource 方法中调用了determineCurrentLookupKey 获取当前执行的方法数据key值。

           在重写的方法

         

protected DataSource determineTargetDataSource() {
		Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
		Object lookupKey = determineCurrentLookupKey();
		DataSource dataSource = this.resolvedDataSources.get(lookupKey);
		if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
			dataSource = this.resolvedDefaultDataSource;
		}
		if (dataSource == null) {
			throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
		}
		return dataSource;
	}

 重写的方法,把数据示例注入中。


	/**
	 * 配置数据源信息
	 */
	@Override
	public void afterPropertiesSet() {
		Map<Object, Object> map = new HashMap<>();
		map.put("selectDataSource", selectDataSource);
		map.put("updateDataSource", updateDataSource);
		setTargetDataSources(map);
		setDefaultTargetDataSource(updateDataSource);
		super.afterPropertiesSet();
	}

这样即可动态切换数据。

剩下就是mybatis 的创建entity

/**
 * 
 */
package com.dynamic.demo.entity;

import org.springframework.stereotype.Component;

/**
 * @author fandong
 *
 */
@Component
public class T1Entity {

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
}

创建mapper 接口方法

/**
 * 
 */
package com.dynamic.demo.mapper;

import java.util.List;

import javax.websocket.server.PathParam;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;

import com.dynamic.demo.entity.T1Entity;


/**
 * @author fandong
 *
 */
public interface T1Mapper {
    
	@Select("select name from t1")
	List<T1Entity> findT1();
	
	@Insert("insert into t1 (name) values(#{name})")
	void update(@PathParam("entity") T1Entity entity);
}

创建service 

 

/**
 * 
 */
package com.dynamic.demo.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.dynamic.demo.entity.T1Entity;
import com.dynamic.demo.mapper.T1Mapper;

/**
 * @author fandong
 *
 */
@Service
public class T1Service {
	
    @Autowired
	public T1Mapper t1Mapper;
    
    public List<T1Entity> getEntities(){
    	System.out.println("打印kkkk");
    	return t1Mapper.findT1();
    }
    
    public void update(T1Entity entity) {
    	System.out.println("插入。。。");
    	t1Mapper.update(entity);
    }
}

创建Controller 方法

/**
 * 
 */
package com.dynamic.demo.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSON;
import com.dynamic.demo.entity.T1Entity;
import com.dynamic.demo.service.T1Service;

/**
 * @author fandong
 *
 */
@RestController
public class Hello {

	@Autowired
	private T1Service t1Service;
	
	
	@RequestMapping("/findEntities")
	public String getEntity() {
		List<T1Entity> entities = t1Service.getEntities();
		
	    for(T1Entity entity : entities) {
	    	System.out.println(entity.getName());
	    }
	   String  jsonString =   JSON.toJSONString(entities);
		return jsonString;
				
	}
	
	@RequestMapping("/insert/{name}")
	public void  insert(@PathVariable("name") String name) {
        System.out.println("insert value:"+ name);
        T1Entity t1Entity = new T1Entity();
        t1Entity.setName(name);
        t1Service.update(t1Entity);
	}
	
}

 

测试:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值