当前位置: 首页 > article >正文

TiDB 实战项目:从需求分析到生产级代码完整记录

一、前言TiDB 实战项目从需求分析到生产级代码完整记录。本文从实际项目出发给出完整可运行的代码帮你快速掌握实战技能。二、需求分析与架构设计2.1 业务需求功能需求 - 用户注册/登录支持邮箱和手机号 - JWT 无状态认证支持 RefreshToken 续期 - RBAC 权限控制超级管理员/普通用户/访客 - 操作日志审计 非功能需求 - 支持 1000 并发 QPS - 接口响应时间 P99 200ms - 99.9% 可用性2.2 技术选型语言框架Node.js Fastify或 技术 数据库PostgreSQL Redis 认证JWT (access_token 15min, refresh_token 7d) ORMPrisma类型安全、自动迁移 APIRESTful OpenAPI 文档 部署Docker K8s三、核心功能实现3.1 数据库设计与建模-- 用户表 CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), username VARCHAR(64) NOT NULL UNIQUE, email VARCHAR(255) NOT NULL UNIQUE, password_hash VARCHAR(255) NOT NULL, role VARCHAR(32) NOT NULL DEFAULT user, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), CONSTRAINT email_format CHECK (email ~* ^[A-Za-z0-9._%-][A-Za-z0-9.-].[A-Za-z]{2,}$) ); -- 角色表 CREATE TABLE roles ( id SERIAL PRIMARY KEY, name VARCHAR(32) NOT NULL UNIQUE, permissions JSONB NOT NULL DEFAULT [] ); -- 操作日志表 CREATE TABLE audit_logs ( id BIGSERIAL PRIMARY KEY, user_id UUID REFERENCES users(id), action VARCHAR(128) NOT NULL, resource VARCHAR(256), details JSONB, ip_address INET, created_at TIMESTAMP DEFAULT NOW() ); -- 索引 CREATE INDEX idx_users_email ON users(email); CREATE INDEX idx_users_role ON users(role); CREATE INDEX idx_audit_user ON audit_logs(user_id, created_at DESC);3.2 用户认证服务// 技术 用户认证服务 const bcrypt require(bcrypt); const jwt require(jsonwebtoken); class AuthService { constructor(db, redis) { this.db db; this.redis redis; } async register({ username, email, password, role user }) { // 1. 校验唯一性 const existing await this.db.query( SELECT id FROM users WHERE username$1 OR email$2, [username, email] ); if (existing.rows.length 0) { throw new Error(用户名或邮箱已存在); } // 2. 密码哈希bcryptcost12 const password_hash await bcrypt.hash(password, 12); // 3. 创建用户 const result await this.db.query( INSERT INTO users (username, email, password_hash, role) VALUES ($1, $2, $3, $4) RETURNING id, username, email, role, [username, email, password_hash, role] ); // 4. 生成 Token const user result.rows[0]; return this.issueTokens(user); } async login({ email, password }) { const result await this.db.query( SELECT * FROM users WHERE email$1, [email] ); const user result.rows[0]; if (!user || !(await bcrypt.compare(password, user.password_hash))) { throw new Error(邮箱或密码错误); } // 记录登录日志 await this.logAction(user.id, LOGIN, { email }); return this.issueTokens(user); } issueTokens(user) { const accessToken jwt.sign( { user_id: user.id, role: user.role }, process.env.JWT_SECRET, { expiresIn: 15m } ); const refreshToken jwt.sign( { user_id: user.id, type: refresh }, process.env.JWT_REFRESH_SECRET, { expiresIn: 7d } ); // RefreshToken 黑名单注销时使用 return { accessToken, refreshToken }; } async logAction(userId, action, details) { await this.db.query( INSERT INTO audit_logs (user_id, action, details) VALUES ($1, $2, $3), [userId, action, JSON.stringify(details)] ); } }3.3 权限控制中间件// RBAC 权限检查 const ROLE_PERMISSIONS { admin: [users:read, users:write, users:delete, audit:read], user: [users:read, profile:write], guest: [] }; function authorize(...requiredPermissions) { return async (req, res, next) { const user req.user; if (!user) { return res.status(401).json({ error: 未认证 }); } const userPermissions ROLE_PERMISSIONS[user.role] || []; const hasPermission requiredPermissions.every(p userPermissions.includes(p) ); if (!hasPermission) { await authService.logAction(user.id, UNAUTHORIZED_ACCESS, { required: requiredPermissions, user_role: user.role }); return res.status(403).json({ error: 权限不足 }); } next(); }; } // 使用 app.get(/api/users, authenticate, // 认证 authorize(users:read), // 权限 async (req, res) { const users await userService.list(req.query); res.json(users); } );四、测试与质量保证4.1 单元测试// 技术 单元测试Jest describe(AuthService, () { let authService; let mockDb; let mockRedis; beforeEach(() { mockDb { query: jest.fn() }; mockRedis { set: jest.fn(), get: jest.fn() }; authService new AuthService(mockDb, mockRedis); }); test(register: 正常注册返回 Token, async () { mockDb.query .mockResolvedValueOnce({ rows: [] }) // 唯一性检查 .mockResolvedValueOnce({ // 创建用户 rows: [{ id: uuid-1, username: alice, email: ab.com, role: user }] }); const result await authService.register({ username: alice, email: ab.com, password: StrongPass123 }); expect(result).toHaveProperty(accessToken); expect(result).toHaveProperty(refreshToken); expect(mockDb.query).toHaveBeenCalledTimes(2); }); test(register: 重复邮箱抛异常, async () { mockDb.query.mockResolvedValueOnce({ rows: [{ id: existing-uuid }] }); await expect( authService.register({ username: alice, email: ab.com, password: pass }) ).rejects.toThrow(用户名或邮箱已存在); }); test(login: 错误密码抛异常, async () { mockDb.query.mockResolvedValueOnce({ rows: [{ id: uuid-1, password_hash: await bcrypt.hash(correct-password, 12) }] }); await expect( authService.login({ email: ab.com, password: wrong-password }) ).rejects.toThrow(邮箱或密码错误); }); });五、部署与运维5.1 Docker Compose 本地开发version: 3.8 services: app: build: . ports: - 8080:8080 environment: DATABASE_URL: postgresql://appuser:secretdb:5432/appdb REDIS_URL: redis://redis:6379/0 JWT_SECRET: ${JWT_SECRET} depends_on: db: condition: service_healthy redis: condition: service_started db: image: postgres:16-alpine environment: POSTGRES_DB: appdb POSTGRES_USER: appuser POSTGRES_PASSWORD: secret volumes: - pgdata:/var/lib/postgresql/data - ./init.sql:/docker-entrypoint-initdb.d/init.sql healthcheck: test: [CMD-SHELL, pg_isready -U appuser -d appdb] interval: 10s timeout: 5s retries: 5 redis: image: redis:7-alpine command: redis-server --appendonly yes volumes: - redisdata:/data volumes: pgdata: redisdata:5.2 GitHub Actions CI/CDname: CI/CD on: push: branches: [main] pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest services: postgres: image: postgres:16 env: POSTGRES_DB: testdb POSTGRES_USER: test POSTGRES_PASSWORD: test options: - --health-cmd pg_isready --health-interval 10s steps: - uses: actions/checkoutv4 - uses: actions/setup-nodev4 with: node-version: 20 - run: npm ci - run: npm test -- --coverage - uses: codecov/codecov-actionv3 deploy: needs: test if: github.ref refs/heads/main runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - run: docker build -t app . - run: docker push ghcr.io/${{ github.repository }}:latest六、总结先设计再写代码数据库建模 API 接口设计在前测试驱动开发每个功能有测试提交前跑全量 suite日志要完整操作日志是排查问题的救命稻草环境隔离dev/staging/prod 配置要分开收藏本文关注我后续更新更多实战项目系列。觉得有用的话点个赞收藏关注我持续更新优质技术内容标签TiDB | 实战 | 项目 | 完整 | 后端

