From 78f4f7bafb4e9d350fefc2ce5a41f6de7678f361 Mon Sep 17 00:00:00 2001 From: hqqich Date: Sat, 3 Feb 2024 20:40:10 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- blog/dist/404.html | 8 +-- blog/dist/assets/404.html-3afd45f4.js | 1 + ....html-98ecc787.js => 404.html-3ebe33b7.js} | 2 +- blog/dist/assets/404.html-d25048b5.js | 1 - .../{app-48e592bc.js => app-0009cf46.js} | 20 +++---- blog/dist/assets/day01.html-08915fe7.js | 1 + blog/dist/assets/day01.html-40ef3352.js | 3 + blog/dist/assets/day01.html-55eb354f.js | 3 - blog/dist/assets/day01.html-5b3d75e2.js | 1 - blog/dist/assets/day02.html-16f7422e.js | 1 - blog/dist/assets/day02.html-8d6bc722.js | 1 - blog/dist/assets/day03.html-8bf052f3.js | 1 - blog/dist/assets/day03.html-fbe757fe.js | 1 - blog/dist/assets/day04.html-b068227c.js | 1 - blog/dist/assets/day04.html-d99e9bf2.js | 1 - blog/dist/assets/day05.html-019a29ca.js | 1 - blog/dist/assets/day05.html-b3eb6724.js | 10 ---- blog/dist/assets/day06.html-435a8053.js | 1 - blog/dist/assets/day06.html-46d99ff3.js | 1 - blog/dist/assets/day07~day08.html-99b6eb19.js | 1 - blog/dist/assets/day07~day08.html-af1acce9.js | 1 - blog/dist/assets/day09~day10.html-ea2643e5.js | 1 - blog/dist/assets/day09~day10.html-fca95bc7.js | 1 - blog/dist/assets/day11.html-22b3645c.js | 1 - blog/dist/assets/day11.html-bf0a77d6.js | 1 - blog/dist/assets/day12.html-ca956336.js | 1 - blog/dist/assets/day12.html-fd07949c.js | 15 ----- blog/dist/assets/icon/apple-icon-152.png | Bin 3568 -> 0 bytes blog/dist/assets/icon/chrome-192.png | Bin 4733 -> 0 bytes blog/dist/assets/icon/chrome-512.png | Bin 13251 -> 0 bytes blog/dist/assets/icon/chrome-mask-192.png | Bin 4755 -> 0 bytes blog/dist/assets/icon/chrome-mask-512.png | Bin 13040 -> 0 bytes blog/dist/assets/icon/guide-maskable.png | Bin 2270 -> 0 bytes blog/dist/assets/icon/ms-icon-144.png | Bin 3657 -> 0 bytes blog/dist/assets/index.html-2448c597.js | 1 - blog/dist/assets/index.html-408426f6.js | 1 - blog/dist/assets/index.html-5385c67b.js | 1 + blog/dist/assets/index.html-8542c835.js | 1 + blog/dist/assets/index.html-8daec251.js | 1 + ...tml-fe05aaa1.js => index.html-964d1ecc.js} | 2 +- ...tml-09a8d92e.js => index.html-ad5460d9.js} | 2 +- blog/dist/assets/index.html-b25c80fe.js | 1 - ...tml-970a5d45.js => index.html-b50e8a62.js} | 2 +- blog/dist/assets/resume.html-5daad762.js | 1 - blog/dist/assets/resume.html-7640e47a.js | 1 + blog/dist/assets/resume.html-76c4384e.js | 1 - blog/dist/assets/resume.html-b1aba35a.js | 1 + blog/dist/assets/slides.html-141feb08.js | 1 + ...ml-2a1d1365.js => slides.html-86266226.js} | 2 +- blog/dist/assets/slides.html-a8da665a.js | 1 - blog/dist/favicon.ico | Bin 67646 -> 86358 bytes blog/dist/index.html | 8 +-- blog/dist/logo.png | Bin 94186 -> 0 bytes blog/dist/md/dev-log/day01.html | 10 ++-- blog/dist/md/dev-log/day02.html | 40 ------------- blog/dist/md/dev-log/day03.html | 40 ------------- blog/dist/md/dev-log/day04.html | 40 ------------- blog/dist/md/dev-log/day05.html | 49 ---------------- blog/dist/md/dev-log/day06.html | 40 ------------- blog/dist/md/dev-log/day07~day08.html | 40 ------------- blog/dist/md/dev-log/day09~day10.html | 40 ------------- blog/dist/md/dev-log/day11.html | 40 ------------- blog/dist/md/dev-log/day12.html | 54 ------------------ blog/dist/md/dev-log/index.html | 8 +-- blog/dist/md/index.html | 8 +-- blog/dist/md/resume.html | 8 +-- blog/dist/sitemap.xml | 2 +- blog/dist/sitemap.xsl | 5 +- blog/dist/slides.html | 6 +- .../public/assets/icon/apple-icon-152.png | Bin 3568 -> 0 bytes .../public/assets/icon/chrome-192.png | Bin 4733 -> 0 bytes .../public/assets/icon/chrome-512.png | Bin 13251 -> 0 bytes .../public/assets/icon/chrome-mask-192.png | Bin 4755 -> 0 bytes .../public/assets/icon/chrome-mask-512.png | Bin 13040 -> 0 bytes .../public/assets/icon/guide-maskable.png | Bin 2270 -> 0 bytes .../public/assets/icon/ms-icon-144.png | Bin 3657 -> 0 bytes blog/src/.vuepress/public/favicon.ico | Bin 67646 -> 86358 bytes blog/src/.vuepress/public/logo.png | Bin 94186 -> 0 bytes blog/src/README.md | 2 +- 79 files changed, 59 insertions(+), 482 deletions(-) create mode 100644 blog/dist/assets/404.html-3afd45f4.js rename blog/dist/assets/{404.html-98ecc787.js => 404.html-3ebe33b7.js} (71%) delete mode 100644 blog/dist/assets/404.html-d25048b5.js rename blog/dist/assets/{app-48e592bc.js => app-0009cf46.js} (56%) create mode 100644 blog/dist/assets/day01.html-08915fe7.js create mode 100644 blog/dist/assets/day01.html-40ef3352.js delete mode 100644 blog/dist/assets/day01.html-55eb354f.js delete mode 100644 blog/dist/assets/day01.html-5b3d75e2.js delete mode 100644 blog/dist/assets/day02.html-16f7422e.js delete mode 100644 blog/dist/assets/day02.html-8d6bc722.js delete mode 100644 blog/dist/assets/day03.html-8bf052f3.js delete mode 100644 blog/dist/assets/day03.html-fbe757fe.js delete mode 100644 blog/dist/assets/day04.html-b068227c.js delete mode 100644 blog/dist/assets/day04.html-d99e9bf2.js delete mode 100644 blog/dist/assets/day05.html-019a29ca.js delete mode 100644 blog/dist/assets/day05.html-b3eb6724.js delete mode 100644 blog/dist/assets/day06.html-435a8053.js delete mode 100644 blog/dist/assets/day06.html-46d99ff3.js delete mode 100644 blog/dist/assets/day07~day08.html-99b6eb19.js delete mode 100644 blog/dist/assets/day07~day08.html-af1acce9.js delete mode 100644 blog/dist/assets/day09~day10.html-ea2643e5.js delete mode 100644 blog/dist/assets/day09~day10.html-fca95bc7.js delete mode 100644 blog/dist/assets/day11.html-22b3645c.js delete mode 100644 blog/dist/assets/day11.html-bf0a77d6.js delete mode 100644 blog/dist/assets/day12.html-ca956336.js delete mode 100644 blog/dist/assets/day12.html-fd07949c.js delete mode 100644 blog/dist/assets/icon/apple-icon-152.png delete mode 100644 blog/dist/assets/icon/chrome-192.png delete mode 100644 blog/dist/assets/icon/chrome-512.png delete mode 100644 blog/dist/assets/icon/chrome-mask-192.png delete mode 100644 blog/dist/assets/icon/chrome-mask-512.png delete mode 100644 blog/dist/assets/icon/guide-maskable.png delete mode 100644 blog/dist/assets/icon/ms-icon-144.png delete mode 100644 blog/dist/assets/index.html-2448c597.js delete mode 100644 blog/dist/assets/index.html-408426f6.js create mode 100644 blog/dist/assets/index.html-5385c67b.js create mode 100644 blog/dist/assets/index.html-8542c835.js create mode 100644 blog/dist/assets/index.html-8daec251.js rename blog/dist/assets/{index.html-fe05aaa1.js => index.html-964d1ecc.js} (76%) rename blog/dist/assets/{index.html-09a8d92e.js => index.html-ad5460d9.js} (67%) delete mode 100644 blog/dist/assets/index.html-b25c80fe.js rename blog/dist/assets/{index.html-970a5d45.js => index.html-b50e8a62.js} (89%) delete mode 100644 blog/dist/assets/resume.html-5daad762.js create mode 100644 blog/dist/assets/resume.html-7640e47a.js delete mode 100644 blog/dist/assets/resume.html-76c4384e.js create mode 100644 blog/dist/assets/resume.html-b1aba35a.js create mode 100644 blog/dist/assets/slides.html-141feb08.js rename blog/dist/assets/{slides.html-2a1d1365.js => slides.html-86266226.js} (99%) delete mode 100644 blog/dist/assets/slides.html-a8da665a.js delete mode 100644 blog/dist/logo.png delete mode 100644 blog/dist/md/dev-log/day02.html delete mode 100644 blog/dist/md/dev-log/day03.html delete mode 100644 blog/dist/md/dev-log/day04.html delete mode 100644 blog/dist/md/dev-log/day05.html delete mode 100644 blog/dist/md/dev-log/day06.html delete mode 100644 blog/dist/md/dev-log/day07~day08.html delete mode 100644 blog/dist/md/dev-log/day09~day10.html delete mode 100644 blog/dist/md/dev-log/day11.html delete mode 100644 blog/dist/md/dev-log/day12.html delete mode 100644 blog/src/.vuepress/public/assets/icon/apple-icon-152.png delete mode 100644 blog/src/.vuepress/public/assets/icon/chrome-192.png delete mode 100644 blog/src/.vuepress/public/assets/icon/chrome-512.png delete mode 100644 blog/src/.vuepress/public/assets/icon/chrome-mask-192.png delete mode 100644 blog/src/.vuepress/public/assets/icon/chrome-mask-512.png delete mode 100644 blog/src/.vuepress/public/assets/icon/guide-maskable.png delete mode 100644 blog/src/.vuepress/public/assets/icon/ms-icon-144.png delete mode 100644 blog/src/.vuepress/public/logo.png diff --git a/blog/dist/404.html b/blog/dist/404.html index 71d45b3..7325d7f 100644 --- a/blog/dist/404.html +++ b/blog/dist/404.html @@ -5,7 +5,7 @@ - 我的简历 + blog - - - - - -
跳至主要內容

