扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
SpringBoot使用Mybatis实现主从分离的方法?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
成都创新互联公司是专业的和平网站建设公司,和平接单;提供成都网站制作、网站设计,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行和平网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!
新建一个Maven项目,最终项目结构如下:
多数据源注入到sqlSessionFactory
POM增加如下依赖:
com.fasterxml.jackson.core jackson-core com.fasterxml.jackson.core jackson-databind com.fasterxml.jackson.datatype jackson-datatype-joda com.fasterxml.jackson.module jackson-module-parameter-names org.springframework.boot spring-boot-starter-jdbc MySQL mysql-connector-java com.alibaba druid 1.0.11 org.mybatis.spring.boot mybatis-spring-boot-starter 1.1.1 tk.mybatis mapper-spring-boot-starter 1.1.0 com.github.pagehelper pagehelper-spring-boot-starter 1.1.0 mybatis-spring-boot-starter org.mybatis.spring.boot
这里需要注意的是:项目是通过扩展mybatis-spring-boot-starter的org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration来实现多数据源注入的。在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(); } }
将多数据源注入到sqlSessionFactory中
前面提到了这里通过扩展mybatis-spring-boot-starter的org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration来实现多数据源注入的
@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
实现读写分离(多数据源分离)
这里主要思路如下:
1-将不同的数据源标识记录在ThreadLocal中
2-通过注解标识出当前的service方法使用哪个库
3-通过Spring AOP实现拦截注解并注入不同的标识到threadlocal中
4-获取源的时候通过threadlocal中不同的标识给出不同的sqlSession
标识存放ThreadLocal的实现
public class DbContextHolder { public enum DbType{ MASTER,SLAVE } private static final ThreadLocalcontextHolder = 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; } }
根据标识获取不同源
这里我们通过扩展AbstractRoutingDataSource来获取不同的源。它是Spring提供的一个可以根据用户发起的不同请求去转换不同的数据源,比如根据用户的不同地区语言选择不同的数据库。通过查看源码可以发现,它是通过determineCurrentLookupKey()返回的不同key到sqlSessionFactory中获取不同源(前面已经展示了如何在sqlSessionFactory中注入多个源)
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{ }
Service
@Service public class DicTypeService { @Autowired private DicTypeMapper dicTypeMapper; @ReadOnlyConnection public ListgetAll(DicType dicType){ if (dicType.getPage() != null && dicType.getRows() != null) { PageHelper.startPage(dicType.getPage(), dicType.getRows()); } return dicTypeMapper.selectAll(); } }
注意这里的@ReadOnlyConnection注解
Controller
@RestController @RequestMapping("/dictype") public class DicTypeController { @Autowired private DicTypeService dicTypeService; @RequestMapping(value = "/all") public PageInfogetALL(DicType dicType){ List 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-在读写分离场景中不会考虑主从库事务,在纯读的上下文上使用@ReadOnlyConnection标签。其他则默认使用主库。
2-在多源场景中,Spring的@Transaction是可以保证多源的事务性的。
关于SpringBoot使用Mybatis实现主从分离的方法问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注创新互联行业资讯频道了解更多相关知识。
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流