范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

给小白演示分库分表案例

  受群里小伙伴之邀,搞一个分库分表案例,这样让很多没用过分库分表的心里也有个底,不然永远看到的都是网上的各种概念和解决方案性的文章。 需求
  由于用户表过于庞大,采取相关SQL优化,还是不能满足,所以现对其进行做分库分表。
  数据库: my-sharding
  数据库表: t_user
  建表语句如下: DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` (   `id` bigint NOT NULL AUTO_INCREMENT,   `user_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,   `age` int NOT NULL,   `gender` int NOT NULL,   PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
  关于数据库分库分表通常有两种方案: 垂直拆分 水平拆分
  下面我们来演示水平拆分,大致思路: 通过  t_user  表的id进行 hash  ,然后再和数据库个数进行取模,得出对应数据库。
  通过hash值和每个数据库中表的个数进行取模,得出对应表名。  创建数据库和表
  加入有2000万条数据,那么为了方便演示,我们就暂定分为五个库,每个数据库对应五个表。 理想状态:2000万/5/4,那么每个数据库分得400万,每个表分得80万。
  总之,分库分表后,我们的每一张表的数据库和表都与之前的确实不是一个量级了。
  五个数据库:
  每个数据库有五张表:
  建表语句如下:  DROP TABLE IF EXISTS `t_user_0`; CREATE TABLE `t_user_0` (   `id` bigint NOT NULL AUTO_INCREMENT,   `user_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,   `age` int NOT NULL,   `gender` int NOT NULL,   PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;  DROP TABLE IF EXISTS `t_user_1`; CREATE TABLE `t_user_1` (   `id` bigint NOT NULL AUTO_INCREMENT,   `user_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,   `age` int NOT NULL,   `gender` int NOT NULL,   PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;  DROP TABLE IF EXISTS `t_user_2`; CREATE TABLE `t_user_2` (   `id` bigint NOT NULL AUTO_INCREMENT,   `user_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,   `age` int NOT NULL,   `gender` int NOT NULL,   PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;   DROP TABLE IF EXISTS `t_user_3`; CREATE TABLE `t_user_3` (   `id` bigint NOT NULL AUTO_INCREMENT,   `user_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,   `age` int NOT NULL,   `gender` int NOT NULL,   PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;   DROP TABLE IF EXISTS `t_user_4`; CREATE TABLE `t_user_4` (   `id` bigint NOT NULL AUTO_INCREMENT,   `user_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,   `age` int NOT NULL,   `gender` int NOT NULL,   PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; 项目创建
  使用技术栈: JDK8 +MySQL +Spring Boot  +Mybatis  +Shardingsphere  +Druid
  maven 相关依赖:      org.springframework.boot  spring-boot-starter-web    org.mybatis.spring.boot  mybatis-spring-boot-starter  2.1.0        org.mybatis   mybatis   3.5.2      mysql   mysql-connector-java   8.0.16   runtime         com.github.pagehelper    pagehelper-spring-boot-starter    1.2.3      org.springframework.boot    spring-boot-starter-test    test      org.apache.shardingsphere    sharding-jdbc-spring-boot-starter    4.0.1      com.alibaba    druid    1.1.17      com.google.guava    guava    29.0-jre 
  配置文件相关配置如下:  server.port=9002 mybatis.mapper-locations=classpath:/mapper/*.xml # mybatis.type-aliases-package=com.neutral.idmapping.dbshard.pojo  ##### 连接池配置 ####### # 过滤器设置(第一个stat很重要,没有的话会监控不到SQL) spring.datasource.druid.filters=stat,wall,log4j2 ##### WebStatFilter配置 ####### #启用StatFilter spring.datasource.druid.web-stat-filter.enabled=true #添加过滤规则 spring.datasource.druid.web-stat-filter.url-pattern=/* #排除一些不必要的url spring.datasource.druid.web-stat-filter.exclusions=*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/* #开启session统计功能 spring.datasource.druid.web-stat-filter.session-stat-enable=true #缺省sessionStatMaxCount是1000个 spring.datasource.druid.web-stat-filter.session-stat-max-count=1000 #spring.datasource.druid.web-stat-filter.principal-session-name= #spring.datasource.druid.web-stat-filter.principal-cookie-name= #spring.datasource.druid.web-stat-filter.profile-enable=  ##### StatViewServlet配置 ####### #启用内置的监控页面 spring.datasource.druid.stat-view-servlet.enabled=true #内置监控页面的地址 spring.datasource.druid.stat-view-servlet.url-pattern=/druid/* #关闭 Reset All 功能 spring.datasource.druid.stat-view-servlet.reset-enable=false #设置登录用户名 spring.datasource.druid.stat-view-servlet.login-username=admin #设置登录密码 spring.datasource.druid.stat-view-servlet.login-password=admin  spring.shardingsphere.props.sql.show=false #数据库名 spring.shardingsphere.datasource.names=dp0,dp1,dp2,dp3,dp4 #datasource spring.shardingsphere.datasource.dp0.type=com.alibaba.druid.pool.DruidDataSource spring.shardingsphere.datasource.dp0.driver-class-name=com.mysql.jdbc.Driver spring.shardingsphere.datasource.dp0.url=jdbc:mysql://localhost:3306/my-sharding_0?useUnicode=true&characterEncoding=utf-8&serverTimeZone=CTT&allowPublicKeyRetrieval=true&serverTimezone=UTC spring.shardingsphere.datasource.dp0.username=root spring.shardingsphere.datasource.dp0.password=123456   ----------相同的代码部分这里就不贴了------- # 对应 dp1、dp2、dp3、dp4 和上面dp0配置类似,不一样的就是数据库名字不一样 # 因为我使用的本地创建多个数据库演示的,这里就没有必要重复累赘了  #actual-data-nodes #这里是配置所有的 库.表 的集合 #比如我这里配置的意思是 dp0.data_0 , dp0.data_1 ,dp0.data_2 , ... #此缩写方式使用了shardingsphere 官方推荐的语法 #t_user 逻辑表名  在UserMapper.xml中使用 spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=dp$->{0..4}.t_user_$->{0..4} #table #设置了以data中字段id作为分表的标准,这样到时候就会将id作为参数传入到下面配置的我们自定义的分表方法中做具体操 spring.shardingsphere.sharding.tables.t_user.table-strategy.standard.sharding-column=id spring.shardingsphere.sharding.tables.t_user.table-strategy.standard.precise-algorithm-class-name=com.tian.shardingdemo.common.TableShardingAlgorithm #database #设置了以data中字段id作为分库的标准,这样到时候就会将id作为参数传入到下面配置的我们自定义的分库方法中做具体操作 spring.shardingsphere.sharding.tables.t_user.database-strategy.standard.sharding-column=id spring.shardingsphere.sharding.tables.t_user.database-strategy.standard.precise-algorithm-class-name=com.tian.shardingdemo.common.DbShardingAlgorithm
  分库分表的两个分片类: /**  * 分库  */ public class DbShardingAlgorithm implements PreciseShardingAlgorithm {      private Logger logger = LoggerFactory.getLogger(DbShardingAlgorithm.class);      @Override     public String doSharding(Collection availableTargetNames, PreciseShardingValue shardingValue) {         String databaseName = availableTargetNames.stream().findFirst().get();         for (String dbName : availableTargetNames) {             //shardingValue.getValue()就是配置的传入的值             //我们这里选用的是传入sql中的id字段的值             String targetDbName= "dp" + genderToTableSuffix(shardingValue.getValue());             if (dbName.equals(targetDbName)) {                 //匹配到对应的数据库,比如 dp0                 //这个数据库名对应数据源处配置的dp0,dp1,...                 logger.info("数据库名=" + dbName);                 databaseName = dbName;             }         }         return databaseName;     }      private String genderToTableSuffix(Long value) {         //将id字段的值去hash值后去模运算得到分库的数字(就是一种算法而已)         int i = Hashing.murmur3_128(1823977).newHasher().putString(String.valueOf(value), Charsets.UTF_8).hash().asInt();         //hash与表个数进行取模         return String.valueOf(Math.abs(i) % 5);     } } /**  * 分表  */ public class TableShardingAlgorithm implements PreciseShardingAlgorithm {     private Logger logger = LoggerFactory.getLogger(TableShardingAlgorithm.class);      @Override     public String doSharding(Collection availableTargetNames, PreciseShardingValue shardingValue) {         String table = availableTargetNames.stream().findFirst().get();         String targetName = "t_user_" + genderToTableSuffix(shardingValue.getValue());         for (String tableName : availableTargetNames) {             //检查计算出来的表名是否存在             if (tableName.equals(targetName)) {                 logger.info("表名= " + tableName);                 table = tableName;             }         }         return table;     }      private String genderToTableSuffix(Long value) {         //算出一个hash值 int类型         int i = Hashing.murmur3_128(8947189).newHasher().putString(String.valueOf(value), Charsets.UTF_8).hash().asInt();         //hash与表个数进行取模         return String.valueOf(Math.abs(i) % 5);     } }
  下面是业务部分代码,先看 UserMapper.xml 内容:<?xml version="1.0" encoding="UTF-8" ?>                                            INSERT INTO t_user (id, user_name,age,gender) VALUES ( #{id},#{userName},#{age},#{gender}         );                         update t_user                                       `user_name` = #{userName},                                           gender = #{gender},                                           age = #{age},                               where id=#{id}      
  UserMapper 接口:import com.tian.shardingdemo.entity.User; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository;  @Mapper @Repository public interface UserMapper {      User selectUserById(@Param("id") Long id);      int updateAuthorIfNecessary(User user);      int insert(User user); }
  为了更好地演示,我这里加入了 controller 层和service 层,这也是大家平常开发套路。
  service 层代码如下:public interface IUserService {      User selectUserById(Long id);      void add(Long id); } @Service public class UserServiceImpl implements IUserService {      @Resource     private UserMapper userMapper;     @Override     public User selectUserById(Long id) {         return userMapper.selectUserById(id);     }      @Override     public void add(Long id) {         User user = new User();         user.setAge(22);         user.setGender(1);         user.setId(id);         user.setUserName("tian" + id);         userMapper.insert(user);     } }
  controller层代码如下: @RestController @RequestMapping public class UserController {      @Resource     private IUserService userService;      @RequestMapping(value = "/user/{id}", method = RequestMethod.GET)     public User selectUserById(@PathVariable("id") Long id) {         return userService.selectUserById(id);     }      @PostMapping("/add")     public Object add(@RequestBody Map params) {         Long id = params.get("id");         userService.add(id);         return "ok";     } }
  最后是项目的启动类: @SpringBootApplication @MapperScan({"com.tian.shardingdemo.mapper"}) public class ShardingDemoApplication {   public static void main(String[] args) {   SpringApplication.run(ShardingDemoApplication.class, args);  } }
  启动项目,启动成功:
  下面我们来演示一下新增数据和查询。 添加数据到数据库中
  先来添加数据到数据库中,这里使用的是IDEA中restful工具:
  后台日志:
  再查看数据库表中:
  到此,我们的数据依旧落库,下面我们来演示一下数据查询。 数据查询
  浏览器里输入: http://localhost:9002/user/7
  返回数据: {"id":7,"userName":"tian7","age":22,"gender":1}
  后台日志:
  从日志和返回结果可以看出,已经为我们正确的选择到对应的数据库和表了,这样,一个分库分表的查询就成功了。 总结
  本文没有太多的概念,直接使用案例演示。相关概念性的文章,还有分库分表解决方案的文章,网上一堆堆的,感兴趣可以自行查阅。

银行卡冻结限制非柜面交易那是你触发了风控一储蓄卡风控银行卡被限制非柜交易,是银行系统发出的风控指令。主要是为了配合当前电信金融诈骗行为而作出的一大举措。也许大家收到银行卡交易限制信息之后,有一种莫名其妙的感觉。自己的卡平房地产暴利时代结束,但房价不会因此下跌以前房地产是一个暴利行业,房地产高速发展时期造就了许多财富传奇。现在人们津津乐道许老板就是各种代表。在许老板鼎盛时期,一度成为国内首富。足以看出房地产的暴利。不过这种暴利时代已经过解决用户痛点,换电的春天一定会来临撰文钱亚光编辑张南设计赵昊然7月12日,蔚能BaaS(BatteryasaService)服务合作签约会上,蔚能与江淮汽车集团思皓新能源泽清新能源招银云创福田汽车智程运力吉利商用车高管嘴仗带火增程式混动技术日近舞台中央北京日报客户端记者赵语涵近日,华为常务董事余承东与长城魏牌CEO李瑞峰的一场意见交锋让增程式这一名词进入了更多人的视野。在近日的一场问界M7的上市发布会上,余承东为夸自家产品,声称人民日报夜读丰富自己的三件事去靠近去努力去经历早上读了人民日报出版的文章丰富自己的三件事去靠近去努力去经历,读完之后,想了很多,好像又没想很多。想了很多,是因为在读书的过程中,好多想法在大脑中闪现。没想很多,是因为读完之后,这唯美诗80后,你会爱了吗80后你会爱了吗三十而立之意你是否了解它的意境物是人非言犹在耳君心已变的故事在你身上是否经历过几许80后你会爱了吗放下了就释然了你是否能理解它的真意理想的爱界海枯石烂的恋情你是否还这就是人生有一种坚强叫笑给别人看,哭给自己听,用笑容掩饰悲伤。人生在世,不顺心的事常有,谁都有无法言语的心酸,谁都有不可言喻的伤痛,放在心里,太憋屈,倾诉出来,不放心。宁可忍的心累,不愿说的年轻人,请收起你的懦弱大家好,麦田里的晚风第236篇文章,记得点赞与关注,不断为你分享生活哲理与乐趣。每个人心中都藏着一个了不起的自己,怀揣着梦想向未来走去。在每一个平凡而不平淡的日子里,努力寻找自己的网易历时6年!经典MMO天下3上线Steam12月21据Steam商店页面显示,网易游戏出品的经典MMORPG天下3将于12月21日上线Steam平台,玩家们不要错过。宣传片游戏介绍天下3是网易历时6年,耗资过亿开发的国内第一款绿色免微信又上线新功能朋友圈有大变化经过10余年的发展与完善,微信的功能也是越来越丰富,几乎涵盖了我们日常生活中的方方面面。近日,微信又在灰度内测一项新的功能和谁一起。被内测到的用户在发朋友圈时会出现一个和谁一起的新拍摄优秀荣耀70Pro上线,荣耀60让路新机一夜跌至白菜价荣耀70Pro整体的成像风格,还是很荣耀家族特色的。通过AI优化加强,直出色彩讨喜,很适合日常直接拍摄和分享。而这次三颗镜头的素质表现也都更加不错,微距和长焦,也都有更好的细腻呈现
如果选秀大会前送不走沃尔,火箭会和他协商买断据露天看台体育记者JakeFischer报道,如果31岁的约翰沃尔像预期的那样执行他在202223赛季价值4740万美元的球员选项,那么对火箭来说,送走他可能比湖人送走威少更具挑战伤病潮!上赛季总决赛球队均折损核心布克米德尔顿因伤无缘首轮去年的总决赛,雄鹿和太阳队鏖战6场。今年两队依然是争冠的大热门,但季后赛首轮,两队均遭遇了严重的伤病问题,甚至能否突破首轮都要画上问号。雄鹿方面,米德尔顿在与公牛的G2中受伤,他在斯诺克世锦赛第二轮第一阶段结束!赵心童陷入苦战暂时落后马奎尔2022斯诺克世锦赛精彩继续!第二轮的比赛开启!第二轮采用25局13胜,分三个阶段进行。中国球员赵心童率先出战,第一阶段比赛结束,赵心童暂时落后,另外一场马克威廉姆斯大比分领先。赵狂野西部!2场21,1场30,太阳首轮悬了,勇士成大赢家NBA季后赛正在火热进行中,各队都在为争夺总冠军努力!而在西部,季后赛首轮就发生了很大的变化!勇士30领先掘金灰熊21领先森林狼,独行侠21领先爵士,鹈鹕11战平太阳。目前的西部,布克伤缺23周,太阳首轮危矣据今天NBA消息,太阳当家球星布克腿筋拉伤,可能缺阵23周时间,缺少季后赛场均28分的攻坚利器,太阳极有可能被黑八,为什么这么说呢?首先太阳虽然说阵容看起来不错,但实际上缺陷很多,世锦赛8强首人!三冠王133疯狂吊打黑马,轰6杆破百全场欢呼北京时间4月22日,斯诺克世锦赛来到18决赛的争夺。在率先结束的一场比赛中,世锦赛3冠王马克威廉姆斯打出了非常劲爆的表现。面对世界排名第90位的黑马佩奇,金左手在第一阶段71领先的航天城再次飞起!状元热门宣布参加选秀,他是休斯顿火箭的粉丝时间是最难以留住的东西,不知不觉中虎年一下子就来到了四月下旬,而NBA已经进入了季后赛第一轮这个阶段,各支球队正在互相厮杀,以期取得一个好成绩备受球迷关注的休斯顿火箭队却早早前往河冬奥训练主管吴小萌从冰坛回到地坛,让冬奥经验继续发光生活中的吴小萌。受访者供图2月4日,农历大年初四晚上,2022年北京冬奥会开幕式在国家体育场鸟巢举行。候场时,坐在观众席的吴小萌觉得有点冷,她向同行的志愿者借了件外套披在身上。当五冬奥训练主管吴小萌从冰坛回到地坛,让冬奥经验继续发光生活中的吴小萌。受访者供图2月4日,农历大年初四晚上,2022年北京冬奥会开幕式在国家体育场鸟巢举行。候场时,坐在观众席的吴小萌觉得有点冷,她向同行的志愿者借了件外套披在身上。当五追梦我一直在说真正的好球员会闪耀客场并有所发挥直播吧4月22日讯在今天结束的一场NBA季后赛,勇士战胜了掘金,大比分30领先。在赛后接受采访时,追梦这样说道我总是在说,真正的好球员,他们会在客场闪耀,他们会在客场有所发挥。在谈追梦我一直在说真正的好球员会闪耀客场并有所发挥直播吧4月22日讯在今天结束的一场NBA季后赛,勇士战胜了掘金,大比分30领先。在赛后接受采访时,追梦这样说道我总是在说,真正的好球员,他们会在客场闪耀,他们会在客场有所发挥。在谈