Day02

小傅哥大约 4 分钟开发笔记学习记录

任务

  • [x] 表设计
  • [x] 抽奖领域模块开发

学习过程

  1. 查询分库分表相关知识点,了解到垂直和水平分库分表,主要是为了解决数据量过大导致 MySQL 查询慢、单体容量过大问题
  2. 开始写代码
    1. 编写基础的持久化对象 (PO)
    2. 编写 Mapper 接口
    3. 编写对应的 Mapper.xml
    4. 设计抽奖策略顶级接口,主要是入参出参,如何封装,要封装哪些数据
    5. 编写顶级接口的基础实现,实现里面公用的方法,比如把初始化方法、哈希计算的方法以及判断是否初始化完成
    6. 编写两种算法的实现
    7. 算法单元测试

遇到的问题

  1. 为什么在设计阶段就考虑分库分表等问题

    在之前的学习过程中,并没有项目环境的支撑,导致了这个问题,一个大的项目,如果要兼顾性能以及代码的可扩展性,那么在数据库设计阶段就应该想到这些,那些是热点数据,那些数据会进行大量的插入,没有全局把控的观念,只有了解这些,才能设计出一个性能良好且代码可维护性高的项目,这个需要项目积累,这是一个很重要的东西,以后在学习的时候一定要多注意这方面,多看看别人的数据库是怎么设计的,以及为什么要这么设计,要有全局把控的观念

  2. 抽奖算法是怎么实现的呢

    首先这个初始化的时候,传入奖品和对应的概率,然后概率乘以 100,就是对应的下标范围,一个奖品一个范围,是不会重复的,然后经过斐波那契哈希散列算法,将这个对应的下标进行加工,使其均匀的分布在数组中,在对下标进行加工的过程中,确保了无论传入什么数字,都会在 0 ~ 128 的范围内

    1. SingleRateRandomDrawAlgorithm

      这种策略是生成一个 1 ~ 100 的随机数,然后经过 hashIdx 计算对应的下标,然后去上面初始化好的数组中去取奖品

    2. DefaultRateRandomDrawAlgorithm

      这是一种必中奖策略,先排除掉不在抽奖范围内的奖品ID,然后生成随机数,然后判断这个随机数是否在指定的范围内,如果不在,那么这个奖品就没中,然后看下一个奖品,重新生成随机数,然后看是否在指定的中奖概率内加上上次生成的随机数范围内