相关文章:

TiDB 实战项目:从需求分析到生产级代码完整记录

一、前言TiDB 实战项目:从需求分析到生产级代码完整记录。本文从实际项目出发,给出完整可运行的代码,帮你快速掌握实战技能。二、需求分析与架构设计2.1 业务需求功能需求: - 用户注册/登录,支持邮箱和手机号 - JWT 无…...

从0x000000D1蓝屏到系统稳定:深入剖析iaStorA.sys故障的根源与修复路径

1. 当蓝屏突然降临:认识0x000000D1错误 那天下午正赶着交方案,突然屏幕一蓝——熟悉的死亡蓝屏又来了。错误代码0x000000D1,肇事模块iaStorA.sys。这不是我第一次遇到这种问题,去年帮朋友修电脑时就见过这个组合。对于普通用户来说…...

【YOLOv5改进实战】Neck特征融合新思路:CAM模块在PANet不同层级的注入与性能调优

1. CAM模块与YOLOv5 Neck结构的基础认知 在目标检测领域,YOLOv5因其出色的速度和精度平衡成为工业界宠儿。它的Neck部分采用PANet(Path Aggregation Network)结构,负责将不同层级的特征图进行融合。我曾在多个实际项目中验证过&am…...

Kubernetes 实战对比:ReplicationController 与 Deployment 核心差异+落地案例

