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

外国网站开放的浏览器合肥教育平台网站建设

外国网站开放的浏览器,合肥教育平台网站建设,昆山app网站制作,广东省住建局官网读写分离的作用是为了缓解写库,也就是主库的压力,但一定要基于数据一致性的原则,就是保证主从库之间的数据一定要一致。如果一个方法涉及到写的逻辑,那么该方法里所有的数据库操作都要走主库。 一、环境部署 数据库:…

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

一、环境部署

  • 数据库: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.yayakq.cn/news/979910/

相关文章:

  • 教育 高校 网站模板服务器维修
  • 北京网站快速排名优化网站怎么做聚合页面
  • 站点创建成功企业徽章设计
  • 新手如何给自己的网站做优化wordpress安装谷歌分析代码
  • 建设银行上虞支行网站英文网站建设的请示怎么写
  • 苏州企业建设网站价格wordpress script
  • 网站帮助页面设计网页设计师常用网站
  • 库尔勒市建设路街道办网站湘潭做网站价格问下磐石网络
  • 有没有做海报的网站推荐广州开发区官网
  • 网络推广的网站有哪些wordpress 主题制件
  • 四川建设门户网站写作网站水平哪个最好
  • 做网站游戏需要什么免费商标设计网
  • 网站布局的三种基本方法wordpress表白主题
  • wordpress企业主题下载seo排名赚能赚钱吗
  • 用jsp做一网站的流程图桂林两江四湖夜游时间
  • wordpress开发网上商城优化大师百科
  • 网站建设上传文件无锡开发公司
  • 软件资源网站普宁市做网站
  • 汽车网站建设网腾讯广告投放平台官网
  • 免费微网站开发做网站建设个体经营小微企业
  • 往公众号里放网站怎么做做网站游戏怎么挣钱
  • 设计公司网站怎么做建设银行网站的服务管理
  • 国内包装设计网站网站建设服务合同模板
  • 模板网站是啥意思长沙域名注册公司
  • 成功的网站设计前端网站开发实例视频
  • 网站可以免费看查询证书网站建设
  • 无锡网站制作无锡做网站中小型网站建设与管理设计总结
  • 怎样建设网站公司举报的网站是国外的域名和空间
  • 那个网站做推广好网站建设购买模板
  • 公司集团网站开发seo网站优化培训要多少钱