总结

今天主要把抽奖算法给搞定了,虽然代码不多,但是很难理解,最开始都搞不清楚为什么这样子就实现了抽奖算法,不懂这个概率是如何保证的,然后 debug 了好久,发现其实就是一个 128 长度的数组,然后经过哈希散列排列,保证随机的均匀性,其实这 128 长度的数组就已经保证了抽奖的概率,假设不经过哈希算法,直接放进去,假设两个的抽奖概率是 0.1 和 0.2,那么放进去的时候就是下标 1~10 全是第一个奖品,下标 11 ~ 30 全是第二个奖品,随机数生成的是 1 ~ 100,那么第一个奖品也就是有 10 个数字能中奖,那不就是 10% 的中奖概率了么,加哈希散列只是为了均匀分布,增加随机性和公平性

收获:

  1. 对 DDD 有更深的了解,知道什么类该写在什么包下,比昨天更清楚代码该如何组织了
  2. 了解了分库分表,虽然是第一次接触,但是至少知道了为什么要分库分表,随着项目的进行,就会学会如何分库分表了吧
  3. 了解了 Hash 散列算法,后续看看源码,要搞清楚底层是如何运作的
- - - diff --git a/blog/dist/md/dev-log/day03.html b/blog/dist/md/dev-log/day03.html deleted file mode 100644 index 6a40723..0000000 --- a/blog/dist/md/dev-log/day03.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - Day03 | 我的简历 - - - - - - -
跳至主要內容