Kubernetes 实战对比:ReplicationController 与 Deployment 核心差异落地案例 一、前言:从案例看控制器选择的重要性 在 Kubernetes 部署实践中,控制器的选择直接影响应用的稳定性和运维效率。本文通过 3 个真实业务场景,结合命令…...

告别多余空白:Matplotlib 图像输出精细化控制指南 / 详解 bbox_inches 与 subplots_adjust 实战

1. 为什么你的Matplotlib图表总有多余空白? 每次用Matplotlib保存图表时,你是不是也遇到过这样的烦恼:明明在代码里设置了完美的尺寸,保存出来的图片却总带着一圈多余的空白边缘?这些空白不仅浪费空间,还会…...

Outstanding深度解析:从公式到实战的带宽优化指南

1. 从数学公式到真实场景:理解Outstanding的核心价值 第一次接触Outstanding这个概念时,我也被那些字母公式搞得头晕。但真正理解后才发现,它其实就是个"排队理论"的工程应用。想象一下你去银行办业务:R是柜员处理每笔业…...

如何快速移除Unity游戏马赛克:5分钟完成配置的终极指南

如何快速移除Unity游戏马赛克:5分钟完成配置的终极指南 【免费下载链接】UniversalUnityDemosaics A collection of universal demosaic BepInEx plugins for games made in Unity3D engine 项目地址: https://gitcode.com/gh_mirrors/un/UniversalUnityDemosaics…...

2025届必备的十大降重复率工具解析与推荐

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 为了对内容质量予以优化并且规避自动化检测,能够采取下面这些策略去降低AIGC特征…...

Figma中文插件终极指南:让Figma界面秒变中文的完整教程

Figma中文插件终极指南:让Figma界面秒变中文的完整教程 【免费下载链接】figmaCN 中文 Figma 插件,设计师人工翻译校验 项目地址: https://gitcode.com/gh_mirrors/fi/figmaCN 你是否曾经因为Figma的全英文界面而感到困扰?作为一名中文…...

Spring Boot 自动装配条件触发逻辑

Spring Boot自动装配条件触发逻辑揭秘 Spring Boot的自动装配机制是其核心特性之一,它通过条件触发逻辑智能地加载所需的Bean,大幅简化了配置工作。这种“约定优于配置”的设计理念,让开发者能够快速构建应用,而无需手动编写大量…...

