1.分库分表的相关术语

读写分离:不同的数据库,同步相同的数据,分别只负责数据的读和写。
分区:指定分区列表表达式,把记录拆分到不同的区域中(必须是同一台服务器,可以是不同的硬盘),应用看来还是同一张表,没有变化;
分库:一个系统的多张数据表,存储到多个数据库实例中;
分表:对于一张多行(记录)多列(字段)的二维数据表,分两种:

  • 垂直分表:竖向切分,不同分表存储不同的字段,可以吧不常用或大容量、或者不同业务的字段拆分出去;
  • 水平分表(最复杂的):横向切分,按照特定分片算法,不同分表存储不同的记录;

垂直分表:将一个表按照字段分成多表,每个表存储其中一部分字段。(热数据和冷数据的区分,不会改变数据量)
垂直分库:指按照业务将表进行分类,分布到不同的数据库上面,每个库可以放在不同的服务器上,其核心理念是专库专用。
水平分库:是把同一个表的数据按一定会规则拆分到不同的数据库中,每个库可以放到不同的服务器上。
水平分表:在同一个数据库内,把同一个表的数据按一定规则拆分到多个表中。
逻辑表:进行水平拆分的时候同一类型的表的总称。如两张表tab_user_0和tab_user_1,他们的逻辑表名为tab_user。
真实表:在分片的数据库中真实存在的物理表。如:tab_user_0和tab_user_1。
数据节点:数据分片的最小单元,由数据源名称和数据表组成。如:db_0.tab_user_0或db_0.tab_user_1、db_1.tab_user_0或db_1.tab_user_1。
动态表:逻辑表和物理表不一定需要在配置规则中静态配置。如,按照日期分片的场景,物理表的名称随着时间会产生变化。
广播表(公共表):指所有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中完全一致。适用于数据量大且需要与海量数据的表进行关联查询的场景,如:字典表。
绑定表:指分片规则一致的主表和子表。例如:t_order表和t_order_item表,均按照order_id分片,则此两张表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。

2.分库分表存在什么样的问题?在什么情况下才会采用它?

存在的问题:1)事务一致性的问题;2)跨节点关联查询;3)跨节点分页、排序函数;4)主键避重;5)公共表
分库分表会为数据库维护和业务逻辑带来一系列复杂性和性能损耗,除非预估的业务量大到万不得已,切莫过过度设计,过早优化。
当前数据量如果没有达到几百万,通常无需分库分表;
数据量的问题,可以通过增加磁盘或增加分库(不同的业务的功能表,整表拆分至不同的数据库);
性能的问题,升级CPU/内存、读写分离、优化数据库系统配置、优化数据表/索引、优化SQL、分区、数据表的垂直切分;
**

3.shardingJDBC的执行原理是什么?

shardingJDBC的执行原理.png
SQL解析
分为词法解析和语法解析。 先通过词法解析器将SQL拆分为一个个不可再分的单词。再使用语法解析器对SQL进行理解,并最终提炼出解析上下文。 解析上下文包括表、选择项、排序项、分组项、聚合函数、分页信息、查询条件以及可能需要修改的占位符的标记。
执行器优化
合并和优化分片条件,如OR等。
SQL路由
根据解析上下文匹配用户配置的分片策略,并生成路由路径。目前支持分片路由和广播路由
SQL改写
将SQL改写为在真实数据库中可以正确执行的语句。SQL改写分为正确性改写和优化改写
SQL执行
通过多线程执行器异步执行
结果归并
将多个执行结果集归并以便于通过统一的JDBC接口输出。结果归并包括流式归并内存归并使用装饰者模式的追加归并这几种方式。

4.在你们的项目中shardingJDBC是如何使用的?

XA事务使用shardingJDBC
订单的分库建,分表建设置.png
1.分库字段和分表字段如何确定?
1)在设计表结构的时候,会增加一个sharding_id的字段,这是一个分库键,这个字段保证订单表和订单明细表使用的是同一个值:保证分库算法一致
2)在tab_order和tab_order_item两张表中,因为它两是绑定表关系,并且都有order_no以这个字段作为分表字段,有分表字段可以有效消除笛卡尔积问题。保证分表算法一致。
sharding_id和order_no在分库分表时值是对应的,保证两个表的数据是落在同一个库的同一个表中。