Day03

小傅哥大约 40 分钟开发笔记学习记录

day03

任务

  • [x] 模板模式处理抽奖流程

学习过程

  1. 因为之前没学过设计模式,先学一学模板模式,用到一种学一种,哈哈哈

  2. 先看一下整个抽奖流程

    抽奖过程
    抽奖过程
  3. 了解了抽奖流程之后就开始写代码

    1. 先写对应的 dao 层

      1. 要查策略吧?写个策略的 Mapper
      2. 要查策略详情吧?写个策略详情的 Mapper
      3. 要查奖品吧?要减奖品库存吧?要查没库存的奖品吧?写个奖品的 Mapper
    2. 然后实现 repository 层

      这里主要是调 Mapper 将结果进行聚合封装

    3. 使用模板模式设计抽奖过程代码

      1. 顶层接口规定抽奖的入参出参
      2. 加一层 Config 把抽奖策略进行统一录入
      3. 配置完成后需要调用基础服务比如 repository 层,所以加一层基础支持
      4. 然后来一个抽象类,在这里实现接口的抽奖,抽奖接口里面写抽奖的流程,然后具体的方法交给子类实现
      5. 实现抽象类
    4. 测试

遇到的问题

相对于前两天,今天的内容算容易的,因为只有一个模板设计模式没学过,只要理清了思路、理清代码执行流程,今天应该算容易的

  1. 空指针 bug

    今天太晚了,先注销那个判断吧,待会儿搞完又不想睡觉了,后面也会解决这个 bug 吧,先睡觉咯 :TODO

总结

今天主要就两件事,先学习模板设计模式,然后使用模板设计模式来组织抽奖流程,主要就是通过一系列的封装,把公用的代码提取出来,比如配置、执行流程、以及公用仓储服务,然后把接口留给实现类而达到同一套代码,不同的处理方法

收获:

  1. 今天对于前两天来说,对于包的组织架构以及 DDD 有了更深的理解,很明显的感觉到知道代码该写在哪了,找包都比前两天快
  2. 学习了模板模式,知道了模板模式的代码应该怎样组织,突然感觉那种设计模式大牛真的能把封装继承多态玩出花,有了设计模式,代码的扩展性提高了很多
- - - diff --git a/blog/dist/md/dev-log/day04.html b/blog/dist/md/dev-log/day04.html deleted file mode 100644 index 1d71f17..0000000 --- a/blog/dist/md/dev-log/day04.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - Day04 | 我的简历 - - - - - - -
跳至主要內容

Day04

小傅哥大约 2 分钟开发笔记学习记录

任务

  • [x] 简单工厂搭建发奖领域

学习过程

  1. 表结构变了,先导入 SQL,然后该对应的 PO 类,然后改一下 Mapper 文件

  2. 先把包结构建好

    1. 新建一个领域包,负责发奖
    2. 领域包内建三个子包,model 实体封装包、repository 提供仓储服务、service 提供具体的服务(重点内容)
  3. 看一下代码的继承关系

  4. debug 看一下代码执行流程,了解其中的调用关系

    1. 先执行抽奖,返回抽奖结果
    2. 对抽奖结果进行判断,如果是未中奖,直接返回
    3. 中奖了就保存用户信息以及订单信息
    4. 根据中奖结果中的奖品类型获取对应的服务
    5. 然后把第三步保存的用户信息以及订单信息传进去,做一个发奖的操作
    6. 然后返回发奖结果

遇到的问题

今天还没遇到啥问题,代码比较简单,主要是数据库字段规范之后,好多 Mapper 要改 T.T,最开始我还在纠结要不要当初建表的时候就改了

就很气,本来能学两小节的,md,电脑被亲戚孩子给整挂了,直接开不了机了,麻了,修电脑都修了两小时,系统还重装了,又重装环境

总结

  1. 越来越喜欢 DDD 架构这种包的组织方式了,虽然包很多,看着有点复杂,但是真的理解了之后,就感觉很干净,扩展性也很好,虽然目前还没完全搞清楚 DDD
  2. 学会了工厂模式,根据奖品类型,从工厂里面拿对应的实现类进行发奖操作
- - - diff --git a/blog/dist/md/dev-log/day05.html b/blog/dist/md/dev-log/day05.html deleted file mode 100644 index 636034d..0000000 --- a/blog/dist/md/dev-log/day05.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - Day05 | 我的简历 - - - - - - -
跳至主要內容

Day05

小傅哥大约 4 分钟开发笔记学习记录

任务

  • [x] 活动领域的配置与状态