突破百度网盘限速:Python直连解析工具让你的下载速度飙升30倍

突破百度网盘限速:Python直连解析工具让你的下载速度飙升30倍 【免费下载链接】baidu-wangpan-parse 获取百度网盘分享文件的下载地址 项目地址: https://gitcode.com/gh_mirrors/ba/baidu-wangpan-parse 在数字资源获取日益频繁的今天,百度网盘作…...

测试时数据增强(TTA)在表格数据中的实践指南

1. 测试时数据增强在表格数据中的应用测试时数据增强(Test-Time Augmentation, TTA)是一种提升预测模型性能的技术。虽然它最初是为图像数据设计的,但在表格数据上同样能发挥显著作用。作为一名从业多年的数据科学家,我发现很多同…...

DDR5 On-Die ECC:内存颗粒内的数据守护者

1. 内存数据的隐形杀手:为什么需要On-Die ECC? 当你用电脑处理重要文件时,有没有想过内存芯片内部正在发生一场无声的战争?DDR5内存颗粒中集成的On-Die ECC技术,就像一位24小时值守的保安,专门对付那些看不…...

51单片机实战:从直流电机调速到步进电机精确定位

1. 51单片机电机控制入门指南 第一次接触51单片机控制电机时,我完全被各种电机类型搞晕了。直到亲手让一个小车动起来,才真正理解其中的奥妙。51单片机作为经典微控制器,在电机控制领域有着广泛的应用场景,特别适合DIY智能小车、机…...

告别繁琐存档修改:一站式网页版暗黑破坏神2存档编辑器

告别繁琐存档修改:一站式网页版暗黑破坏神2存档编辑器 【免费下载链接】d2s-editor 项目地址: https://gitcode.com/gh_mirrors/d2/d2s-editor 你是否曾在暗黑破坏神2中为了一件稀有装备反复刷图数小时?是否想过调整角色属性却担心复杂的修改工具…...

深度解析:如何用UE Viewer高效处理虚幻引擎1-4代游戏资源

深度解析:如何用UE Viewer高效处理虚幻引擎1-4代游戏资源 【免费下载链接】UEViewer Viewer and exporter for Unreal Engine 1-4 assets (UE Viewer). 项目地址: https://gitcode.com/gh_mirrors/ue/UEViewer UE Viewer是一款强大的开源虚幻引擎资源查看与导…...

ComfyUI IPAdapter Plus:如何用一张图片重塑AI生成的艺术世界?

ComfyUI IPAdapter Plus:如何用一张图片重塑AI生成的艺术世界? 【免费下载链接】ComfyUI_IPAdapter_plus 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI_IPAdapter_plus 你是否曾经遇到过这样的困境:想要AI生成一张特定风格的…...

5分钟快速配置Switch大气层系统:终极优化指南

5分钟快速配置Switch大气层系统:终极优化指南 【免费下载链接】Atmosphere-stable 大气层整合包系统稳定版 项目地址: https://gitcode.com/gh_mirrors/at/Atmosphere-stable 你是否还在为Switch游戏加载缓慢、系统频繁崩溃而烦恼?Atmosphere-sta…...

Docker Desktop → Docker CE 完整迁移部署方案