2.创建模块framework-sharding-jdbc

3.framework-sharding-jdbc模块引依赖:

  1. <dependencies>
  2. <!-- 使用XA事务时,需要引入此模块,sharding的本地刚性事务 -->
  3. <dependency>
  4. <groupId>org.apache.shardingsphere</groupId>
  5. <artifactId>sharding-transaction-xa-core</artifactId>
  6. </dependency>
  7. <!-- 使用BASE事务时,需要引入此模块分布式事务的柔性事务 -->
  8. <dependency>
  9. <groupId>org.apache.shardingsphere</groupId>
  10. <artifactId>sharding-transaction-base-seata-at</artifactId>
  11. </dependency>
  12. <!-- sharding-jdbc -->
  13. <dependency>
  14. <groupId>org.apache.shardingsphere</groupId>
  15. <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
  16. </dependency>
  17. </dependencies>

注意:XA事务和BASE事务,两者根据实际情况选择,没有远程调用选XA事务,有远程调用选BASE事务。当引入shardingJDBC后,事务就由seata交给shardingJDBC管理了,所以需要移除seata的依赖。
model-shop-applet模块引入依赖:

  1. <dependency>
  2. <groupId>com.itheima.restkeeper</groupId>
  3. <artifactId>model-security-service</artifactId>
  4. <exclusions>
  5. <exclusion>
  6. <artifactId>druid-spring-boot-starter</artifactId>
  7. <groupId>com.alibaba</groupId>
  8. </exclusion>
  9. </exclusions>
  10. </dependency>
  11. <!--sharding-JDBC 必须使用原生的druid,排除druid-spring-boot-starter-->
  12. <dependency>
  13. <groupId>com.itheima.restkeeper</groupId>
  14. <artifactId>model-shop-service</artifactId>
  15. <exclusions>
  16. <exclusion>
  17. <groupId>com.alibaba</groupId>
  18. <artifactId>druid-spring-boot-starter</artifactId>
  19. </exclusion>
  20. </exclusions>
  21. </dependency>
  22. <!--使用XA事务,则必须移除seata-at依赖-->
  23. <dependency>
  24. <groupId>com.itheima.restkeeper</groupId>
  25. <artifactId>framework-sharding-jdbc</artifactId>
  26. <exclusions>
  27. <exclusion>
  28. <groupId>org.apache.shardingsphere</groupId>
  29. <artifactId>sharding-transaction-base-seata-at</artifactId>
  30. </exclusion>
  31. </exclusions>
  32. </dependency>