学习过程

  1. 包结构变化,调整对应的包
  2. 了解活动创建的整个流程,然后将流程进行编排(其实就是落库的步骤呗),写对应的 repository 层代码
    1. 首先明确要做哪些操作
      1. 添加活动
      2. 添加奖品
      3. 添加活动配置
      4. 添加策略
      5. 添加策略明细
    2. 编写对应的 repository 接口和实现类
  3. debug 了解状态模式如何进行的状态判断(感觉不用刻意去学这个设计模式,通过对项目的学习,从而达到状态模式的学习,后期进行设计模式的统一学习
    1. 首先定义一个状态处理的接口,入参统一是活动ID和当前状态
    2. 定义一个活动状态抽象类,这个抽象类的子类用来判断某种状态是否可以流转
    3. 编写抽象类的实现,里面定义是否可以流转
    4. 编写状态配置类,把每一种活动状态抽象类的实现注入进去并放入 Map 中,供状态处理服务使用
    5. 编写状态处理接口的实现类
      1. 先从状态配置中获取当前状态所对应的活动状态流转实现类
      2. 然后实现类调用方法,通过方法的返回值来确定是否能进行操作
        1. 如果能进行变更的,先进行落库操作,然后根据 MyBatis 返回值返回对应信息
        2. 如果不能进行变更的,直接返回对应的错误信息

遇到的问题

  1. 为什么要使用 BeanUtils.copyProperties()

    因为原来很少使用这种方法,以前都是 new 对象,然后把传进来的对象手动一个一个赋值,对这个方法不太了解,简单来说就是实现对象的拷贝,属性名相同的就进行拷贝,属性名不相同的就不进行操作,底层使用反射,首先把读写权限都设置为 true,然后再进行获取和赋值操作,这种操作是 浅拷贝

    if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
    -    readMethod.setAccessible(true);
    -}
    -
    -Object value = readMethod.invoke(source);
    -if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
    -    writeMethod.setAccessible(true);
    -}
    -writeMethod.invoke(target, value);
    -
  2. 数据库 bug ### Error updating database. Cause: java.sql.SQLException: Incorrect string value: '\xE4\xB8\x80\xE7\xAD\x89...' for column 'award_name' at row 1

    中文插入乱码问题,我建数据库的时候设置了 utf8,但是建表的时候默认没有设置成 utf8,使用的编码是 latin1,所以需要修改字段的编码为 utf8

总结

  1. 包结果的变化

    1. 首先呢这个解决了我之前的一个疑问:为啥要把数据库的真实操作写到领域层呢?这不应该写到基础服务层更符合逻辑吗?
    2. 更改详情:基础服务模块引入领域模块,在领域层写 repository 接口,在基础服务层写实现
  2. 状态流程处理

    相对于普通的 if-else 处理流程,状态模式设计模式把状态的流转转化为方法,从而简化了 if-else 一坨接着一坨的形式,如果有新的状态,只需要添加对应的抽象实现以及在其他实现中添加对应的流转方法

    后期对设计模式进行统一的学习,目前只了解了基础的程序运行流程,根据流程来了解对应的设计模式,目前对于状态模式的了解仅限于以下两点

    1. 将一种状态的流转包装成一个类,然后在类里面定义是否可以流转
    2. 状态的流转通过调用方法的形式进行,而不是通过 if-else 去判断,比如要把状态修改为审核通过,那么直接调用 checkPass() 然后找到当前状态处理类,调用处理类的 checkPass() 方法,然后返回结果就可以了
  3. 对于学习的思考

    最近陷入了日夜颠倒的死循环,主要就是晚上窝在床上玩手机呢,然后看了会儿星球就想起床学习,一学又搞到两三点三四点,搞不好 bug 多还通了个宵,导致第二天甚至第三天状态低迷,后面要压制学习欲望了,每天该做的做完了就休息,以后每周日休息一天,晚上一点前就睡觉,避免陷入死循环,再多的任务,人的精力也是有限的,只要按部就班稳扎稳打,相信最后也会有收获,不必急于求成

- - - diff --git a/blog/dist/md/dev-log/day06.html b/blog/dist/md/dev-log/day06.html deleted file mode 100644 index e72dd13..0000000 --- a/blog/dist/md/dev-log/day06.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - Day06 | 我的简历 - - - - - - -
跳至主要內容

Day06

小傅哥大约 4 分钟开发笔记学习记录

任务

  • [x] ID 生成策略开发

学习过程

  1. 先看视频了解用到了啥

  2. 看小傅哥策略模式的文章open in new window

  3. 看代码结构

    1. 定义一个接口,用来生成 id
    2. 实现接口,实现不同的 id 生成算法
    3. 定义一个上下文对象,包装各种 id 生成算法,然后放到 Spring 容器中供其他类注入使用

    今天的代码比较简单,主要就是涉及策略模式的使用,这里的上下文对象和之前的 config 类似,都是把写好的实现类进行包装,统一放到一个容器内,然后其他类通过这个容器,配合枚举拿到对应的实现类进行调用

  4. 实操

