最基础的传输控制

考虑至少要实现一个简单的并发控制吧亲!

使用的架构:

  • Java 21
  • Redis
  • MySQL

使用到的包:

  • Hutool SecureUtil MD5
  • Java Spring Framework MutilPartFile/TransactionTemplate
  • Redission Lock


使用的协议:

  • HTTP 协议

对于一个使用最基础的 HTTP 协议的文件传输功能。使用 Spring 框架的 Controller / Service / Dal 是可以的。

  1. 基础的 @PostMapping(“/upload”) 路由即可。
  2. Service 层处理存储逻辑
    • 基于 Redisson 的并发控制
    • MD5 算法校验文件完整性
    • (预拓展分片、流式传输、预签名 url)
  3. 调用 dal 写入文件明细
    • 逻辑目录,存储文件的实际物理地址

在数据库建表的时候,不仅逻辑上使用 ID 作为主键索引,同时要使用 MD5 作为唯一索引,因为在大多数情况下,我们使用 MD5 进行查询一个文件是否存在于我们的数据空间中。

基础上传业务逻辑代码

在具体的实现流程上,具体发生的情况如下:

  1. 将接收到的文件进行 MD5 校验计算
  2. 尝试使用该 MD5 值获取 RLock 锁
    • 如果没能获取锁,说明该文件正在被其他线程处理,抛出异常;
    • 如果获取了锁,启动 TransactionTemplate 事务调用执行函数,用 status 控制事务的状态。
  3. 持有锁状态,未开启事务:
    • 调用 FileSpaceService 层的方法,进行刷盘、写盘操作,文件成功落盘后进行下一步。(如你所见,这是潜在的最耗时的流程。线程阻塞在这里等待执行完毕。未来这是一个优化点)。
    • 如果出现任何异常,调用 Hutool 清除僵尸文件,抛出异常,不进行下一步。
  4. 持有锁状态,开启事务:
    • 调用另外一个 Service 层的方法,进行数据库明细的写入
    • 如果发生任何异常,则进行 catch 和回滚,并清除原本写盘的文件。
    • 处理上传中断情况,主动设置线程行为;
  5. 事务提交。
  6. 最后释放锁。

文件夹嵌套设计

引入另一张表管理文件夹与文件之间的关联关系。

关于一些细节决策……

Q1: 为什么刷盘的行为要放在外面呢?

  • 为了避免长事务问题。事务长期持有某条数据库的连接池连接,在高并发情况下可能会导致性能瓶颈的并发问题。在我们的情景下,我们为了保证文件的落实和操作建议等待文件落盘后才写入数据库,如果从头到尾都开启事务,就导致了连接占用的无效等待。

Q2: 事务一定会持有数据库连接池的某条连接吗?

  • 事务是基于数据库连接之上的。

Q3: 关于其中的事务传播行为?

  • 在我们的情境下,事务方法调用了另一层 Service 中的方法。在 TransactionTemplate 中,默认的事务传播行为是 REQUIRED,意为如果当前已有事务,则加入该事务;若无事务,则以非事务方式执行。
  • 不过可喜的是,我们内层的目前还不涉及到事务。因为它目前只被这个方法调用。如果未来要更加通用的话,我们还要作事务传播行为的专门控制。
  • 未来我们会开一个小专题讨论这个事务传播行为控制问题。

事务传递

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