4.在model-shop-applet模块的resources文件夹下添加配置application.yml

  1. #服务配置
  2. server:
  3. #端口
  4. port: 7079
  5. #服务编码
  6. tomcat:
  7. uri-encoding: UTF-8
  8. #spring相关配置
  9. spring:
  10. main:
  11. allow-bean-definition-overriding: true
  12. redis:
  13. redisson:
  14. config: classpath:singleServerConfig.yaml
  15. #redis配置信息
  16. host: 192.168.200.129
  17. port: 6379
  18. password: pass
  19. jta:
  20. atomikos:
  21. properties:
  22. log-base-dir: logs/model-shop-applet-atomikos
  23. log-base-name: model-shop-applet
  24. #数据源配置
  25. shardingsphere:
  26. datasource:
  27. names: ds0,ds1
  28. ds0:
  29. type: com.alibaba.druid.pool.DruidDataSource
  30. driverClassName: com.mysql.jdbc.Driver
  31. url: jdbc:mysql://192.168.200.129:3306/restkeeper-shop-0?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
  32. username: root
  33. password: pass
  34. ds1:
  35. type: com.alibaba.druid.pool.DruidDataSource
  36. driverClassName: com.mysql.jdbc.Driver
  37. url: jdbc:mysql://192.168.200.151:3306/restkeeper-shop-1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
  38. username: root
  39. password: root
  40. #分库分表
  41. sharding:
  42. tables:
  43. tab_order: #数据库中要分表的逻辑名
  44. actualDataNodes: ds${0..1}.tab_order_${0..1}
  45. databaseStrategy:
  46. inline:
  47. shardingColumn: sharding_id
  48. algorithmExpression: ds${sharding_id % 2}
  49. tableStrategy:
  50. inline:
  51. shardingColumn: order_no
  52. algorithmExpression: tab_order_${order_no % 2}
  53. keyGenerator:
  54. type: SNOWFLAKE
  55. column: id
  56. tab_order_item: #数据库中要分表的逻辑名
  57. actualDataNodes: ds${0..1}.tab_order_item_${0..1}
  58. databaseStrategy:
  59. inline:
  60. shardingColumn: sharding_id
  61. algorithmExpression: ds${sharding_id % 2}
  62. tableStrategy:
  63. inline:
  64. shardingColumn: product_order_no
  65. algorithmExpression: tab_order_item_${product_order_no % 2}
  66. keyGenerator:
  67. type: SNOWFLAKE
  68. column: id
  69. binding-tables:
  70. - tab_order
  71. - tab_order_item
  72. broadcast-tables:
  73. - tab_brand
  74. - tab_category
  75. - tab_dish
  76. - tab_dish_flavor
  77. - tab_printer
  78. - tab_printer_dish
  79. - tab_store
  80. - tab_table
  81. - tab_table_area
  82. - undo_log
  83. default-key-generator:
  84. type: SNOWFLAKE
  85. column: id
  86. props:
  87. sql.show: true
  88. #mybatis配置
  89. mybatis-plus:
  90. # MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名
  91. type-aliases-package: com.itheima.springcloud.pojo
  92. # 该配置请和 typeAliasesPackage 一起使用,如果配置了该属性,则仅仅会扫描路径下以该类作为父类的域对象 。
  93. type-aliases-super-type: com.itheima.restkeeper.basic.BasicPojo
  94. configuration:
  95. # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
  96. log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  97. # 驼峰下划线转换
  98. map-underscore-to-camel-case: true
  99. use-generated-keys: true
  100. default-statement-timeout: 60
  101. default-fetch-size: 100
  102. #忽略商户号表
  103. ignore-enterprise-tables:
  104. - tab_brand
  105. - tab_category
  106. - tab_dish
  107. - tab_dish_flavor
  108. - tab_order
  109. - tab_order_item
  110. - tab_printer
  111. - tab_printer_dish
  112. - tab_store
  113. - tab_table
  114. - tab_table_area
  115. - tab_role
  116. - tab_order_role
  117. - undo_log
  118. #忽略门店号表
  119. ignore-store-tables:
  120. - tab_brand
  121. - tab_category
  122. - tab_dish
  123. - tab_dish_flavor
  124. - tab_order
  125. - tab_order_item
  126. - tab_printer
  127. - tab_printer_dish
  128. - tab_store
  129. - tab_table
  130. - tab_table_area
  131. - tab_role
  132. - tab_order_role
  133. - undo_log
  134. logging:
  135. config: classpath:logback.xml
  136. dubbo:
  137. application:
  138. version: 1.0.0
  139. logger: slf4j
  140. scan:
  141. base-packages: com.itheima.restkeeper
  142. registry:
  143. address: spring-cloud://192.168.200.129
  144. protocol:
  145. #指定二进制协议
  146. name: dubbo
  147. port: 27079
  148. threads: 200
  149. accesslog: logs/model-shop-applet-01.log

5.在resources文件夹下添加jta.properties 这个文件的作用是什么?待问

  1. com.atomikos.icatch.output_dir=D:/atomikos/model-shop-applet
  2. com.atomikos.icatch.log_base_dir=D:/atomikos/model-shop-applet

6.在AppletFaceImpl类中需要事务的方法上添加@ShardingTransactionType(TransactionType.XA)注解。注意:如果是分布式事务TransactionType.XA改为TransactionType.BASE