遇到的问题

  1. 什么是雪花算法
  2. 项目代码中的雪花算法为什么要这么写

总结

  1. 对策略模式的新看法

    现在对策略模式的看法如下:

    1. 将每一种策略想象成一个又一个的工具类
    2. 这些工具类都来自同一个接口,也就是实现的功能是类似的,比如都是生成 ID,都是用来发奖的
    3. 把这些工具类进行 “打包” 处理,封装在一个 Map 中,键使用枚举进行处理
    4. 后续使用通过注入封装好的 Map 和枚举直接进行 get 操作然后使用就可以了

    好处:

    减少 if else 的次数,如果以后要进行扩展,只需要添加一个接口实现,然后在 "打包" 里添加一种策略就可以了,易于扩展,避免代码过度耦合,把一坨代码进行分片,功能职责划分更清楚,并且可以动态切换算法:将实现类进行更改就可以实现动态切换

  2. 什么是雪花算法

    雪花算法用于生成分布式唯一 ID,核心思想如下:

    1. 将一个64位的整数划分为不同的部分,每一部分代表不同的含义
    2. 符号位(1位):始终为 0,表示生成的 ID 为正整数
    3. 时间戳(41位):记录生成 ID 的时间戳,精确到毫秒级,41位可以表示约 69 年的时间
    4. 工作机器 ID(10位):标识机器的唯一ID,用于解决分布式系统中的多节点生成 ID 的冲突问题,最多有 2^10 台机器 ,即 1024 个
    5. 序列号(12位):表示同一毫秒内的序列号,用于解决同一节点在同一毫秒内生成 ID 的冲突问题,最多可以用 2 的 12 次方个 ID,也就是同一毫秒内同一机器最多生成 4096 个

    通俗化:确保在分布式系统中,通过对时间戳、机器和序列号进行加工,生成一个唯一 ID

    了解了这个东西就能理解项目中为啥要这么写了,后面看看雪花算法的具体源码,看看每个部分如何进行加工的

  3. 短码生成的时候进行打乱和再加工

    因为没有实际项目经验之前就是直接拿当前时间戳进行获取的,没有进行打乱操作,以后要记住这个操作,避免项目数据被别人抓个包一下子就猜出来了 -.- 好歹穿件衣服,不能裸奔

  4. 预习预习明天的内容,哈哈哈,好像要开始上强度了,昨天亲戚结婚忙了一天,半夜才回来,今天就到这把,查点资料预习预习明天的,感觉 DDD 这种包组织方式特别适合每种设计模式和算法的落地,MVC 如果想要算法和设计模式落地的话,感觉要考虑的东西很多很多,要么就是牵一发而动全身,要么就是落地之后包里面有很多的多余的东西,这种方式则不会出现这种情况,一个领域里面,使用一种设计模式,并不会影响其他的包,其他的包只管调用所提供的接口就好了

- - - diff --git a/blog/dist/md/dev-log/day07~day08.html b/blog/dist/md/dev-log/day07~day08.html deleted file mode 100644 index 491ffd5..0000000 --- a/blog/dist/md/dev-log/day07~day08.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - Day07 ~ Day08 | 我的简历 - - - - - - -
跳至主要內容

Day07 ~ Day08

小傅哥大约 3 分钟开发笔记学习记录

任务

  • [x] 分库分表组件

遇到的问题

问题就不说了,这一章节全是问题 T.T,基础不牢,地动山摇啊!!!

总结

首先建立一个大局观,要实现一个分库分表组件,那么先要学会如何编写 SpringBoot Starter,然后这个 Starter 需要实现的功能是分库分表,那么一定是有多个数据源,这个数据源从项目的 yml 配置文件传进来,然后就要实现多数据源的切换,然后分表操作就是要修改 SQL 的表名,所以需要做的事情大概是如下:

  1. 读取数据源信息
  2. 动态修改数据源
  3. 动态修改 SQL

那么细节该如何实现呢?需要想几个问题,某条数据应该分到哪个库的哪个表呢?这个库表信息该存到哪里进行共享呢?如何动态修改数据源呢?如何动态修改 SQL 呢?那么就需要对应的技术进行支持:

  1. Spring & SpringBoot 基础框架,提供依赖注入、配置管理功能
  2. AbstractRoutingDataSource 实现动态数据源的路由逻辑
  3. AspectJ 切面编程,运行时动态拦截方法调用
  4. 反射 API,从方法参数中提取路由键的值
  5. 正则表达式,解析和修改 SQL
  6. ThreadLocal,存储路由信息,以支持动态数据源路由

