昨天,我发了一篇关于 Spring 脑图的学习知识体系,包括原理,源码解析,结合设计模式等。没想到非常的火爆,微信通讯录里一下子多了很多好友。我预计在今年 5 月份左右通讯录会达到 5000 人的上限。目的还是希望大家相互交流,共同进步,相互鼓励!
在互联网技术飞速发展的今天,各种技术已经非常成熟,尤其是像读写分离这样的架构,以及这样的项目显得非常的常见。那么今天我就和大家一起来,手把手的教大家利用 SpringBoot + Mybatis 实现一个读写分库的 demo 项目。
首先,我们这个项目要使用 SpringBoot,因为 SpringBoot 是现阶段最火的框架之一了;第二,我们要使用 Mybatis;第三,我们还要使用自定义注解。
下面我介绍几个主要的类实现,需要源码的可以加我微信号:xmtxtt 为好友,我免费发给大家!
先创建一个 DataSources 数据源接口。比如,我们假设是一主一从。
public interface DataSources {
String MASTER_DB = "masterDB";
String SLAVE_DB = "slaveDB";
}
第二步,创建一个切换数据源的 RoutingDataSource 注解类。
@Retention(RetentionPolicy.RUNTIME)
@Target({
ElementType.METHOD
})
public @interface RoutingDataSource {
String value() default DataSources.MASTER_DB;
}
注解的使用我就不在过多的解释了,就当大家都会吧,如果不会加群交流,好了。
第三步,在 application.yml 中配置多个数据源。
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/xttblog
username: xttblog
password: xttblog
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
datasourceSlave:
url: jdbc:mysql://127.0.0.1:3306/xttblog
username: xttblog
password: xttblog
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
第四步,配置多个 Datasource。
@Configuration
public class DatasourceConfig {
@Bean(destroyMethod = "close", name = DataSources.MASTER_DB)
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().type(DruidDataSource.class).build();
}
@Bean(destroyMethod = "close", name = DataSources.SLAVE_DB)
@ConfigurationProperties(prefix = "spring.datasourceSlave")
public DataSource dataSourceSlave() {
return DataSourceBuilder.create().type(DruidDataSource.class).build();
}
}
第五步,定义一个 DataSourceHolder,切换数据源。
public class DataSourceHolder {
/**
* 默认数据源
*/
public static final String DEFAULT_DATASOURCE = DataSources.MASTER_DB;
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
// 设置数据源名
public static void setDB(String dbType) {
System.out.println("切换到" + dbType + "数据源");
contextHolder.set(dbType);
}
// 获取数据源名
public static String getDB() {
return (contextHolder.get());
}
// 清除数据源名
public static void clearDB() {
contextHolder.remove();
}
}
第六步,定义一个动态数据源。
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceHolder.getDB();
}
}
第七步,Mybatis 整合动态数据源。
@Configuration
public class MybatisDynamicDataSourceConfig {
@Autowired
@Qualifier(DataSources.MASTER_DB)
private DataSource masterDB;
@Autowired
@Qualifier(DataSources.SLAVE_DB)
private DataSource slaveDB;
/**
* 动态数据源
*/
@Bean(name = "dynamicDataSource")
public DataSource dynamicDataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
// 默认数据源
dynamicDataSource.setDefaultTargetDataSource(masterDB);
// 配置多数据源
Map<Object, Object> dsMap = Maps.newHashMap();
dsMap.put(DataSources.MASTER_DB, masterDB);
dsMap.put(DataSources.SLAVE_DB, slaveDB);
dynamicDataSource.setTargetDataSources(dsMap);
return dynamicDataSource;
}
@Bean
@ConfigurationProperties(prefix = "mybatis")
public SqlSessionFactoryBean sqlSessionFactoryBean() {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
// 配置数据源,此处配置为关键配置,如果没有将 dynamicDataSource 作为数据源则不能实现切换
sqlSessionFactoryBean.setDataSource(dynamicDataSource());
return sqlSessionFactoryBean;
}
}
第八步,也是最重要的一步,拦截所有有 @RoutingDataSource 注解的方法。动态的给它指定数据源。
@Aspect
@Component
public class XttblogDynamicDataSourceAspect {
@Before("@annotation(com.xttblog.sharding.RoutingDataSource)")
public void doBeforeSwitchDataSource(ProceedingJoinPoint point){
//获得当前访问的class
Class<?> className = point.getTarget().getClass();
//获得访问的方法名
String methodName = point.getSignature().getName();
Signature signature =point.getSignature();
MethodSignature methodSignature = (MethodSignature)signature;
//得到方法的参数的类型
Class[] argClass = methodSignature.getMethod().getParameterTypes();
String dataSource = DataSourceHolder.DEFAULT_DATASOURCE;
try {
// 得到访问的方法对象
Method method = className.getMethod(methodName, argClass);
// 判断是否存在@DS注解
if (method.isAnnotationPresent(RoutingDataSource.class)) {
RoutingDataSource annotation = method.getAnnotation(RoutingDataSource.class);
// 取出注解中的数据源名
dataSource = annotation.value();
}
} catch (Exception e) {
e.printStackTrace();
}
// 切换数据源
DataSourceHolder.setDB(dataSource);
}
@After("@annotation(com.xttblog.sharding.RoutingDataSource)")
public void doAfterSwitchDataSource(JoinPoint point){
DataSourceHolder.clearDB();
}
}
第九步,要取消自动配置数据源,不要让 SpringBoot 自动的使用 DataSourceAutoConfiguration 了。
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class XttblogApplication {
public static void main(String[] args) {
SpringApplication.run(XttblogApplication.class,args);
}
}
最后就是如何使用了,插入我们使用主库,查询我们使用从库。
@Service
public class XttblogService {
@Autowired
private XttblogMapper xttblogMapper;
@RoutingDataSource(DataSources.MASTER_DB)
public int insert(Xttblog xttblog) {
return xttblogMapper.insertXttblog(xttblog.getName());
}
@RoutingDataSource(DataSources.SLAVE_DB)
public Xttblog select(Long id) {
return xttblogMapper.selectXttblogById(id);
}
}
以上源码,需要的可以加我微信号:xmtxtt 为好友,我免费发给大家!
: » 手把手教你利用 SpringBoot + Mybatis 实现一个读写分库项目
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/252065.html