SpringBoot第33讲:SpringBoot集成ShardingJDBC - 基于JPA的读写分离

SpringBoot第33讲:SpringBoot集成ShardingJDBC - 基于JPA的读写分离

本文是SpringBoot第33讲,主要介绍分表分库,以及SpringBoot集成基于 ShardingJDBC 的读写分离实践

文章目录

  • SpringBoot第33讲:SpringBoot集成ShardingJDBC - 基于JPA的读写分离
    • 1、知识准备
      • 1.1、读写分离库的场景和设计目标?
      • 1.2、核心功能
    • 2、简单示例
      • 2.1、准备DB和依赖配置
      • 2.2、Entity
      • 2.3、DAO
      • 2.4、Service
      • 2.5、Controller
      • 2.6、简单测试
    • 3、进一步理解
      • 3.1、shardingJDBC的主从分离解决不了什么问题?
      • 3.2、读写分离加分库分表?
    • 4、示例源码

1、知识准备

主要理解 ShardingJDBC 针对读写分离库的场景和设计目标等。

1.1、读写分离库的场景和设计目标?

透明化读写分离所带来的影响,让使用方尽量像使用一个数据库一样使用主从数据库集群,是ShardingSphere读写分离模块的主要设计目标。

面对日益增加的系统访问量,数据库的吞吐量面临着巨大瓶颈。 对于同一时刻有大量并发读操作和较少写操作类型的应用系统来说,将数据库拆分为主库和从库,主库负责处理事务性的增删改操作,从库负责处理查询操作,能够有效的避免由数据更新导致的行锁,使得整个系统的查询性能得到极大的改善。

通过一主多从的配置方式,可以将查询请求均匀的分散到多个数据副本,能够进一步的提升系统的处理能力。 使用多主多从的方式,不但能够提升系统的吞吐量,还能够提升系统的可用性,可以达到在任何一个数据库宕机,甚至磁盘物理损坏的情况下仍然不影响系统的正常运行。

与将数据根据分片键打散至各个数据节点的水平分片不同,读写分离则是根据SQL语义的分析,将读操作和写操作分别路由至主库与从库。

img

读写分离的数据节点中的数据内容是一致的,而水平分片的每个数据节点的数据内容却并不相同。将水平分片和读写分离联合使用,能够更加有效的提升系统性能

读写分离虽然可以提升系统的吞吐量和可用性,但同时也带来了数据不一致的问题。 这包括多个主库之间的数据一致性,以及主库与从库之间的数据一致性的问题。 并且,读写分离也带来了与数据分片同样的问题,它同样会使得应用开发和运维人员对数据库的操作和运维变得更加复杂。 下图展现了将分库分表与读写分离一同使用时,应用程序与数据库集群之间的复杂拓扑关系。

img

详细可参考这篇文章:MySQL第七讲:MySQL分库分表详解

1.2、核心功能

  • 提供一主多从的读写分离配置,可独立使用,也可配合分库分表使用。
  • 独立使用读写分离支持SQL透传。
  • 同一线程且同一数据库连接内,如有写入操作,以后的读操作均从主库读取,用于保证数据一致性
  • 基于Hint的强制主库路由

2、简单示例

这里主要介绍SpringBoot集成基于ShardingJDBC的读写分离和数据分片实践,主要承接之前的相关文章在JPA方式的基础上实现的。

2.1、准备DB和依赖配置

创建MySQL的schema db_user_sharding_master 和 db_user_sharding_slave, 导入SQL 文件如下

db_user_sharding_master