总体执行流程:

  1. 调用被 @DBRouter 注解的方法
  2. 然后被切面进行拦截,拦截之后先进行路由计算,然后把计算结果保存到 ThreadLocal 中
  3. 然后 DynamicDataSource 通过保存到 ThreadLocal 中的数据确定使用哪一个数据源
  4. 然后 MyBatis 插件修改 SQL 中的表字段
  5. 然后数据库操作执行完成
  6. 切面清理 ThreadLocal 里面的数据
  7. 方法执行完成,返回结果

虽然步骤不多,但是稍不注意就会出现小 bug,抑或扰动函数算法出错,抑或解析 yml 配置出错等等诸多问题,也是花了两三天才大致搞明白这个路由组件,因为这里面的东西大部分之前都没接触过,查阅了许多文档,毕竟之前连切面都不怎么用,最多也就是拿来做全局日志处理

总之,要先在大脑里面理清总体的一个执行流程,然后根据这个流程再去看代码要清晰很多,最开始的时候没理清步骤,直接看的代码,那种感觉就像第一天学 DDD 一样,直接一脸懵逼,怎么这么多包,卧槽,第一遍下来大概只学到了百分之五十吧,这一遍大概只学到了整体架构,具体的细节还没掌握,下一次努力啃啃细节,如果要我写整个这一套代码,我肯定写出来会报很多错,但是第一次就想学透整个路程怎么可能呢?好在这一次理清了整体架构,至少有了头绪,不至于开不了头,有了头绪,到处搜一搜,拼拼凑凑也能写,哈哈哈

- - - diff --git a/blog/dist/md/dev-log/day09~day10.html b/blog/dist/md/dev-log/day09~day10.html deleted file mode 100644 index 11b68a4..0000000 --- a/blog/dist/md/dev-log/day09~day10.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - Day09 ~ Day10 | 我的简历 - - - - - - -
跳至主要內容

Day09 ~ Day10

小傅哥大约 2 分钟开发笔记学习记录

任务

  • [x] 在应用层编排抽奖过程

总结

有了前面的模板模式的基础,这一章节相对来说比较容易,自己实现的时候也没有什么大问题,大体流程就是写接口,编排流程,然后写实现类,然后写 Mapper,至于为什么花了两三天,这就不得不说上一章的分库分表了,没写过 SpringBoot Starter,没写过 MyBatis 插件,对 AOP 没有深刻的理解,纯硬啃下来的,但是记不太劳,所以晚上睡不着觉,总感觉缺点什么东西,就花了两天干了如下几件事:

  1. 新建一个空的 SpringBoot 项目,从 SpringApplication.run() 方法开始 debug,一步一步看,在这一个过程中主要学到了如下几点:

    • 一个 SpringBoot 项目是如何初始化的,在哪里创建的容器等等
    • 如何加载第三方 Starter 的
    • 在哪里打印的Banner 以及如何设置 这个不是重点,哈哈哈,但是挺好玩的
    • 还有 ApplicationRunnerCommandLineRunner
    • 还有异常报告器 exceptionReporters
    • 还有几个关于上下文环境的重要方法 prepareContext()refreshContext()afterRefresh()

    明白了 SpringBoot 应用初始化流程就知道所写的分录分表路由 starter 是在哪个阶段进行数据源设置以及为什么要在 AutoConfig 类下进行 Bean 的注入了

  2. 看了看 MyBatis 插件相关的文档,大致了解了一个 MyBatis 插件如何编写,看了这个以后看 MyBatis-Plus 源码的时候可能会轻松一点

  3. 复习了一下 AOP,注解的属性有哪些以及该怎么写都有点忘了

  4. 在这个 debug 的过程中其实画了一些图,但是因为没有 OSS,所以图片不太好展示,所以使用 vuepress + github pages + github actions 搭建了一个博客,后面有空了会把看源码的过程发上去

虽然很想继续往下学,但是感觉这个项目里面,分库分表这一章节应该是灵魂所在了,虽然还没学后面,但是感觉其他章节更多的是关注业务层面,主要是来解决业务问题的,但是分库分表这一章节感觉能彻彻底底搞明白的话收获应该是很大的,虽然进度慢了,但是通过对源码的阅读也学到了很多东西,比如代码规范,在阅读 SpringBoot 源码的时候,给我最大的感觉就是,其实好的东西是不需要太多注释的,因为他每一步所调用的方法都给你写的很明白,比如 SpringBoot 程序初始化过程,只要英文够好,就跟看小学阅读一样,不知道花的这两天值不值,毕竟还有一个月就找工作了,是不是应该快点把项目做完

- - - diff --git a/blog/dist/md/dev-log/day11.html b/blog/dist/md/dev-log/day11.html deleted file mode 100644 index 4c14972..0000000 --- a/blog/dist/md/dev-log/day11.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - Day011 | 我的简历 - - - - - - -
跳至主要內容

Day011

小傅哥大约 1 分钟开发笔记学习记录

任务

  • [x] 在应用层编排抽奖过程

总结