seata-at使用shardingJDBC
1.创建模块framework-sharding-jdbc
2.引入依赖

  1. <dependency>
  2. <groupId>com.itheima.restkeeper</groupId>
  3. <artifactId>model-shop-service</artifactId>
  4. <exclusions>
  5. <exclusion>
  6. <groupId>com.alibaba</groupId>
  7. <artifactId>druid-spring-boot-starter</artifactId>
  8. </exclusion>
  9. </exclusions>
  10. </dependency>
  11. <dependency>
  12. <groupId>com.itheima.restkeeper</groupId>
  13. <artifactId>framework-sharding-jdbc</artifactId>
  14. <exclusions>
  15. <exclusion>
  16. <groupId>org.apache.shardingsphere</groupId>
  17. <artifactId>sharding-transaction-xa-core</artifactId>
  18. </exclusion>
  19. </exclusions>
  20. </dependency>

3.在model-shop-producer模块中的resource文件夹下添加application.yml

  1. #服务配置
  2. server:
  3. #端口
  4. port: 7077
  5. #服务编码
  6. tomcat:
  7. uri-encoding: UTF-8
  8. #spring相关配置
  9. spring:
  10. #应用配置
  11. application:
  12. #应用名称
  13. name: model-shop-producer
  14. main:
  15. allow-bean-definition-overriding: true
  16. redis:
  17. redisson:
  18. config: classpath:singleServerConfig.yaml
  19. #redis配置信息
  20. host: 192.168.200.129
  21. port: 6379
  22. password: pass
  23. cloud:
  24. alibaba:
  25. seata:
  26. tx-service-group: project_tx_group
  27. jta:
  28. atomikos:
  29. properties:
  30. log-base-dir: logs/model-shop-producer-atomikos
  31. log-base-name: model-shop-producer
  32. #数据源配置
  33. shardingsphere:
  34. datasource:
  35. names: ds0,ds1
  36. ds0:
  37. type: com.alibaba.druid.pool.DruidDataSource
  38. driverClassName: com.mysql.jdbc.Driver
  39. url: jdbc:mysql://192.168.200.129:3306/restkeeper-shop-0?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
  40. username: root
  41. password: pass
  42. ds1:
  43. type: com.alibaba.druid.pool.DruidDataSource
  44. driverClassName: com.mysql.jdbc.Driver
  45. url: jdbc:mysql://192.168.200.151:3306/restkeeper-shop-1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
  46. username: root
  47. password: root
  48. #分库分表
  49. sharding:
  50. tables:
  51. tab_order: #数据库中要分表的逻辑名
  52. actualDataNodes: ds${0..1}.tab_order_${0..1}
  53. databaseStrategy:
  54. inline:
  55. shardingColumn: sharding_id
  56. algorithmExpression: ds${sharding_id % 2}
  57. tableStrategy:
  58. inline:
  59. shardingColumn: order_no
  60. algorithmExpression: tab_order_${order_no % 2}
  61. keyGenerator:
  62. type: SNOWFLAKE
  63. column: id
  64. tab_order_item: #数据库中要分表的逻辑名
  65. actualDataNodes: ds${0..1}.tab_order_item_${0..1}
  66. databaseStrategy:
  67. inline:
  68. shardingColumn: sharding_id
  69. algorithmExpression: ds${sharding_id % 2}
  70. tableStrategy:
  71. inline:
  72. shardingColumn: product_order_no
  73. algorithmExpression: tab_order_item_${product_order_no % 2}
  74. keyGenerator:
  75. type: SNOWFLAKE
  76. column: id
  77. binding-tables:
  78. - tab_order
  79. - tab_order_item
  80. broadcast-tables:
  81. - tab_brand
  82. - tab_category
  83. - tab_dish
  84. - tab_dish_flavor
  85. - tab_printer
  86. - tab_printer_dish
  87. - tab_store
  88. - tab_table
  89. - tab_table_area
  90. - undo_log
  91. default-key-generator:
  92. type: SNOWFLAKE
  93. column: id
  94. props:
  95. sql.show: true
  96. #mybatis配置
  97. mybatis-plus:
  98. # MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名
  99. type-aliases-package: com.itheima.springcloud.pojo
  100. # 该配置请和 typeAliasesPackage 一起使用,如果配置了该属性,则仅仅会扫描路径下以该类作为父类的域对象 。
  101. type-aliases-super-type: com.itheima.restkeeper.basic.BasicPojo
  102. configuration:
  103. # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
  104. log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  105. # 驼峰下划线转换
  106. map-underscore-to-camel-case: true
  107. use-generated-keys: true
  108. default-statement-timeout: 60
  109. default-fetch-size: 100
  110. #忽略商户号表
  111. ignore-enterprise-tables:
  112. - tab_dish_flavor
  113. - tab_order_item
  114. - undo_log
  115. #忽略门店号表
  116. ignore-store-tables:
  117. - tab_dish_flavor
  118. - tab_brand
  119. - tab_order_item
  120. - tab_store
  121. - undo_log
  122. seata:
  123. tx-service-group: project_tx_group
  124. enabled: true
  125. application-id: ${spring.application.name}
  126. # **注意:此处必须设置为 false,将数据源的代理权限交给sharding-jdbc管理
  127. enable-auto-data-source-proxy: false
  128. service:
  129. #这里的名字与file.conf中vgroup_project_tx_group = "default"相同
  130. vgroup-mapping:
  131. project_tx_group: default
  132. #这里的名字与file.conf中default.grouplist = "192.168.200.129:8091"相同
  133. grouplist:
  134. default: 192.168.200.129:9200
  135. config:
  136. type: nacos
  137. nacos:
  138. group: SEATA_GROUP
  139. server-addr: 192.168.200.129:8848
  140. username: nacos
  141. password: nacos
  142. registry:
  143. type: nacos
  144. nacos:
  145. group: SEATA_GROUP
  146. server-addr: 192.168.200.129:8848
  147. username: nacos
  148. password: nacos
  149. dubbo:
  150. #dubbo应用服务定义
  151. application:
  152. #版本
  153. version: 1.0.0
  154. #日志
  155. logger: slf4j
  156. scan:
  157. #扫描路径
  158. base-packages: com.itheima.restkeeper
  159. registry:
  160. #注册中心
  161. address: spring-cloud://192.168.200.129
  162. #服务协议定义
  163. protocol:
  164. #服务协议名称
  165. name: dubbo
  166. #协议端口
  167. port: 27077
  168. #线程数
  169. threads: 200
  170. #dubbo调用日志
  171. accesslog: logs/model-shop-producer-01.log