DROP TABLE IF EXISTS `tb_role`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `tb_role` (`id` int NOT NULL AUTO_INCREMENT,`name` varchar(255) NOT NULL,`role_key` varchar(255) NOT NULL,`description` varchar(255) DEFAULT NULL,`create_time` datetime DEFAULT NULL,`update_time` datetime DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;--
-- Dumping data for table `tb_role`
--LOCK TABLES `tb_role` WRITE;
/*!40000 ALTER TABLE `tb_role` DISABLE KEYS */;
/*!40000 ALTER TABLE `tb_role` ENABLE KEYS */;
UNLOCK TABLES;--
-- Table structure for table `tb_user`
--DROP TABLE IF EXISTS `tb_user`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `tb_user` (`id` int NOT NULL AUTO_INCREMENT,`user_name` varchar(45) NOT NULL,`password` varchar(45) NOT NULL,`email` varchar(45) DEFAULT NULL,`phone_number` int DEFAULT NULL,`description` varchar(255) DEFAULT NULL,`create_time` datetime DEFAULT NULL,`update_time` datetime DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;--
-- Dumping data for table `tb_user`
--LOCK TABLES `tb_user` WRITE;
/*!40000 ALTER TABLE `tb_user` DISABLE KEYS */;
INSERT INTO `tb_user` VALUES (2,'qiwenjie','aaa','1172814226@qq.com',123133332,'qwj2','2022-04-06 20:44:34','2022-04-06 20:44:34');
/*!40000 ALTER TABLE `tb_user` ENABLE KEYS */;
UNLOCK TABLES;--
-- Table structure for table `tb_user_role`
--DROP TABLE IF EXISTS `tb_user_role`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `tb_user_role` (`user_id` int NOT NULL,`role_id` int NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;--
-- Dumping data for table `tb_user_role`
--LOCK TABLES `tb_user_role` WRITE;
/*!40000 ALTER TABLE `tb_user_role` DISABLE KEYS */;
/*!40000 ALTER TABLE `tb_user_role` ENABLE KEYS */;
UNLOCK TABLES;

db_user_sharding_slave

DROP TABLE IF EXISTS `tb_role`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `tb_role` (`id` int NOT NULL AUTO_INCREMENT,`name` varchar(255) NOT NULL,`role_key` varchar(255) NOT NULL,`description` varchar(255) DEFAULT NULL,`create_time` datetime DEFAULT NULL,`update_time` datetime DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;--
-- Dumping data for table `tb_role`
--LOCK TABLES `tb_role` WRITE;
/*!40000 ALTER TABLE `tb_role` DISABLE KEYS */;
/*!40000 ALTER TABLE `tb_role` ENABLE KEYS */;
UNLOCK TABLES;--
-- Table structure for table `tb_user`
--DROP TABLE IF EXISTS `tb_user`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `tb_user` (`id` int NOT NULL AUTO_INCREMENT,`user_name` varchar(45) NOT NULL,`password` varchar(45) NOT NULL,`email` varchar(45) DEFAULT NULL,`phone_number` int DEFAULT NULL,`description` varchar(255) DEFAULT NULL,`create_time` datetime DEFAULT NULL,`update_time` datetime DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;--
-- Dumping data for table `tb_user`
--LOCK TABLES `tb_user` WRITE;
/*!40000 ALTER TABLE `tb_user` DISABLE KEYS */;
INSERT INTO `tb_user` VALUES (2,'qwj-salve','xxx','xx',12111,'qwj','2022-04-06 20:44:34','2022-04-06 20:44:34');
/*!40000 ALTER TABLE `tb_user` ENABLE KEYS */;
UNLOCK TABLES;--
-- Table structure for table `tb_user_role`
--DROP TABLE IF EXISTS `tb_user_role`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `tb_user_role` (`user_id` int NOT NULL,`role_id` int NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;--
-- Dumping data for table `tb_user_role`
--LOCK TABLES `tb_user_role` WRITE;
/*!40000 ALTER TABLE `tb_user_role` DISABLE KEYS */;
/*!40000 ALTER TABLE `tb_user_role` ENABLE KEYS */;
UNLOCK TABLES;

引入maven依赖, 包含mysql驱动,JPA包, 以及 sharding-jdbc 的依赖。

<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version>
</dependency>
<dependency><groupId>com.github.wenhao</groupId><artifactId>jpa-spec</artifactId><version>3.1.0</version>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.1.1</version>
</dependency>

增加yml配置

spring:shardingsphere:datasource:names: master,slave0master:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://localhost:3306/db_user_sharding_master?allowPublicKeyRetrieval=true&useSSL=false&autoReconnect=true&characterEncoding=utf8username: rootpassword: qwj930828slave0:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://localhost:3306/db_user_sharding_slave?allowPublicKeyRetrieval=true&useSSL=false&autoReconnect=true&characterEncoding=utf8username: rootpassword: qwj930828sharding:tables:tb_user:database-strategy:inline:sharding-column: idalgorithm-expression: masterkey-generator:column: idtype: SNOWFLAKEprops:worker:id: 123tb_role:database-strategy:inline:sharding-column: idalgorithm-expression: masterkey-generator:column: idtype: SNOWFLAKEprops:worker:id: 123tb_user_role:database-strategy:inline:sharding-column: idalgorithm-expression: masterkey-generator:column: idtype: SNOWFLAKEprops:worker:id: 123master-slave:name: msload-balance-algorithm-type: round_robinmaster-data-source-name: masterslave-data-source-names: slave0props:sql:show: truejpa:open-in-view: falsegenerate-ddl: falseshow-sql: falseproperties:hibernate:dialect: org.hibernate.dialect.MySQLDialectformat_sql: trueuse-new-id-generator-mappings: false

2.2、Entity

user entity

package springboot.shardingjdbc.jpa.masterslave.entity;import java.time.LocalDateTime;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;/*** @author qiwenjie*/
@Getter
@Setter
@ToString
@Entity
@Table(name = "tb_user")
public class User implements BaseEntity {/*** user id.*/@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name = "id", nullable = false)private Long id;/*** username.*/private String userName;/*** user pwd.*/private String password;/*** email.*/private String email;/*** phoneNumber.*/private long phoneNumber;/*** description.*/private String description;/*** create date time.*/private LocalDateTime createTime;/*** update date time.*/private LocalDateTime updateTime;/*** join to role table.*/@ManyToMany(cascade = {CascadeType.REFRESH}, fetch = FetchType.EAGER)@JoinTable(name = "tb_user_role", joinColumns = {@JoinColumn(name = "user_id")}, inverseJoinColumns = {@JoinColumn(name = "role_id")})private Set<Role> roles;
}

role entity

package springboot.shardingjdbc.jpa.masterslave.entity;import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;/*** @author qiwenjie*/
@Getter
@Setter
@ToString
@Entity
@Table(name = "tb_role")
public class Role implements BaseEntity {/*** role id.*/@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name = "id", nullable = false)private Long id;/*** role name.*/private String name;/*** role key.*/private String roleKey;/*** description.*/private String description;/*** create date time.*/private LocalDateTime createTime;/*** update date time.*/private LocalDateTime updateTime;
}

2.3、DAO

user dao

package springboot.shardingjdbc.jpa.masterslave.dao;import org.springframework.stereotype.Repository;
import springboot.shardingjdbc.jpa.masterslave.entity.User;/*** @author qiwenjie*/
@Repository
public interface IUserDao extends IBaseDao<User, Long> {}

role dao

package springboot.shardingjdbc.jpa.masterslave.dao;import org.springframework.stereotype.Repository;
import springboot.shardingjdbc.jpa.masterslave.entity.Role;/*** @author qiwenjie*/
@Repository
public interface IRoleDao extends IBaseDao<Role, Long> {}

2.4、Service

user service 接口

package springboot.shardingjdbc.jpa.masterslave.service;import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import springboot.shardingjdbc.jpa.masterslave.entity.User;
import springboot.shardingjdbc.jpa.masterslave.entity.query.UserQueryBean;/*** @author qiwenjie*/
public interface IUserService extends IBaseService<User, Long> {/*** find by page.** @param userQueryBean query* @param pageRequest   pageRequest* @return page*/Page<User> findPage(UserQueryBean userQueryBean, PageRequest pageRequest);
}

user service 实现类

package springboot.shardingjdbc.jpa.masterslave.service.impl;import com.github.wenhao.jpa.Specifications;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import springboot.shardingjdbc.jpa.masterslave.dao.IBaseDao;
import springboot.shardingjdbc.jpa.masterslave.dao.IUserDao;
import springboot.shardingjdbc.jpa.masterslave.entity.User;
import springboot.shardingjdbc.jpa.masterslave.entity.query.UserQueryBean;
import springboot.shardingjdbc.jpa.masterslave.service.IUserService;@Service
public class UserDoServiceImpl extends BaseDoServiceImpl<User, Long> implements IUserService {/*** userDao.*/private final IUserDao userDao;/*** init.** @param userDao2 user dao*/public UserDoServiceImpl(final IUserDao userDao2) {this.userDao = userDao2;}/*** @return base dao*/@Overridepublic IBaseDao<User, Long> getBaseDao() {return this.userDao;}/*** find by page.** @param queryBean   query* @param pageRequest pageRequest* @return page*/@Overridepublic Page<User> findPage(UserQueryBean queryBean, PageRequest pageRequest) {Specification<User> specification = Specifications.<User>and().like(StringUtils.isNotEmpty(queryBean.getName()), "user_name", queryBean.getName()).like(StringUtils.isNotEmpty(queryBean.getDescription()), "description",queryBean.getDescription()).build();return this.getBaseDao().findAll(specification, pageRequest);}
}

role service 接口

package springboot.shardingjdbc.jpa.masterslave.service;import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import springboot.shardingjdbc.jpa.masterslave.entity.Role;
import springboot.shardingjdbc.jpa.masterslave.entity.query.RoleQueryBean;public interface IRoleService extends IBaseService<Role, Long> {/*** find page by query.** @param roleQueryBean query* @param pageRequest   pageRequest* @return page*/Page<Role> findPage(RoleQueryBean roleQueryBean, PageRequest pageRequest);
}

role service 实现类

package springboot.shardingjdbc.jpa.masterslave.service.impl;import com.github.wenhao.jpa.Specifications;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import springboot.shardingjdbc.jpa.masterslave.dao.IBaseDao;
import springboot.shardingjdbc.jpa.masterslave.dao.IRoleDao;
import springboot.shardingjdbc.jpa.masterslave.entity.Role;
import springboot.shardingjdbc.jpa.masterslave.entity.query.RoleQueryBean;
import springboot.shardingjdbc.jpa.masterslave.service.IRoleService;@Service
public class RoleDoServiceImpl extends BaseDoServiceImpl<Role, Long> implements IRoleService {/*** roleDao.*/private final IRoleDao roleDao;/*** init.** @param roleDao2 role dao*/public RoleDoServiceImpl(final IRoleDao roleDao2) {this.roleDao = roleDao2;}/*** @return base dao*/@Overridepublic IBaseDao<Role, Long> getBaseDao() {return this.roleDao;}/*** find page by query.** @param roleQueryBean query* @param pageRequest   pageRequest* @return page*/@Overridepublic Page<Role> findPage(RoleQueryBean roleQueryBean, PageRequest pageRequest) {Specification<Role> specification = Specifications.<Role>and().like(StringUtils.isNotEmpty(roleQueryBean.getName()), "name",roleQueryBean.getName()).like(StringUtils.isNotEmpty(roleQueryBean.getDescription()), "description",roleQueryBean.getDescription()).build();return this.roleDao.findAll(specification, pageRequest);}
}

2.5、Controller

user controller

package springboot.shardingjdbc.jpa.masterslave.controller;import java.time.LocalDateTime;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springboot.shardingjdbc.jpa.masterslave.entity.User;
import springboot.shardingjdbc.jpa.masterslave.entity.query.UserQueryBean;
import springboot.shardingjdbc.jpa.masterslave.entity.response.ResponseResult;
import springboot.shardingjdbc.jpa.masterslave.service.IUserService;/*** @author qiwenjie*/
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate IUserService userService;/*** @param user user param* @return user*/@ApiOperation("Add/Edit User")@PostMapping("add")public ResponseResult<User> add(User user) {if (user.getId()==null || !userService.exists(user.getId())) {user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userService.save(user);} else {user.setUpdateTime(LocalDateTime.now());userService.update(user);}return ResponseResult.success(userService.find(user.getId()));}/*** @return user list*/@ApiOperation("Query User One")@GetMapping("edit/{userId}")public ResponseResult<User> edit(@PathVariable("userId") Long userId) {return ResponseResult.success(userService.find(userId));}/*** @return user list*/@ApiOperation("Query User Page")@GetMapping("list")public ResponseResult<Page<User>> list(@RequestParam int pageSize, @RequestParam int pageNumber) {return ResponseResult.success(userService.findPage(UserQueryBean.builder().build(), PageRequest.of(pageNumber, pageSize)));}
}

2.6、简单测试

访问页面:

http://localhost:8080/doc.html

在这里插入图片描述

插入数据,写入master库

(注意:主库和从库的数据同步不是shardingJDBC做的,需要自行同步)

在这里插入图片描述

查询数据,从slave中查询

查询结果
在这里插入图片描述

slave db中的数据
在这里插入图片描述

相关查询console打印出的日志:

// 如下是插入
2023-08-05 16:48:10.814  INFO 36856 --- [nio-8081-exec-7] ShardingSphere-SQL                       : Logic SQL: insert into tb_user (create_time, description, email, password, phone_number, update_time, user_name) values (?, ?, ?, ?, ?, ?, ?)
2023-08-05 16:48:10.814  INFO 36856 --- [nio-8081-exec-7] ShardingSphere-SQL                       : SQLStatement: CommonSQLStatementContext(sqlStatement=org.apache.shardingsphere.sql.parser.sql.statement.dml.InsertStatement@550b49d4, tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@4ef3f621)
2023-08-05 16:48:10.814  INFO 36856 --- [nio-8081-exec-7] ShardingSphere-SQL                       : Actual SQL: master ::: insert into tb_user (create_time, description, email, password, phone_number, update_time, user_name) values (?, ?, ?, ?, ?, ?, ?)
2023-08-05 16:48:10.859  INFO 36856 --- [nio-8081-exec-7] ShardingSphere-SQL                       : Logic SQL: select user0_.id as id1_1_0_, user0_.create_time as create_t2_1_0_, user0_.description as descript3_1_0_, user0_.email as email4_1_0_, user0_.password as password5_1_0_, user0_.phone_number as phone_nu6_1_0_, user0_.update_time as update_t7_1_0_, user0_.user_name as user_nam8_1_0_, roles1_.user_id as user_id1_2_1_, role2_.id as role_id2_2_1_, role2_.id as id1_0_2_, role2_.create_time as create_t2_0_2_, role2_.description as descript3_0_2_, role2_.name as name4_0_2_, role2_.role_key as role_key5_0_2_, role2_.update_time as update_t6_0_2_ from tb_user user0_ left outer join tb_user_role roles1_ on user0_.id=roles1_.user_id left outer join tb_role role2_ on roles1_.role_id=role2_.id where user0_.id=?
2023-08-05 16:48:10.859  INFO 36856 --- [nio-8081-exec-7] ShardingSphere-SQL                       : SQLStatement: SelectStatementContext(super=CommonSQLStatementContext(sqlStatement=org.apache.shardingsphere.sql.parser.sql.statement.dml.SelectStatement@60866f71, tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@488f6585), tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@488f6585, projectionsContext=ProjectionsContext(startIndex=7, stopIndex=541, distinctRow=false, projections=[ColumnProjection(owner=user0_, name=id, alias=Optional[id1_1_0_]), ColumnProjection(owner=user0_, name=create_time, alias=Optional[create_t2_1_0_]), ColumnProjection(owner=user0_, name=description, alias=Optional[descript3_1_0_]), ColumnProjection(owner=user0_, name=email, alias=Optional[email4_1_0_]), ColumnProjection(owner=user0_, name=password, alias=Optional[password5_1_0_]), ColumnProjection(owner=user0_, name=phone_number, alias=Optional[phone_nu6_1_0_]), ColumnProjection(owner=user0_, name=update_time, alias=Optional[update_t7_1_0_]), ColumnProjection(owner=user0_, name=user_name, alias=Optional[user_nam8_1_0_]), ColumnProjection(owner=roles1_, name=user_id, alias=Optional[user_id1_2_1_]), ColumnProjection(owner=role2_, name=id, alias=Optional[role_id2_2_1_]), ColumnProjection(owner=role2_, name=id, alias=Optional[id1_0_2_]), ColumnProjection(owner=role2_, name=create_time, alias=Optional[create_t2_0_2_]), ColumnProjection(owner=role2_, name=description, alias=Optional[descript3_0_2_]), ColumnProjection(owner=role2_, name=name, alias=Optional[name4_0_2_]), ColumnProjection(owner=role2_, name=role_key, alias=Optional[role_key5_0_2_]), ColumnProjection(owner=role2_, name=update_time, alias=Optional[update_t6_0_2_])]), groupByContext=org.apache.shardingsphere.sql.parser.binder.segment.select.groupby.GroupByContext@70473bc5, orderByContext=org.apache.shardingsphere.sql.parser.binder.segment.select.orderby.OrderByContext@54fe8172, paginationContext=org.apache.shardingsphere.sql.parser.binder.segment.select.pagination.PaginationContext@750817b, containsSubquery=false)
2023-08-05 16:48:10.860  INFO 36856 --- [nio-8081-exec-7] ShardingSphere-SQL                       : Actual SQL: slave0 ::: select user0_.id as id1_1_0_, user0_.create_time as create_t2_1_0_, user0_.description as descript3_1_0_, user0_.email as email4_1_0_, user0_.password as password5_1_0_, user0_.phone_number as phone_nu6_1_0_, user0_.update_time as update_t7_1_0_, user0_.user_name as user_nam8_1_0_, roles1_.user_id as user_id1_2_1_, role2_.id as role_id2_2_1_, role2_.id as id1_0_2_, role2_.create_time as create_t2_0_2_, role2_.description as descript3_0_2_, role2_.name as name4_0_2_, role2_.role_key as role_key5_0_2_, role2_.update_time as update_t6_0_2_ from tb_user user0_ left outer join tb_user_role roles1_ on user0_.id=roles1_.user_id left outer join tb_role role2_ on roles1_.role_id=role2_.id where user0_.id=?// 如下是查询
2023-08-05 18:25:55.299  INFO 36856 --- [nio-8081-exec-9] ShardingSphere-SQL                       : Logic SQL: select user0_.id as id1_1_0_, user0_.create_time as create_t2_1_0_, user0_.description as descript3_1_0_, user0_.email as email4_1_0_, user0_.password as password5_1_0_, user0_.phone_number as phone_nu6_1_0_, user0_.update_time as update_t7_1_0_, user0_.user_name as user_nam8_1_0_, roles1_.user_id as user_id1_2_1_, role2_.id as role_id2_2_1_, role2_.id as id1_0_2_, role2_.create_time as create_t2_0_2_, role2_.description as descript3_0_2_, role2_.name as name4_0_2_, role2_.role_key as role_key5_0_2_, role2_.update_time as update_t6_0_2_ from tb_user user0_ left outer join tb_user_role roles1_ on user0_.id=roles1_.user_id left outer join tb_role role2_ on roles1_.role_id=role2_.id where user0_.id=?
2023-08-05 18:25:55.317  INFO 36856 --- [nio-8081-exec-9] ShardingSphere-SQL                       : SQLStatement: SelectStatementContext(super=CommonSQLStatementContext(sqlStatement=org.apache.shardingsphere.sql.parser.sql.statement.dml.SelectStatement@60866f71, tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@194a9ab4), tablesContext=org.apache.shardingsphere.sql.parser.binder.segment.table.TablesContext@194a9ab4, projectionsContext=ProjectionsContext(startIndex=7, stopIndex=541, distinctRow=false, projections=[ColumnProjection(owner=user0_, name=id, alias=Optional[id1_1_0_]), ColumnProjection(owner=user0_, name=create_time, alias=Optional[create_t2_1_0_]), ColumnProjection(owner=user0_, name=description, alias=Optional[descript3_1_0_]), ColumnProjection(owner=user0_, name=email, alias=Optional[email4_1_0_]), ColumnProjection(owner=user0_, name=password, alias=Optional[password5_1_0_]), ColumnProjection(owner=user0_, name=phone_number, alias=Optional[phone_nu6_1_0_]), ColumnProjection(owner=user0_, name=update_time, alias=Optional[update_t7_1_0_]), ColumnProjection(owner=user0_, name=user_name, alias=Optional[user_nam8_1_0_]), ColumnProjection(owner=roles1_, name=user_id, alias=Optional[user_id1_2_1_]), ColumnProjection(owner=role2_, name=id, alias=Optional[role_id2_2_1_]), ColumnProjection(owner=role2_, name=id, alias=Optional[id1_0_2_]), ColumnProjection(owner=role2_, name=create_time, alias=Optional[create_t2_0_2_]), ColumnProjection(owner=role2_, name=description, alias=Optional[descript3_0_2_]), ColumnProjection(owner=role2_, name=name, alias=Optional[name4_0_2_]), ColumnProjection(owner=role2_, name=role_key, alias=Optional[role_key5_0_2_]), ColumnProjection(owner=role2_, name=update_time, alias=Optional[update_t6_0_2_])]), groupByContext=org.apache.shardingsphere.sql.parser.binder.segment.select.groupby.GroupByContext@2d70c572, orderByContext=org.apache.shardingsphere.sql.parser.binder.segment.select.orderby.OrderByContext@714045df, paginationContext=org.apache.shardingsphere.sql.parser.binder.segment.select.pagination.PaginationContext@4f9cbea8, containsSubquery=false)
2023-08-05 18:25:55.321  INFO 36856 --- [nio-8081-exec-9] ShardingSphere-SQL                       : Actual SQL: slave0 ::: select user0_.id as id1_1_0_, user0_.create_time as create_t2_1_0_, user0_.description as descript3_1_0_, user0_.email as email4_1_0_, user0_.password as password5_1_0_, user0_.phone_number as phone_nu6_1_0_, user0_.update_time as update_t7_1_0_, user0_.user_name as user_nam8_1_0_, roles1_.user_id as user_id1_2_1_, role2_.id as role_id2_2_1_, role2_.id as id1_0_2_, role2_.create_time as create_t2_0_2_, role2_.description as descript3_0_2_, role2_.name as name4_0_2_, role2_.role_key as role_key5_0_2_, role2_.update_time as update_t6_0_2_ from tb_user user0_ left outer join tb_user_role roles1_ on user0_.id=roles1_.user_id left outer join tb_role role2_ on roles1_.role_id=role2_.id where user0_.id=?

3、进一步理解

通过几个问题进一步理解。

3.1、shardingJDBC的主从分离解决不了什么问题?

  • 主库和从库的数据同步。
  • 主库和从库的数据同步延迟导致的数据不一致。
  • 主库双写或多写。

3.2、读写分离加分库分表?

可以参考官方给的如下配置:

dataSources:ds0: !!org.apache.commons.dbcp.BasicDataSourcedriverClassName: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/ds0username: rootpassword: ds0_slave0: !!org.apache.commons.dbcp.BasicDataSourcedriverClassName: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/ds0_slave0username: rootpassword: ds0_slave1: !!org.apache.commons.dbcp.BasicDataSourcedriverClassName: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/ds0_slave1username: rootpassword: ds1: !!org.apache.commons.dbcp.BasicDataSourcedriverClassName: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/ds1username: rootpassword: ds1_slave0: !!org.apache.commons.dbcp.BasicDataSourcedriverClassName: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/ds1_slave0username: rootpassword: ds1_slave1: !!org.apache.commons.dbcp.BasicDataSourcedriverClassName: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/ds1_slave1username: rootpassword: shardingRule:  tables:t_order: actualDataNodes: ms_ds${0..1}.t_order${0..1}databaseStrategy:inline:shardingColumn: user_idalgorithmExpression: ms_ds${user_id % 2}tableStrategy: inline:shardingColumn: order_idalgorithmExpression: t_order${order_id % 2}keyGenerator:type: SNOWFLAKEcolumn: order_idt_order_item:actualDataNodes: ms_ds${0..1}.t_order_item${0..1}databaseStrategy:inline:shardingColumn: user_idalgorithmExpression: ms_ds${user_id % 2}tableStrategy:inline:shardingColumn: order_idalgorithmExpression: t_order_item${order_id % 2}  bindingTables:- t_order,t_order_itembroadcastTables:- t_configdefaultDataSourceName: ds0defaultTableStrategy:none:defaultKeyGenerator:type: SNOWFLAKEcolumn: order_idmasterSlaveRules:ms_ds0:masterDataSourceName: ds0slaveDataSourceNames:- ds0_slave0- ds0_slave1loadBalanceAlgorithmType: ROUND_ROBINms_ds1:masterDataSourceName: ds1slaveDataSourceNames: - ds1_slave0- ds1_slave1loadBalanceAlgorithmType: ROUND_ROBIN
props:sql.show: true

!! 表示实例化该类

  • 表示可以包含一个或多个

[] 表示数组,可以与减号相互替换使用

4、示例源码

todo

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/27151.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

天津最新python培训班就业形势 python能就业吗?

小编认为Python是一门非常适合学习的编程语言&#xff0c;无论性别如何。它易于学习、功能强大&#xff0c;并且在各个领域都有广泛的应用&#xff0c;因此&#xff0c;性别不应该成为学习Python的障碍&#xff0c;那么学习Python是否就能找到满意的工作呢&#xff1f; 这是一…

大量删除hdfs历史文件导致全部DataNode心跳汇报超时为死亡状态问题解决

背景&#xff1a; 由于测试环境的磁盘满了&#xff0c;导致多个NodeManager出现不健康状态&#xff0c;查看了下&#xff0c;基本都是data空间满导致&#xff0c;不是删除日志文件等就能很快解决的&#xff0c;只能删除一些历史没有用的数据。于是从大文件列表中&#xff0c;找…

深入理解高并发编程 - 线程的生命周期

1、线程的生命周期 线程的生命周期可以分为以下几个阶段&#xff1a; 新建&#xff08;New&#xff09;&#xff1a;线程对象被创建但尚未启动。这是通过实例化Thread类或其子类来实现的。就绪&#xff08;Runnable&#xff09;&#xff1a;线程对象已经创建&#xff0c;并且…

吃瓜教程-Task05

目录 支持向量机 间隔与支持向量 SVM基本型 对偶问题 kkt条件 例子 对偶问题 例子 对偶问题原理解释 软间隔与正则化 替代损失函数 支持向量回归 例子 支持向量机 间隔与支持向量 在样本空间中&#xff0c;划分超平面可通过如下线性方程来描述: 样本空间中任意点x到…

Android WIFI-系统连接WIFI显示网络连接受限

问题描述 使用Android设备打开设置&#xff0c;选择WIFI输入正确密码连接&#xff0c;会显示已连接&#xff0c;无网络&#xff0c;然后变成网络连接受限&#xff0c;实际可以使用此WIFI进行上网。 问题分析 异常Log D NetworkMonitor/100: PROBE_DNS www.google.com 107ms O…

数据结构【哈夫曼树】

哈夫曼树 哈夫曼树的概念哈夫曼树的构造构造算法的实现哈夫曼树应用哈夫曼编码哈夫曼编码的算法实现 哈夫曼树的概念 最优二叉树也称哈夫曼 (Huffman) 树&#xff0c;是指对于一组带有确定权值的叶子结点&#xff0c;构造的具有最小带权路径长度的二叉树。权值是指一个与特定结…

Redis持久化

Redis 持久化 redis 提供了两种持久化的方式&#xff0c;分别是RDB&#xff08;Redis DataBase&#xff09;和AOF&#xff08;Append Only File&#xff09;。 RDB&#xff0c;简而言之&#xff0c;就是在不同的时间点&#xff0c;将 redis 存储的数据生成快照并存储到磁盘等…

MongoDB文档-进阶使用-spring-boot整合使用MongoDB---MongoTemplate完成增删改查

传送门&#xff1a; MongoDB文档--基本概念_一单成的博客-CSDN博客 MongoDB文档--基本安装-linux安装&#xff08;mongodb环境搭建&#xff09;-docker安装&#xff08;挂载数据卷&#xff09;-以及详细版本对比_一单成的博客-CSDN博客 MongoDB文档--基本安装-linux安装&…

[原创]从强化学习的本质推导到PPO

前言 这篇博客很久之前就想做了&#xff0c;一直在拖是因为觉得自己对知识点理解还没有足够的透彻。但是每当去复盘基本概念的时候又很难理清逻辑&#xff0c;所以觉得即便现在半吊子水平&#xff0c;但是也想通过博客记录一下自己肤浅的学习心得&#xff0c;权当是为自己巩固…

加拿大量子研究新动作!D-Wave与滑铁卢大学合作研究量子相干性

​ &#xff08;图片来源&#xff1a;网络&#xff09; D-Wave是量子计算系统、软件和服务的领导者&#xff0c;也是量子计算机的第一家供应商。近期&#xff0c;D-Wave宣布与滑铁卢大学量子计算研究所&#xff08;IQC&#xff09;达成两项新合作。他们为量子计算系统建立了关键…

C/C++面试经历(一)

目录 1. 说说你对C与C的认识&#xff1f; 2. 说说C的三大特性&#xff1f; 3. 说说C的重载&#xff1f; 4. C语言为什么不支持重载&#xff1f; 5. 说说类的默认成员函数&#xff1f; 6. 类的构造函数为什么不支持虚函数&#xff1f; 7. 说说你对指针和引用的理解&…

【计算机网络】网络层协议 -- ICMP协议

文章目录 1. ICMP协议简介2. ICMP协议格式3. ping命令4. ping命令与端口号没有关系&#xff01;&#xff01;&#xff01;5. traceroute命令 1. ICMP协议简介 ICMP&#xff08;Internet Control Message Protocol&#xff0c;控制报文协议&#xff09;&#xff0c;用于在IP主机…

无代码集成明道云与更多应用连接

明道云是一个APaaS平台&#xff0c;可以帮助用户快速搭建个性化企业应用&#xff0c;用户不需要代码开发就能够搭建出用户体验上佳的销售、运营、人事、采购等核心业务应用&#xff0c;打通企业内部数据&#xff0c;也能够通过API和Webhook和其他系统对接。 场景描述&#xff…

libcurl网络库的函数接口使用

文章目录 1、libcurl简介2、libcurl的使用3、函数简介4、 curl_easy_setopt函数部分选项介绍5、curl_easy_perform 函数说明&#xff08;error 状态码&#xff09;6、简单实例,包含库文件&#xff0c;头文件即可 1、libcurl简介 libcurl是一个跨平台的网络协议库&#xff0c;支…

消息队列(3) -封装数据库的操作

前言 上一篇博客我们写了, 关于交换机, 队列,绑定, 写入数据库的一些建库建表的操作 这一篇博客中,我们将建库建表操作,封装一下实现层一个类来供上层服务的调用 , 并在写完该类之后, 测试代码是否完整 实现封装 在写完上述的接口类 与 xml 后, 我们想要 创建一个类 ,来调用…

Python的PyHook3插件使用详解

Python的PyHook3插件使用详解 上代码 上代码 def OnMouseEvent(event):print(MessageName:,event.MessageName)print(Message:,event.Message)print(Time:,event.Time)print(Window:,event.Window)print(WindowName:,event.WindowName)print(Position:,event.Position)print(W…

PAT 1065 A+B and C (64bit)

个人学习记录&#xff0c;代码难免不尽人意。 Given three integers A, B and C in (−263,263), you are supposed to tell whether AB>C. Input Specification: The first line of the input gives the positive number of test cases, T (≤10). Then T test cases foll…

uniapp实现支付宝菜单展开与收起

需求实现支付宝类似的效果&#xff1a; 思路&#xff1a; 1.首先建立展开收起按钮&#xff0c;这里使用的是uview里面的icon图标。 2.其次建立展开菜单内容&#xff0c;这里只演示了文本信息&#xff0c;后期引入首页应用。 3.最后写js逻辑&#xff0c;展开收起时改变盒子高度和…

基于STM32设计的出租车计费系统

一、项目介绍 在城市交通中&#xff0c;出租车是一种常见的交通工具。为了方便乘客和司机之间的交易&#xff0c;出租车计费系统被广泛应用于出租车行业。系统能够自动计算乘客的费用&#xff0c;提供准确、方便的计费服务&#xff0c;并且能够记录乘客的行驶数据&#xff0c;…

flink kafka消费者如何处理kafka主题的rebalance

背景&#xff1a; 我们日常使用kafka客户端消费kafka主题的消息时&#xff0c;当消费者退出/加入消费者组&#xff0c;kafka主题分区数有变等事件发生时&#xff0c;都会导致rebalance的发生&#xff0c;此时一般情况下&#xff0c;如果我们不自己处理offset&#xff0c;我们不…