当前位置: 首页 > news >正文

福田做棋牌网站建设找哪家效益快郑州建网站的公司

福田做棋牌网站建设找哪家效益快,郑州建网站的公司,免费网站建设品牌,wap网站建设公司读写分离的作用是为了缓解写库,也就是主库的压力,但一定要基于数据一致性的原则,就是保证主从库之间的数据一定要一致。如果一个方法涉及到写的逻辑,那么该方法里所有的数据库操作都要走主库。 一、环境部署 数据库:…

读写分离的作用是为了缓解写库,也就是主库的压力,但一定要基于数据一致性的原则,就是保证主从库之间的数据一定要一致。如果一个方法涉及到写的逻辑,那么该方法里所有的数据库操作都要走主库。

一、环境部署

  • 数据库:MySql
  • 2个,一主一从
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (`user_id` bigint(20) NOT NULL COMMENT '用户id',`user_name` varchar(255) DEFAULT '' COMMENT '用户名称',`user_phone` varchar(50) DEFAULT '' COMMENT '用户手机',`address` varchar(255) DEFAULT '' COMMENT '住址',`weight` int(3) NOT NULL DEFAULT '1' COMMENT '权重,大者优先',`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO `user` VALUES ('1196978513958141952', '测试1', '18826334748', '广州市海珠区', '1', '2019-11-20 10:28:51', '2019-11-22 14:28:26');
INSERT INTO `user` VALUES ('1196978513958141953', '测试2', '18826274230', '广州市天河区', '2', '2019-11-20 10:29:37', '2019-11-22 14:28:14');
INSERT INTO `user` VALUES ('1196978513958141954', '测试3', '18826273900', '广州市天河区', '1', '2019-11-20 10:30:19', '2019-11-22 14:28:30');

二、依赖

<dependencies><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.10</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><dependency><groupId>tk.mybatis</groupId><artifactId>mapper-spring-boot-starter</artifactId><version>2.1.5</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency><!-- 动态数据源 所需依赖 ### start--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId><scope>provided</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><scope>provided</scope></dependency><!-- 动态数据源 所需依赖 ### end--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.4</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency>
</dependencies>

在这里插入图片描述

三、application.yml配置主从数据源

server:port: 8001
spring:jackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: GMT+8datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Drivermaster:url: jdbc:mysql://127.0.0.1:3307/user?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&useSSL=false&zeroDateTimeBehavior=convertToNull&allowMultiQueries=trueusername: rootpassword:slave:url: jdbc:mysql://127.0.0.1:3308/user?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&useSSL=false&zeroDateTimeBehavior=convertToNull&allowMultiQueries=trueusername: rootpassword:

四、Config配置

@Getter
public enum DynamicDataSourceEnum {MASTER("master"),SLAVE("slave");private String dataSourceName;DynamicDataSourceEnum(String dataSourceName) {this.dataSourceName = dataSourceName;}
}
@Configuration
@MapperScan(basePackages = "com.xjt.proxy.mapper", sqlSessionTemplateRef = "sqlTemplate")
public class DataSourceConfig{//主库@Bean@ConfigurationProperties(prefix = "spring.datasource.master")public DataSource masterDb(){return DruidDataSourceBuilder.create().build();}//从库@Bean@ConditionalOnProperty(prefix = "spring.datasource", name = "slave", matchIfMissing = true)@ConfigurationProperties(prefix = "spring.datasource.slave")public DataSource slaveDb() {return DruidDataSourceBuilder.create().build();}//主从动态配置@Beanpublic DynamicDataSource dynamicDb(@Qualifier("masterDb") DataSource masterDataSource,@Autowired(required = false) @Qualifier("slaveDb") DataSource slaveDataSource){DynamicDataSource dynamicDataSource = new DynamicDataSource();Map<Object,Object> targetDataSources = new HashMap<>();targetDataSources.put(DynamicDataSourceEnum.MASTER.getDataSourceName(), masterDataSource);if(slaveDataSource != null){targetDataSources.put(DynamicDataSourceEnum.SLAVE.getDataSourceName(), slaveDataSource);}dynamicDataSource.setTargetDataSources(targetDataSources);dynamicDataSource.setDefaultTargetDataSource(masterDataSource);return dynamicDataSource;}@Beanpublic SqlSessionFactory sessionFactory(){SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*Mapper.xml"));bean.setDataSource(dynamicDataSource);return bean.getObject();}@Beanpublic SqlSessionTemplate sqlTemplate(){return new SqlSessionTemplate(sqlSessionFactory);}@Bean(name = "dataourceTx")public DataSourceTransactionManager dataSourceTx(){DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();dataSourceTransactionManager.setDataSource(dynamicDataSource);return dataSourceTransactionManager;}
}

五、设置路由

为了方便查找对应的数据源,我们可以用ThreadLocal保存数据源的信息到每个线程中,方便我们需要时获取

pubic class DataSourceContextHolder{private static final ThreadLocal<String> DYNAMIC_DATASOURCE_CONTEXT = new ThreadLocal<>();public static void set(String datasourceType) {DYNAMIC_DATASOURCE_CONTEXT.set(datasourceType);}public static String get() {return DYNAMIC_DATASOURCE_CONTEXT.get();}public static void clear() {DYNAMIC_DATASOURCE_CONTEXT.remove();}
}

AbstractRoutingDataSource的作用是基于查找key路由到对应的数据源,它内部维护了一组目标数据源,并且做了路由key与目标数据源之间的映射,提供基于key查找数据源的方法。

public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.get();}
}

六、数据源的注解

方便切换数据源,注解中包含数据源对应的枚举值,默认是主库

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface DataSourceSelector {DynamicDataSourceEnum value() default DynamicDataSourceEnum.MASTER;boolean clear() default true;
}

七、Aop切换数据源

定义一个aop类,对有注解的方法做切换数据源的操作

@Slf4j
@Aspect
@Order(value = 1)
@Component
public class DataSourceContextAop {@Around("@annotation(com.xjt.proxy.dynamicdatasource.DataSourceSelector)")public Object setDynamicDataSource(ProceedingJoinPoint pjp) throws Throwable {boolean clear = true;try {Method method = this.getMethod(pjp);DataSourceSelector dataSourceImport = method.getAnnotation(DataSourceSelector.class);//获取注解标注的方法clear = dataSourceImport.clear();DataSourceContextHolder.set(dataSourceImport.value().getDataSourceName());log.info("========数据源切换至:{}", dataSourceImport.value().getDataSourceName());return pjp.proceed();} finally {if (clear) {DataSourceContextHolder.clear();}}}private Method getMethod(JoinPoint pjp) {MethodSignature signature = (MethodSignature)pjp.getSignature();return signature.getMethod();}}

八、测试

写好Service文件,包含读取和更新两个方法

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;@DataSourceSelector(value = DynamicDataSourceEnum.SLAVE)public List<User> listUser() {List<User> users = userMapper.selectAll();return users;}@DataSourceSelector(value = DynamicDataSourceEnum.MASTER)public int update() {User user = new User();user.setUserId(Long.parseLong("1196978513958141952"));user.setUserName("修改后的名字2");return userMapper.updateByPrimaryKeySelective(user);}@DataSourceSelector(value = DynamicDataSourceEnum.SLAVE)public User find() {User user = new User();user.setUserId(Long.parseLong("1196978513958141952"));return userMapper.selectByPrimaryKey(user);}
}

根据方法上的注解可以看出,读的方法走从库,更新的方法走主库,更新的对象是userId为1196978513958141953 的数据

@RunWith(SpringRunner.class)
@SpringBootTest
class UserServiceTest {@AutowiredUserService userService;@Testvoid listUser() {List<User> users = userService.listUser();for (User user : users) {System.out.println(user.getUserId());System.out.println(user.getUserName());System.out.println(user.getUserPhone());}}@Testvoid update() {userService.update();User user = userService.find();System.out.println(user.getUserName());}
}

读取方法
在这里插入图片描述

更新方法
在这里插入图片描述
执行之后,比对数据库就可以发现主从库都修改了数据,说明我们的读写分离是成功的。当然,更新方法可以指向从库,这样一来就只会修改到从库的数据,而不会涉及到主库。

http://www.hengruixuexiao.com/news/56446.html

相关文章:

  • 汇算清缴在哪个网站上做深圳网站建设方案
  • 微信 网站 优劣势昆明网站seo服务
  • 影楼网站建设百度关键词搜索排名代发
  • 小型网站建设方案seo现在还有前景吗
  • dedecms婚纱摄影网站模板精准营销方式有哪些
  • wordpress_DMSseo快速排名的方法
  • 西安 做网站谷歌google浏览器官方下载
  • 百度收录左侧带图片的网站百度网盘搜索引擎入口哪里
  • 免费在线观看电影网站优化精灵
  • 58同城网站模板网络推广都有哪些方式
  • 门户网站的建设费用个人推广网站
  • 安徽建设工程造价信息网站搜索引擎优化公司
  • 西安哪家做网站靠谱百度小说排行榜2019
  • 个人简介网站怎么做淘宝网页版
  • 网站虚拟主机哪个好网络平台推广具体是怎么推广
  • 多种专业网站建设seo优化专员编辑
  • 盐城网站制作关键词搜索方法
  • 南京师范大学课程建设网站网站搜索引擎优化
  • 网站开发的工作要求线上营销推广方案
  • 电商ui设计是什么意思安卓手机优化软件哪个好
  • 网站开发工具的功能有哪些免费发布推广平台
  • 网站建设公司联系方式西安seo按天收费
  • 做网站建设公司哪家好营销策划方案1000例
  • 崇文网站建设营销软文范文
  • b2b电子商务平台都有哪些成都seo招聘
  • 南京网站建设案例潍坊百度网站排名
  • 民治营销网站制作seo推广方案怎么做
  • 泉州市亿民建设发展有限公司网站新app推广去哪里找
  • 海南省工程建设定额网站seo和sem的关系
  • 做网站现在可以挣钱吗吸引人的营销标题