注意: enable-auto-data-source-proxy: false在seata中一定要写false,因为引入sharding-jdbc后事务就是由sharding-jdbc管理了,而不是seata。
4.添加jta.properties 这个文件的作用是什么?待问

  1. com.atomikos.icatch.output_dir=D:/atomikos/model-shop-producer
  2. com.atomikos.icatch.log_base_dir=D:/atomikos/model-shop-producer

5.在resource路径下添加seata.conf 这个文件的作用是什么?待问

  1. client {
  2. application.id = model-shop-producer
  3. transaction.service.group = project_tx_group
  4. }

6.在需要事务的方法上添加注解@ShardingTransactionType(TransactionType.BASE)

5.在项目中分片键的值是怎么设置的?

采用了分片键回填机制,mybatis-plus提供了一个MetaObjectHandler接口(作用是在插入或更新数据的时候为一些字段指定默认值),有两个方法void insertFill(MetaObject metaObject)插入时自动填充和void updateFill(MetaObject metaObject)更新时自动填充。
在项目中自定义了一个类来实现这个接口,并且引入了mybatisplus的雪花算法IdentifierGenerator解决了分片键值设置的问题。不能采用自动回填机制,这样会导致每个表的sharding_id都是1.2.3.4…,在分片策略(对数取余)下,最终会导致数据分布不均匀,影响性能。