做了这么久的Flask后端开发到第八篇终于轮到数据库了。前面几篇我们一直在处理路由、模板、Request对象这些“表面功夫”但真正的后端开发核心永远是对数据的操作。这一篇我就把Flask连接MySQL、用ORM做增删改查这件事一次性讲透从环境准备到实际代码再到我踩过的坑全部整理出来。文章适合刚接触Flask不久、想在项目中落地数据库操作的开发者也适合那些已经能跑通Hello World、但一遇到数据库就不知道怎么下手的同学。1. 环境准备先把MySQL和依赖库搞定1.1 MySQL安装与数据库创建连接MySQL的第一步是你得先有一个能用的MySQL服务。很多人卡在这一步不是因为不会写代码而是MySQL压根没装好。MySQL的安装其实不复杂但有几个关键点必须注意否则后面连接时会各种报错。我建议直接去MySQL官网下载安装包选择MySQL Community Server这是免费版本也是绝大多数项目的选择。版本方面MySQL 5.7和8.0我都用过如果没有特殊限制直接上8.0。8.0在性能、JSON支持、窗口函数方面都比5.7强不少而且现在新项目基本默认8.0起步。网上很多教程还在讲5.7是因为它稳定、资料多但对新手来说直接用8.0反而省得以后迁移。安装过程中有一步是让你设置root密码这一步不要跳过随便填一定记住你设的密码。另外有个选项是选择字符集强烈建议选utf8mb4因为这个字符集支持完整的Unicode包括中文、emoji等特殊字符。如果你用默认的latin1或者utf8mb3后面插入中文数据经常会出现乱码或者“Data too long”之类的报错。装完之后Windows用户需要把MySQL的bin目录添加到系统环境变量PATH中否则在命令行里敲mysql命令会提示找不到命令。Mac和Linux用户一般安装时自动配好了但也不绝对遇到提示找不到mysql命令时先检查环境变量。接下来创建项目专用的数据库。登录MySQL之后执行下面这条命令CREATE DATABASE flask_demo DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;这里我建了一个名为flask_demo的数据库字符集指定utf8mb4。如果你只执行CREATE DATABASE flask_demoMySQL会用默认字符集但为了保险起见建议每次都显式指定字符集和排序规则。这样建出来的库才能真正承载中文内容。1.2 Flask相关依赖安装清单数据库准备好了接下来是Python环境这边要装的库。网上很多教程是装flask-mysqldb或者MySQLdb但我要劝你直接用pymysql。理由很简单MySQLdb在某些系统上需要编译C扩展安装过程会遇到一堆依赖问题而pymysql是纯Python实现pip直接装上就能用对新手极其友好。需要安装的依赖总共就这么几个pip install flask pip install flask-sqlalchemy pip install pymysqlflask-sqlalchemy是Flask官方推荐的ORM扩展它把SQLAlchemy和Flask做了整合用起来比直接裸用SQLAlchemy方便很多。pymysql是驱动层负责让Python能和MySQL通信。装好之后你可以先测试一下pymysql能不能正常导入避免后面排查问题时多一个不确定性python -c import pymysql; print(pymysql.__version__)如果输出版本号说明驱动没问题。这一步看起来多余但结合我多年的经验大部分连接异常都可以通过这种基础检查提前排除。2. 为什么要用ORM连接配置到底怎么写2.1 ORM是什么和裸SQL比优势在哪ORM的全称是Object Relational Mapping对象关系映射。我见过很多初学者第一次听到这个概念时一脸懵觉得不如直接写SQL来得直接。我给你打个比方裸SQL就像你去菜市场买菜想买什么就亲自去挑灵活但费劲ORM就像你通过外卖平台下单你告诉平台“我要一条鲈鱼”平台帮你完成后面所有的采购、清洗、处理流程。具体到代码层面ORM让你可以这样操作数据库定义一个Python类代表一张表这个类的实例代表表中的一行记录操作这个实例的方法和属性就被ORM自动翻译成SQL语句。你不需要手写INSERT、UPDATE、DELETE这些SQL只需要操作对象即可。这样做的好处有几个。第一是安全性ORM底层使用参数化查询天然防止SQL注入攻击新手写裸SQL时很容易犯字符串拼接的错误而埋下安全漏洞。第二是可维护性业务代码里全是Python对象没有SQL字符串夹杂结构更清晰重构也更方便。第三是可移植性如果你哪天想把MySQL换成PostgreSQLORM框架下只需改一行连接配置SQL基本不用动。当然ORM也不是万能钥匙。复杂查询、多表关联、批量更新等场景ORM生成的SQL未必有手写SQL高效。但在绝大多数业务系统里ORM的效率完全够用而且开发效率远高于手写SQL。2.2 连接串配置与引擎初始化flask-sqlalchemy的配置核心是一个数据库连接串。这个连接串的格式是固定的我来拆解一下mysqlpymysql://用户名:密码主机地址:端口/数据库名?charsetutf8mb4mysqlpymysql表示使用MySQL数据库通过pymysql驱动连接用户名和密码是MySQL的登录账号信息主机地址本地开发写localhost即可端口默认3306数据库名就是你刚才创建的flask_democharsetutf8mb4这个参数非常重要不写的话中文很容易出问题完整的代码写法如下from flask import Flask from flask_sqlalchemy import SQLAlchemy app Flask(__name__) app.config[SQLALCHEMY_DATABASE_URI] mysqlpymysql://root:your_passwordlocalhost:3306/flask_demo?charsetutf8mb4 app.config[SQLALCHEMY_TRACK_MODIFICATIONS] False db SQLAlchemy(app)这里有个细节SQLALCHEMY_TRACK_MODIFICATIONS这个配置项在旧版本中默认开启会跟踪对象的修改并消耗额外内存并且会有一条警告提示。显式设置为False可以消除警告同时也是一种更合理的资源利用方式。另外注意flask-sqlalchemy 3.x版本中连接配置项的key已经改成SQLALCHEMY_DATABASE_URI而2.x版本用的是SQLALCHEMY_DATABASE_URI写法上是一样的。如果你用的是2.x配置key也是一样。但一些老项目中可能还存在SQLALCHEMY_DATABASE_URI和SQLALCHEMY_DATABASE_URI混用的记忆误区建议以官方文档为准。db SQLAlchemy(app)这一步完成了flask-sqlalchemy与应用的绑定。绑定之后你就可以在任意视图函数或业务代码中通过db这个对象来操作数据库了。3. 模型定义与数据库表初始化3.1 用户表和文章表怎么定义字段ORM的模型定义本质上就是用Python类来描述数据库表的结构。我以一个典型的用户模型为例讲解字段定义和约束。假设我们要做一个小项目有用户表和文章表。用户表包含ID、用户名、邮箱、创建时间等字段。模型定义如下from datetime import datetime class User(db.Model): __tablename__ users id db.Column(db.Integer, primary_keyTrue) username db.Column(db.String(80), uniqueTrue, nullableFalse) email db.Column(db.String(120), uniqueTrue, nullableFalse) created_at db.Column(db.DateTime, defaultdatetime.utcnow) def __repr__(self): return fUser {self.username}我来逐一解释这些字段的作用__tablename__指定数据库中的表名。如果不写SQLAlchemy会根据类名自动生成表名比如User会变成user但为了代码清晰和可控最好显式指定。db.Integer对应MySQL的INT类型primary_keyTrue表示主键主键自动自增不需要手动赋值。db.String对应VARCHAR类型括号里的数字是长度上限。uniqueTrue表示该字段的值不能重复适合用户名、邮箱这类字段。nullableFalse表示该字段不能为NULL插入数据时必须有值。db.DateTime对应DATETIME类型defaultdatetime.utcnow表示如果插入时没有显式赋值就自动填充当前UTC时间。文章表可以这样定义class Article(db.Model): __tablename__ articles id db.Column(db.Integer, primary_keyTrue) title db.Column(db.String(200), nullableFalse) content db.Column(db.Text, nullableFalse) user_id db.Column(db.Integer, db.ForeignKey(users.id), nullableFalse) created_at db.Column(db.DateTime, defaultdatetime.utcnow)这里多了一个db.ForeignKey表示文章的用户ID关联到users表的主键。这就是外键约束用于维持表间的引用完整性。后续可以用relationship实现更高级的关联查询但在这篇文章里我们先不过度展开先把增删改查跑通。3.2 建表与验证三种常见的初始化方式模型定义好了接下来要在MySQL里真正创建这些表。flask-sqlalchemy提供了db.create_all()方法它会根据所有已定义的模型自动建表非常方便。但这里有一个很容易踩的坑在调用db.create_all()之前必须先确保应用上下文已经准备好。直接在一个独立的Python脚本里写db.create_all()有可能会报错说“Working outside of application context”。解决方法是把建表操作放在app.app_context()里面或者放在视图函数、应用启动代码中。常见的写法有三种。第一种在建表的独立脚本里显式创建应用上下文with app.app_context(): db.create_all()第二种直接在应用启动入口处建表if __name__ __main__: with app.app_context(): db.create_all() app.run(debugTrue)第三种通过flask shell来操作。在命令行里敲flask shell进入交互环境然后执行db.create_all()。这种方式适合调试时使用。建表之后你可以用Navicat、MySQL Workbench或者命令行查看一下表结构确认表已经生成。我用过的工具里Navicat最方便但它是收费的。MySQL Workbench是官方免费工具功能虽重但完全够用。如果只是在命令行里查看执行SHOW TABLES;就能看到当前库里有哪些表。4. 增删改查的完整实操4.1 新增数据与事务提交机制增删改查四件事新增是第一件。用ORM新增一条数据分三步创建对象、加入会话、提交事务。# 方法一单独创建再提交 user User(username张三, emailzhangsanexample.com) db.session.add(user) db.session.commit()为什么要分成add和commit两步这里的db.session是SQLAlchemy的会话对象它负责跟踪所有对象的状态变化。db.session.add(user)只是把对象加入会话的待处理列表此时数据还没有真正写入数据库。只有调用db.session.commit()所有在会话中积累的操作才会一次性提交到MySQL。这种机制叫做工作单元模式。它的好处是你可以把多个操作放在一个事务里要么全部成功要么全部失败不会出现只插入一半数据的尴尬局面。比如注册用户时要同时往用户表和日志表各插入一条记录你可以在同一次commit中完成其中任何一个失败都会触发回滚数据库恢复到提交前的状态。commit对应的事务提交如果不想保留这次操作可以调用db.session.rollback()来回滚。我个人建议在写代码时养成一个习惯涉及写操作的地方用try-except包起来失败时调用rollback。我见过太多项目因为没处理异常数据库里出现了一些半成品数据排查起来特别痛苦。4.2 查询的各种姿势filter vs filter_by查询是增删改查里用得最多的操作也是新手最容易混淆的地方。flask-sqlalchemy提供了两个常用的条件查询方法filter和filter_by。# 查询所有用户 all_users User.query.all() # 查询第一个用户 first_user User.query.first() # 按主键查询 user db.session.get(User, 1) # filter_by方式等值条件 user User.query.filter_by(username张三).first() # filter方式支持复杂条件 user User.query.filter(User.username 张三).first()两者区别在于filter_by只支持等值匹配写法更简洁接收关键字参数filter支持任意比较运算符包括大于、小于、不等于、模糊匹配等并且需要写成User.username 张三这种形式。再举几个filter的典型用法# 年龄大于18的用户 User.query.filter(User.age 18).all() # 用户名不为空的用户 User.query.filter(User.username ! None).all() # 模糊匹配查找用户名包含张的用户 User.query.filter(User.username.like(%张%)).all() # 逻辑与条件 User.query.filter(User.username 张三, User.email ! ).all() # 逻辑或条件需要显式导入or_ from sqlalchemy import or_ User.query.filter(or_(User.username 张三, User.username 李四)).all()要注意查询返回的结果是一个Query对象并不是最终的列表。只有调用.all()才会真正执行SQL并得到所有满足条件的记录列表.first()则返回第一条记录如果没有记录则返回None。还有一个细节在flask-sqlalchemy 3.x版本中Query.get()方法已被标记为废弃推荐使用db.session.get(User, id)来按主键查询。旧教程里常见的User.query.get(1)写法虽然还能用但会有DeprecationWarning建议新代码统一使用db.session.get。4.3 修改与删除记住这一两个坑修改数据在ORM里很简单先查到要修改的对象直接改它的属性然后commit即可。# 修改用户名 user db.session.get(User, 1) if user: user.username 王五 db.session.commit()这里有个必须注意的坑如果你改了对象的属性但没有调用commit修改只体现在当前会话的缓存里MySQL里的数据并没有变。后续如果你做了其他查询可能会发现数据还是旧值然后一脸疑惑。记住一条原则ORM里任何改动都要显式调用commit才会真正落库。删除数据同样比较直接但要注意顺序先查出对象再delete再commit。# 删除用户 user db.session.get(User, 1) if user: db.session.delete(user) db.session.commit()如果删除的对象与其他表存在外键关联而外键字段又没有设置ON DELETE CASCADE之类的级联规则删除时可能会报外键约束错误。这也是新手容易困惑的地方明明是一句简简单单的delete怎么就报错了遇到这种情况要么先删除关联的子记录要么在模型里配置级联删除。为了更直观地展示增删改查的完整业务场景我写一个简单的用户管理接口把这些操作串在一起from flask import request, jsonify app.route(/users, methods[GET]) def get_users(): users User.query.all() return jsonify([{id: u.id, username: u.username, email: u.email} for u in users]) app.route(/users, methods[POST]) def add_user(): data request.get_json() user User(usernamedata[username], emaildata[email]) db.session.add(user) db.session.commit() return jsonify({id: user.id}), 201 app.route(/users/int:user_id, methods[PUT]) def update_user(user_id): user db.session.get(User, user_id) if not user: return jsonify({error: User not found}), 404 data request.get_json() user.username data.get(username, user.username) user.email data.get(email, user.email) db.session.commit() return jsonify({id: user.id, username: user.username, email: user.email}) app.route(/users/int:user_id, methods[DELETE]) def delete_user(user_id): user db.session.get(User, user_id) if not user: return jsonify({error: User not found}), 404 db.session.delete(user) db.session.commit() return jsonify({message: User deleted})这套接口跑起来之后你就能通过POST、GET、PUT、DELETE四个HTTP方法对用户数据做完整的增删改查了。用Postman或者curl测试时注意POST和PUT要传JSON格式的数据并且请求头要加Content-Type: application/json。5. 常用查询技巧与进阶玩法5.1 对查询结果排序、分页与模糊搜索实际项目中查询很少像基础增删改查那样简单。我把几个高频的查询场景单独拎出来讲这些代码我几乎每个项目都会用到。排序很常用使用order_by# 按创建时间倒序排列 articles Article.query.order_by(Article.created_at.desc()).all() # 按创建时间正序排列 articles Article.query.order_by(Article.created_at.asc()).all() # 多个条件排序 articles Article.query.order_by(Article.created_at.desc(), Article.id.desc()).all()分页有一个非常方便的paginate方法# 每页10条取第2页的数据 page 2 paginate_obj Article.query.paginate(pagepage, per_page10) # 当前页的文章列表 articles paginate_obj.items # 总页数 total_pages paginate_obj.pages # 是否有上一页 has_prev paginate_obj.has_prev # 是否有下一页 has_next paginate_obj.has_nextpaginate返回的对象包含了分页后的数据以及分页相关的元信息处理前端的分页展示特别顺手。模糊搜索用的是like加通配符# 搜索标题里包含Flask的文章 articles Article.query.filter(Article.title.like(%Flask%)).all()这里有个小技巧在MySQL中百分号%表示任意多个字符下划线_表示单个字符。如果你要搜索的字符串本身包含百分号或下划线需要用escape转义但这属于少数情况平时都直接用%包裹关键词就行。5.2 常用查询技巧速查表我把日常开发中最高频的一些查询写法整理成一个表格方便以后直接查阅需求写法查全部Model.query.all()查主键db.session.get(Model, id)查第一条Model.query.first()等值查询Model.query.filter_by(fieldvalue).first()不等值Model.query.filter(Model.field ! value).all()大于/小于Model.query.filter(Model.field value).all()模糊匹配Model.query.filter(Model.field.like(%xx%)).all()排序Model.query.order_by(Model.field.desc()).all()分页Model.query.paginate(page1, per_page10)计数Model.query.filter_by(fieldvalue).count()去重Model.query.with_entities(Model.field).distinct().all()限制数量Model.query.limit(5).all()这些写法可以组合使用比如filter加order_by再加limitSQLAlchemy会自动拼成正确的SQL语句。5.3 默认值设置与类型检查项目中经常遇到字段要设置默认值的情况比如用户积分默认0、文章状态默认“草稿”。在模型里可以直接用default参数class User(db.Model): __tablename__ users id db.Column(db.Integer, primary_keyTrue) username db.Column(db.String(80), uniqueTrue, nullableFalse) points db.Column(db.Integer, default0) status db.Column(db.String(20), defaultinactive)这里的default只是Python层面的默认值也就是说当你创建User对象没有传入points时Python会自动填入0。但如果有人绕过ORM直接往表里插数据就不会有这个默认效果。想要MySQL层面也有默认值可以加server_default参数但这属于进阶用法普通项目用default就足够。另外我在调试接口时经常会打印客户端传的数据类型。可以用type()方法查看Flask的request对象里form和args的数据都是字符串查询参数即使传的是数字也要先转换成int才能真正参与数值比较。这是后端开发中很常见的类型坑多留意一下就能少踩很多雷。6. 高频报错与排查记录6.1 连接报错、编码报错、字段报错这部分是我最想分享的因为学习中遇到的绝大多数“卡住”其实都卡在这些报错上。我把高频报错整理成了速查表。报错信息原因解决方法ModuleNotFoundError: No module named MySQLdb没安装pymysql或者没设置驱动装pymysql连接串用mysqlpymysql://ERROR 2002 (HY000): Cant connect to local MySQL server through socket /tmp/mysql.sockMySQL服务没有启动启动MySQL服务Windows检查服务列表Mac/Linux用brew services或systemctlAccess denied for user rootlocalhost密码错误或权限问题检查MySQL账号密码确认远程访问是否有授权Unknown database flask_demo没有创建数据库执行CREATE DATABASE flask_demoData too long for column username at row 1字段长度不够或字符集不支持中文加长String长度把字符集改为utf8mb4OperationalError: (pymysql.err.OperationalError) (1045, ...)认证失败检查用户名密码、host权限sqlalchemy.exc.ProgrammingError: You have an error in your SQL syntaxSQL语法错误多发生在裸SQL场景ORM下较少见检查原生SQL写法Working outside of application context在应用上下文外调用db操作把代码放入with app.app_context():中第一个错误是新手最常遇到的。因为你明明装了pymysql但flask-sqlalchemy默认会找MySQLdb如果不做任何处理就会报No module named MySQLdb。解决办法是在代码里加上一句import pymysql pymysql.install_as_MySQLdb()这句代码的作用是把pymysql伪装成MySQLdb这样SQLAlchemy在查找默认驱动时就能找到。6.2 排查思路与避坑清单排查数据库连接类的报错我的固定思路是分层排查先确认MySQL服务本身是否正常再用命令行登录测试账号密码然后写一个独立的Python脚本测试pymysql连接最后才检查Flask应用里的配置。逐层收窄很快就能定位问题具体出在哪一层。很多初学者一出问题就盯着Flask配置反复改实际上问题根本不在那一层。避坑清单方面我再分享几个实际项目里非常有价值的经验第一数据库密码不要写死在代码里尤其是准备提交到Git仓库的项目。我建议用环境变量来保存敏感信息配合dotenv之类的配置管理方式。哪怕现在只是在本地练习也应该养成这个习惯。第二commit的时机要把握好尽量让每个业务操作对应一个逻辑事务。不要在一个循环里每改一条数据就commit一次性能会很差。正确的做法是在循环里拼接操作全做完了最后统一commit。第三查询结果集转成字典很方便但不要直接把ORM对象返回给前端做JSON序列化因为ORM对象里包含很多内部状态信息而且默认没有json序列化能力。正确的做法是手动构建一个字典只包含需要的字段就像我前面接口示例里那样。第四开发阶段建议开启Flask的debug模式并且把SQLAlchemy的echo设为True这样SQLAlchemy会打印出所有执行的原生SQL语句对理解和排查问题非常有帮助。app.config[SQLALCHEMY_ECHO] True开启这个选项后每次查询、插入、更新操作都会在控制台输出对应的SQL原文。我靠着这个日志排查过无数个“为什么数据没更新”、“为什么查不到数据”的问题。等熟悉了ORM之后再把它关掉。第五删除和修改操作一定要先确认对象存在再执行操作。像我前面接口示例里那样先用db.session.get查询如果返回None就返回404响应。很多数据库错都是在“对不存在的数据做修改”或者“重复插入相同数据”时出现的。另外关于外键和关联初学者经常会问要不要在表里建外键。我的建议是正式项目表多、关系复杂的阶段外键能建就建它对数据完整性的保护是实打实的。但在做海量数据写入或高并发的场景下外键会带来额外性能开销有些团队会选择在应用层维护关联关系而不建外键。这个属于架构层面的取舍问题等你遇到对应场景再深入也不迟。关于后续的扩展方向这篇已经把连接和增删改查讲完了还有几个话题非常适合接着深入models的relationship关联查询、数据库迁移工具Alembic、多表联查、事务隔离级别等。我后面的文章会接着写relationship的一对多和多对多玩法那才是ORM真正发挥威力的地方。在实际操作中我的体会是ORM的学习曲线比裸SQL要缓得多千万不要因为一开始要理解session、filter这些概念就觉得麻烦代码写多了就会自然习惯。最后分享一个小经验遇到任何数据库操作的问题先确认你的数据到底有没有提交成功再去看代码逻辑。十次有七次是忘了commit剩下三次是查询条件写错了。
企业数字化 ERP 产品动态
相关推荐
Substrate框架实战:构建自定义区块链的核心架构与开发流程 Substrate 这名字乍一听挺学术,但在区块链开发圈子里,它是过去几年我认为最值得投入学习的一套底层框架。别被“区块链”三个字吓跑,你可以把它理解成一条链的“乐高底座”——你想做一条有自己业务逻辑的链,不需要从零写共识、写… · 2026/9/26 4:54:12
压缩包隐写与取证分析:从ZIP结构到CTF实战 1. 压缩包不只是“打包”:从文件结构看隐写空间很多人对压缩包的理解停留在“把一堆文件压成一个小包,方便传输”这个层面。但如果你接触过CTF里的Misc方向,或者做过电子数据取证相关的工作,就会知道压缩包本身就是一个天然的隐写… · 2026/9/26 4:54:12
微信数据库密钥提取工具:C#进程内存扫描与SQLCipher解密 简介:这是一套基于C#实现的微信数据库密钥获取小工具完整源码,附带sln解决方案,面向程序开发学习者,尤其适合毕业设计、期末大作业或课程实训中的桌面应用开发场景。压缩包共8个文件,涵盖C#源码、项目工程文件、解决方… · 2026/9/26 4:54:12
Vibe Coding时代,架构决策如何不翻车? Vibe Coding这个词,最近半年在圈子里几乎是绕不开的话题。我自己的项目里也有大量代码是这么写出来的——打开编辑器,把需求往对话窗口一丢,AI就把一坨能跑的功能代码给你生成完,连注释都带好。说句实话,第一次用Codex… · 2026/9/26 5:22:21
嵌入式I2C通信失败排查全流程:从万用表静态检查到示波器NACK定位 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 5:22:21
SMA黏菌算法优化SVM/SVR/LSSVM超参数实战指南 直接说结论:用SVM/SVR做分类或回归建模,模型表现的上限往往不是算法本身,而是惩罚参数C和核函数参数没调好。网格搜索慢,随机搜索看脸,贝叶斯优化又要装一堆额外依赖。我这两年一直在做各种回归预测和分类建模… · 2026/9/26 5:22:15
Modbus RTU转Web API:RS-485设备物联网接入服务器框架 1. 项目背景与整体思路拆解1.1 为什么要把 485 设备搬上 Web API在工厂车间、配电房、农业大棚、楼宇自控这些场景里摸爬滚打久了,你会发现一个特别现实的问题:现场成千上万的传感器、电表、PLC、变频器,十有八九还是靠着 RS-485 总线在跑。这… · 2026/9/26 5:22:09
彻底关闭广告弹窗:从系统通知到浏览器劫持的完整排查指南 广告弹窗这东西,烦人程度跟夏天厕所里的蚊子差不多:打了一只,换个地方又冒出来。这些年我帮朋友清理电脑,见过最夸张的一台机器,开机后右下角、桌面、浏览器三路夹击,前前后后弹出八九个窗口,连… · 2026/9/26 5:22:03
HTML CSS网页制作成品交付指南:从结构搭建到打包避坑全解析 简介:这是一份以爱与婚姻为主题的网页制作入门实例,压缩包内共7个文件,包含1个HTML页面、1个CSS样式表及5张JPG图片素材,整体大小约336KB,适合刚接触HTML与CSS的前端初学者动手练习。资源围绕“千年之恋”这一视觉主题… · 2026/9/26 5:21:57
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46