全程分为 5 步:环境准备 → 迁移文件 → 部署配置 → 启动验证 → 维护规范。一、先明确两个环境区别Docker Desktop:开发用(Windows/Mac),自带 ComposeDocker CE:Linux 服务器生产环境(CentOS …...

Kubernetes 垃圾收集(Garbage Collection)完全指南:对象生命周期管理

Kubernetes 垃圾收集(Garbage Collection)完全指南:对象生命周期管理 1. Owner 和 Dependent(所有者与依赖对象) 1.1 核心概念Owner(所有者):Kubernetes 中部分对象可作为其他对象的…...

3PEAK思瑞浦 TP2582-SR SOIC-8 运算放大器

特性 供电电压:3V至36V 差分输入电压范围至电源轨输入轨至-Vs,轨到轨输出过载恢复时间 快速响应:10MHz带宽,8V/us斜率,100ns 低失调电压:在25C时最大3mV,在-40C至85C范围内最大值为3.5mV 在-40C至125C范围内最大值为4mV 极低总谐波…...

LFM2.5-VL-1.6B惊艳效果:手绘草图→物体识别+CAD建模提示词生成

LFM2.5-VL-1.6B惊艳效果:手绘草图→物体识别CAD建模提示词生成 1. 模型概述 LFM2.5-VL-1.6B是由Liquid AI推出的轻量级多模态大模型,专为边缘设备和端侧应用优化。这个1.6B参数的视觉语言模型(1.2B语言400M视觉)能够在低显存环境…...

Kubernetes 网络策略(NetworkPolicy)完全指南:声明式 Pod 通信管控

Kubernetes 网络策略(NetworkPolicy)完全指南:声明式 Pod 通信管控 1. Before you begin(前置条件) 1.1 核心要求Kubernetes 集群需支持 NetworkPolicy API(Kubernetes 1.7 版本默认支持)。部署…...

基于RAG与本地化部署的智能文献助手Aeiva:从原理到实践

1. 项目概述:当AI遇上科研,Aeiva如何重塑文献阅读与知识管理如果你是一名科研工作者、研究生,或者任何需要深度阅读大量文献的从业者,那么你肯定对“文献焦虑”深有体会。面对海量的PDF论文,从筛选、阅读、整理到提炼核…...

前端库作者必看:如何用@babel/plugin-transform-runtime优雅地发布你的npm包(避坑全局污染)

前端库作者必看:如何用babel/plugin-transform-runtime优雅地发布你的npm包(避坑全局污染) 当你准备将精心开发的前端库发布到npm时,是否考虑过你的polyfill策略可能会污染使用者的全局环境?作为库开发者,我…...

多智能体强化学习环境PettingZoo:从AEC/并行API到实战应用

1. 项目概述:从单智能体到多智能体的跃迁 如果你是从OpenAI Gym或者Gymnasium一路玩过来的强化学习爱好者,那么当你第一次尝试把研究兴趣扩展到多个智能体时,大概率会感到一阵头疼。单智能体环境里, env.reset() 、 env.step(…...

ESP32-CAM通过TCP传图,如何解决常见的网络中断和图片乱码问题?

ESP32-CAM TCP图像传输实战:破解网络中断与数据乱码的工程级方案 当你兴奋地完成ESP32-CAM的基础TCP图像传输demo后,现实往往给你当头一棒——WiFi信号波动导致频繁断连、接收到的图片出现诡异马赛克、服务端解析时内存溢出...这些才是真实开发中的常态。…...

终极Windows更新修复指南:5分钟解决系统更新故障的完整方案

终极Windows更新修复指南:5分钟解决系统更新故障的完整方案 【免费下载链接】Reset-Windows-Update-Tool Troubleshooting Tool with Windows Updates (Developed in Dev-C). 项目地址: https://gitcode.com/gh_mirrors/re/Reset-Windows-Update-Tool 你是否…...

微软公司产品图谱及生态

微软公司产品图谱及生态报告日期:2026年4月25日摘要微软(Microsoft Corporation)作为全球市值最高的科技企业之一,已完成了从传统软件授权公司向云服务与人工智能平台的史诗级转型。在首席执行官萨提亚纳德拉(Satya Na…...

Conda创建环境卡在‘Solving environment: failed’?别慌,试试这3种镜像源配置方法(附.condarc文件详解)

Conda环境创建卡在Solving environment: failed的深度解决方案与镜像源配置指南 当你在使用Conda创建Python环境时遇到Solving environment: failed错误,这通常意味着Conda无法解析和满足你指定的依赖关系。这个问题在配置不当或网络连接不稳定的情况下尤为常见。本…...