spring boot+mybatis 实现数据库读写分离

本人做的是后台管理项目,基于配置文件application.yml,我这里配置的是两个数据源,一读一写,没有使用ali的Druid,这个喜欢可以自己加在配置在文件里

 datasource:
    name: master
    url: jdbc:mysql://127.0.0.1:3306/test52?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
    username: 
    password: 
    driver-class-name: com.mysql.jdbc.Driver
    hikari:
      max-lifetime: 1765000 #一个连接的生命时长(毫秒),超时而且没被使用则被释放(retired),缺省:30分钟,建议设置比数据库超时时长少30秒以上  
      maximum-pool-size:  15 #连接池中允许的最大连接数。缺省值:10;推荐的公式:((core_count * 2) + effective_spindle_count) 
  readdb:
    name: readdb
    url: jdbc:mysql://127.0.0.1:3306/swingcard?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
    password: 
    driver-class-name: com.mysql.jdbc.Driver

接下来根据配置文件配置数据源:

@Configuration
@EnableTransactionManagement
public class DataSourceConfig {
	private final Logger logger = LoggerFactory.getLogger(DataSourceConfig.class);
	@Bean(name="masterDataSource",destroyMethod = "close" )
	@ConfigurationProperties(prefix="spring.datasource")
	public DataSource masterDataSource() {
		logger.info("主库初始化");
		return new org.apache.tomcat.jdbc.pool.DataSource();
	}
	@Bean(name="slaveDataSource")
	@ConfigurationProperties(prefix = "spring.readdb")
	public DataSource slaveDataSource() {
		return new org.apache.tomcat.jdbc.pool.DataSource();
	}
	
	@Bean(name="dynamicDataSource")
	@Primary
	public DynamicDataSource getDataSource() {
		DynamicDataSource dataSource  =  new DynamicDataSource();
		dataSource.setTargetDataSources(targetDataSources());
		return dataSource;
	}
	
	private Map<Object,Object> targetDataSources(){
		Map<Object,Object> targetDataSources = new HashedMap<>();
		targetDataSources.put(DataSourceType.MASTER.getType(), masterDataSource());
		targetDataSources.put(DataSourceType.SLAVE.getType(), slaveDataSource());
//		targetDataSources.put(DbContextHolder.getDbType(), masterDataSource());
//		targetDataSources.put(DbContextHolder.getDbType(), slaveDataSource());
		return targetDataSources;
	}
	
}

枚举的数据连接类型:主从配置和数据源的动态切换

public enum DataSourceType {
    MASTER("master"),
    SLAVE("slave");

    private String type;

    DataSourceType(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }
}
public class DataSourceHolder {
	private static final ThreadLocal<String> holder = new ThreadLocal<>();
	
	public static void putDataSource(DataSourceType dataSourceType) {
		holder.set(dataSourceType.getType());
	}
	
	public static String getDataSource() {
		return holder.get();
	}
	
	  public static void clearDataSourceType() {
		  holder.remove();
	}
}

数据库路由:这里fianally中的方法根据自己需求来决定是否使用,我这里是因为想要的实现结果是默认都是主库的,个别方法才会读取从库数据,这里是清除从库的记录,(注:没有这个方法时出现过在没有加从库注解的方法去使用了从库的数据源,这只是我个人的问题,仅供参考)

public class DynamicDataSource extends AbstractRoutingDataSource{

	@Override
	protected Object determineCurrentLookupKey() {
		if(null!=DataSourceHolder.getDataSource()) {
			try {
				return DataSourceHolder.getDataSource();
			}finally {
				DataSourceHolder.clearDataSourceType();
			}
		}
		return DataSourceType.MASTER.getType();
	}
}

默认数据源:这里的RetentionPolicy和ElementType可能要手动导入

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
@Inherited
public @interface DataSource {
	DataSourceType value() default DataSourceType.MASTER;
}

切面值入:

@Configuration
@Aspect
public class DataSourceAspect implements Ordered{
    //使用@DataSource注解的时候会设置具体使用的数据源
    @Before(value = "@annotation(dataSource)")
    public void dataSourcePoint(JoinPoint jp, DataSource dataSource) {
        	DataSourceHolder.putDataSource(dataSource.value());
    }

    //order 越低,代表优先级越高
    @Override
    public int getOrder() {
        return -1;
    }
}

最后在要读取从库数据的serviceImpl实现类的方法上加上注解,即可,(注:事务应该是可以的,因为这里没有用到,需要的话可以打开注解,这个功能还没有测试)

       @DataSource(DataSourceType.SLAVE)
//    @Transactional(rollbackFor = Exception.class)
	public PageInfo<User> selectuserListByCondition(DataGrid grid, String username, String name, String startTime,
			String stopTime, String sourceType, String verifiedStatus, String registday) {
		grid.getOrderBy();
		return PageHelper.startPage(grid.getPageNum(), grid.getPageSize())
				.doSelectPageInfo(() -> this.userMapper.selectuserListByCondition());
	}
pom文件的就不写了,这些应该是把用到的都写在上面了,如果有什么问题错误或者还缺少什么欢迎指正,新手第一次发博客,把今天解决的问题记录下来,如有不当之处请见谅 微笑




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值