今天的内容比较简单,最主要的问题就是表改了,然后花了很多时间去改对应的 PO 以及 SQL,然后今天第一次开发 application 层,感觉就是把 domain 层各个领域进行组装,然后形成一个又一个的流程,在这里面会使用 MQ 把流程进行切片,之后写门面接口应该就是调 application 层里面各个流程了,这样对于 Controller 层感觉挺好的,只需要简单的封装一下前端传进来的参数,然后调用 application 层执行各个流程就可以了

感觉今天最大的收获就在于学到了在开发的过程中要把整个流程切分一下,分成一块一块的,然后用 MQ 进行后续的操作,用户不需要感知到这一切,他只需要点进去,然后执行一个小的片段,然后剩下的操作可以使用 MQ 来慢慢操作,而不是之前那样直接单线程一个流程写完,又臭又长,返回得还慢,用户体验很不好,学到了流程切片,今天不亏,哈哈哈哈,这个东西还是很有用的

- - - diff --git a/blog/dist/md/dev-log/day12.html b/blog/dist/md/dev-log/day12.html deleted file mode 100644 index 21dfd63..0000000 --- a/blog/dist/md/dev-log/day12.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - Day012 | 我的简历 - - - - - - -
跳至主要內容

Day012

小傅哥大约 3 分钟开发笔记学习记录

任务

  • [x] 规则引擎量化人群参与活动

总结

首先先去了解了一下组合模式和决策树,然后看了看数据库,其实就是把一个类似于二叉树的结构存到了数据库里,分别对应了三个东西,一个表用来保存决策树的树根信息,然后一个表用来保存树上的所有节点的信息,然后一个表用来存决策树的连接信息,我们可以通过树根的 ID 拿到所有相关的连线信息以及所有相关的节点信息,明白了数据库相关的东西之后屡屡代码结构

什么是组合模式呢?先看看维基百科对组合模式的定义,然后直接看代码,给我的第一感觉就是把每一个 if-else 的条件抽取出来,然后变成一个又一个的 filter,然后在规则引擎中进行使用,首先把一个个 filter 包装到 map 中,供子类使用

其中最重要的代码我觉得是这个:

    protected TreeNodeVO engineDecisionMaker(TreeRuleRich treeRuleRich, DecisionMatterReq matterReq) {
-        TreeRootVO treeRoot = treeRuleRich.getTreeRoot();
-        Map<Long, TreeNodeVO> treeNodeMap = treeRuleRich.getTreeNodeMap();
-        Long rootNodeId = treeRoot.getTreeRootNodeId();
-        TreeNodeVO treeNodeInfo = treeNodeMap.get(rootNodeId);
-        while (Constants.NodeType.STEM.equals(treeNodeInfo.getNodeType())) {
-            String ruleKey = treeNodeInfo.getRuleKey();
-            LogicFilter logicFilter = logicFilterMap.get(ruleKey);
-            String matterValue = logicFilter.matterValue(matterReq);
-            Long nextNode = logicFilter.filter(matterValue, treeNodeInfo.getTreeNodeLineInfoList());
-            treeNodeInfo = treeNodeMap.get(nextNode);
-        }
-        return treeNodeInfo;
-    }
-
  1. 获取树根节点信息
  2. 获取树根所对应的所有节点信息
  3. 判断每个节点是不是叶子节点
    1. 如果不是,就执行决策,如果通过就返回下一个节点
    2. 如果是叶子节点,也就是找到了对应的活动号,表示可以参与

那么就可以将代码结构分为两个部分,一个是决策者,提供决策相关逻辑,一个是执行者,对决策链条进行链路执行,然后返回最终结果,那么到这里应该代码逻辑就清晰了,决策者根据一定的比较规则,返回 ture 或者 false,执行者根据这个结果来判断是否要继续进行下一个判断,直到判断到叶子节点

了解了这个之后代码就好写了

感觉这个章节最大的难点就在于如果之前没有设计模式基础的话,会很难受,代码跳过去跳过来有时候找不到方向,一般我遇到这种情况的时候我就会梳理一下业务逻辑,代码结构无论怎么变,也一定是根据业务逻辑来的,之前做的事情一样不少,所以就按照自己想的逻辑去代码中找对应,去看看哪里做的比较,哪里拿到的链路结构,这样就将大问题化成了小问题,然后去对应代码中的每一个部分,这里也就是将逻辑执行步骤进行“打散”的过程,找到了每段代码对应那一段逻辑之后,看一看代码的继承体系,大概也就了解个七七八八了

- - - diff --git a/blog/dist/md/dev-log/index.html b/blog/dist/md/dev-log/index.html index 4cbc866..3c8fae5 100644 --- a/blog/dist/md/dev-log/index.html +++ b/blog/dist/md/dev-log/index.html @@ -5,7 +5,7 @@ - 开发日志 | 我的简历 + 开发日志 | blog