Eric’s Blog 👋 💻

一个小站点,记录一些技术笔记,以及一些有趣的事情。

PostgreSQL 常用终端命令总结

📌 连接与基本操作 连接数据库 # 连接到默认数据库(postgres) psql -U username # 连接到指定数据库 psql -U username -d database_name # 连接指定主机和端口 psql -h localhost -p 5432 -U username -d database_name # 直接执行SQL并退出 psql -U username -d database_name -c "SELECT * FROM users;" # 执行SQL文件 psql -U username -d database_name -f script.sql 退出psql \q -- 退出 exit -- 也可用 📋 查看信息命令 数据库相关 -- 列出所有数据库 \l \l+ -- 显示更多信息 -- 查看当前连接的数据库 \c -- 切换数据库 \c database_name -- 查看数据库大小 \l+ -- 包含大小信息 SELECT pg_database_size('database_name'); 表相关 -- 列出所有表 \dt \dt+ -- 显示更多信息(大小、描述等) \dt schema.* -- 查看指定schema下的表 -- 查看表结构 \d table_name \d+ table_name -- 更详细,包含注释 -- 列出所有关系(表、视图、序列等) \d \d+ -- 更详细 其他对象 -- 查看所有schema \dn \dn+ -- 查看所有视图 \dv \dv+ -- 查看所有索引 \di \di+ -- 查看所有序列 \ds \ds+ -- 查看所有函数 \df \df+ \df pattern -- 按模式匹配 -- 查看所有触发器 \dtr -- 查看所有用户/角色 \du \du+ 🔧 交互式命令设置 查询格式化 -- 设置显示模式 \x on -- 扩展显示模式(每字段一行) \x off -- 标准表格模式 \x auto -- 根据屏幕宽度自动切换 -- 设置输出格式 \a -- 切换对齐模式(对齐/不对齐) \pset format aligned -- 对齐格式 \pset format csv -- CSV格式 \pset format html -- HTML格式 \pset format json -- JSON格式 -- 显示查询时间 \timing on \timing off -- 显示执行SQL \echo on \echo off 常用组合设置 -- 生产环境推荐 \pset format aligned \pset border 2 \timing on -- 导出数据推荐 \pset format csv \pset footer off \o output.csv 📁 数据导入导出 导出数据 -- 导出查询结果为CSV \copy (SELECT * FROM table_name) TO 'output.csv' WITH CSV HEADER; -- 导出整个表为CSV \copy table_name TO 'output.csv' WITH CSV HEADER; -- 导出为CSV指定分隔符 \copy table_name TO 'output.csv' WITH CSV DELIMITER '|' HEADER; -- 导出为INSERT语句 \copy table_name TO 'dump.sql' WITH INSERT; -- 导出到文件 \o output.txt SELECT * FROM table_name; \o -- 恢复输出到屏幕 导入数据 -- 从CSV导入 \copy table_name FROM 'data.csv' WITH CSV HEADER; -- 从CSV导入指定列 \copy table_name(col1, col2) FROM 'data.csv' WITH CSV HEADER; -- 执行SQL文件 \i script.sql \include script.sql 🔍 性能调试 -- 查看查询执行计划 EXPLAIN SELECT * FROM users; EXPLAIN ANALYZE SELECT * FROM users; -- 实际执行 -- 查看详细执行计划 EXPLAIN (BUFFERS, ANALYZE, VERBOSE) SELECT * FROM users; -- 查看正在运行的查询 SELECT * FROM pg_stat_activity WHERE state = 'active'; -- 查看慢查询 SELECT * FROM pg_stat_statements ORDER BY total_time DESC LIMIT 10; -- 分析表(更新统计信息) ANALYZE table_name; ANALYZE; -- 分析所有表 💾 数据库维护 备份与恢复 # 备份数据库(命令行) pg_dump -U username database_name > backup.sql pg_dump -U username -d database_name -Fc > backup.dump # 自定义格式 # 备份特定表 pg_dump -U username -t table_name database_name > table_backup.sql # 恢复数据库 psql -U username -d database_name < backup.sql # 恢复自定义格式 pg_restore -U username -d database_name backup.dump 维护命令 -- 清理并分析数据库 VACUUM; VACUUM ANALYZE; -- 清理并更新统计信息 VACUUM FULL; -- 完全清理(锁表) -- 重建索引 REINDEX INDEX index_name; REINDEX TABLE table_name; REINDEX DATABASE database_name; -- 查看数据库大小 SELECT pg_database_size('database_name'); -- 查看表大小 SELECT pg_total_relation_size('table_name'); -- 查看索引大小 SELECT pg_indexes_size('table_name'); 🛠️ 权限管理 -- 查看权限 \z \dp \dp table_name -- 授予权限 GRANT SELECT ON table_name TO username; GRANT ALL PRIVILEGES ON database_name TO username; -- 撤销权限 REVOKE INSERT ON table_name FROM username; 🎯 实用脚本示例 1. 快速查看表信息和数据量 \dt+ -- 查看所有表及大小 SELECT schemaname, tablename, n_live_tup FROM pg_stat_user_tables ORDER BY n_live_tup DESC; 2. 批量导出表为CSV -- 使用psql变量 \set table_name 'users' \copy :table_name TO '/tmp/:table_name.csv' WITH CSV HEADER; 3. 监控连接数 -- 查看当前连接数 SELECT count(*) FROM pg_stat_activity; -- 查看各数据库连接数 SELECT datname, count(*) FROM pg_stat_activity GROUP BY datname; -- 终止连接 SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname='database_name'; ⚡ 快速参考卡片 命令 用途 \l 列出所有数据库 \c dbname 切换数据库 \dt 列出所有表 \d tablename 查看表结构 \du 查看用户/角色 \dn 查看schema \df 查看函数 \x 切换扩展显示 \timing 显示执行时间 \copy ... TO 导出数据 \copy ... FROM 导入数据 \i file.sql 执行SQL文件 \q 退出 💡 小技巧 自动补全:在psql中按 Tab 键可以自动补全程SQL命令和对象名 ...

2026年5月3日 · 3 分钟 · Eric

SQLite 常用终端命令总结

📌 基础操作 连接数据库 # 打开/创建数据库 sqlite3 database.db # 打开后立即执行SQL并退出 sqlite3 database.db "SELECT * FROM users;" # 以只读方式打开 sqlite3 database.db -readonly 退出数据库 .exit -- 或 .quit 📋 查看命令(最常用) 查看基本信息 -- 查看所有表 .tables -- 查看表结构 .schema table_name -- 查看所有表的创建语句 .schema -- 查看数据库信息 .database -- 查看当前连接的数据库文件 .databases 查看索引和触发器 -- 查看索引 .indexes table_name -- 查看所有索引 .indexes -- 查看触发器 .schema -- 会显示所有触发器定义 📊 查询数据优化 设置显示格式 -- 以表格形式显示(推荐) .mode table -- 以列对齐方式显示 .mode column -- CSV格式导出 .mode csv -- JSON格式输出 .mode json -- 显示表头 .headers on -- 显示行号 .nullvalue NULL -- 将NULL显示为NULL 常用组合设置 -- 生产环境推荐配置 .headers on .mode column .nullvalue NULL -- 导出数据推荐配置 .mode csv .headers on .output output.csv 🔧 数据导入导出 导出数据 -- 导出到CSV文件 .output result.csv SELECT * FROM table_name; .output stdout -- 恢复输出到屏幕 -- 导出为SQL文件(备份) .output backup.sql .dump .output stdout -- 只导出特定表 .output table_backup.sql .dump table_name .output stdout 导入数据 -- 从CSV导入 .mode csv .import data.csv table_name -- 从SQL文件导入 .read backup.sql -- 在命令行中直接导入 sqlite3 database.db < data.sql 🔍 调试与性能 -- 显示当前设置 .show -- 开启SQL执行计时 .timer on -- 查看查询执行计划 .explain EXPLAIN QUERY PLAN SELECT * FROM table_name; -- 查看最近执行的SQL语句 .history 📁 数据库维护 备份和恢复 -- 备份整个数据库 .backup backup.db -- 备份到文件 .backup main backup.db -- 恢复备份 .restore main backup.db 数据库优化 -- 分析表,更新统计信息 ANALYZE; -- 整理数据库,回收空间 VACUUM; -- 检查数据库完整性 PRAGMA integrity_check; -- 查看数据库大小 PRAGMA page_count; PRAGMA page_size; -- 计算数据库大小(字节) SELECT page_count * page_size FROM pragma_page_count(), pragma_page_size(); 🎯 实用脚本示例 1. 快速查询脚本 #!/bin/bash # 快速查询某个表的行数 sqlite3 database.db "SELECT COUNT(*) FROM table_name;" 2. 批量执行SQL文件 # 执行SQL文件并输出结果到文件 sqlite3 database.db < query.sql > result.txt 3. 交互式查询优化 -- 开启这些设置,查询体验最佳 .headers on .mode column .timer on .echo on -- 显示执行的SQL -- 执行长查询时开启 .timer on .explain SELECT * FROM large_table WHERE condition; 💡 常用操作组合 快速查看表结构 -- 查看所有表 .tables -- 查看特定表详情 .schema table_name -- 预览数据(前10行) SELECT * FROM table_name LIMIT 10; 导出特定表为CSV .mode csv .headers on .output output.csv SELECT * FROM table_name WHERE condition; .output stdout .mode table -- 恢复默认 数据库迁移 -- 导出整个数据库 .output full_backup.sql .dump .output stdout -- 只导出表结构 .output schema_only.sql .schema .output stdout ⚡ 快速参考卡片 命令 用途 .tables 列出所有表 .schema 查看表结构 .database 查看数据库信息 .mode [csv|column|table|json] 设置输出格式 .headers on|off 显示/隐藏表头 .output filename 重定向输出到文件 .import file.csv table 导入CSV .dump 导出SQL备份 .backup file.db 创建完整备份 .timer on 显示执行时间 .exit 退出 这些命令基本覆盖了日常开发中90%的SQLite使用场景。遇到复杂查询时,先用 .explain 分析查询计划,用 .timer on 测量性能,然后根据需要进行优化。

2026年5月3日 · 2 分钟 · Eric

ABAC 模型在列表查询中的应用

查询接口使用 ABAC 策略模型 ABAC 策略处理逻辑扩展为一个 通用 Node.js 类,它可以根据策略自动生成 MongoDB 查询过滤条件,用于在「列表查询接口」中动态控制数据可见性。 🎯 设计目标 这个类要做到以下几点: 支持加载多条策略; 根据用户信息(roles, attributes 等)和操作类型(action)生成 MongoDB 查询过滤条件; 支持组合策略(多策略叠加); 支持多种条件表达式(==, !=, in, not in, and, or, >,<,>=,<=等); 输出标准 MongoDB 查询对象,可直接传入 Model.find(filter)。 🧩 策略示例 const policies = [ { name: 'operator-view-online', effect: 'allow', subjectExpr: 'operator', resourceExpr: 'device', action: 'view', condition: { and: [ { in: ['operator', { var: 'user.roles' }] }, { '==': [{ var: 'resource.status' }, 'online'] } ] }, priority: 5 }, { name: 'manager-view-all', effect: 'allow', subjectExpr: 'manager', resourceExpr: 'device', action: 'view', condition: { in: ['manager', { var: 'user.roles' }] }, priority: 10 } ]; 🧱 通用 ABAC 查询构造类 class ABACQueryBuilder { constructor(policies = []) { this.policies = policies; } /** * 生成 MongoDB 查询过滤条件 * @param {Object} user - 用户信息,如 { id, roles, projectId, department } * @param {String} action - 动作,如 'view', 'edit' * @param {String} resource - 资源类型,如 'device', 'product' * @returns {Object} MongoDB 查询条件 */ buildQuery(user, action, resource) { const matchedPolicies = this.policies .filter(p => p.action === action && p.resourceExpr === resource) .sort((a, b) => b.priority - a.priority); if (matchedPolicies.length === 0) { return { _id: { $exists: false } }; // 无策略则拒绝访问 } const allowFilters = []; const denyFilters = []; for (const policy of matchedPolicies) { const condition = this._evaluateCondition(policy.condition, user); if (!condition) continue; const filter = this._conditionToMongo(policy.condition, user); if (policy.effect === 'allow') { allowFilters.push(filter); } else { denyFilters.push(filter); } } // 最终 MongoDB 查询组合规则 let query = {}; if (allowFilters.length > 0) { query = { $or: allowFilters }; } if (denyFilters.length > 0) { query = { $and: [query, { $nor: denyFilters }] }; } return query; } /** * 将条件表达式转换为 MongoDB 查询过滤条件 */ _conditionToMongo(condition, user) { if (!condition) return {}; if (condition.and) { return { $and: condition.and.map(c => this._conditionToMongo(c, user)) }; } if (condition.or) { return { $or: condition.or.map(c => this._conditionToMongo(c, user)) }; } const key = Object.keys(condition)[0]; const [left, right] = condition[key]; const leftVal = this._resolveVar(left, user); const rightVal = this._resolveVar(right, user); switch (key) { case '==': if (this._isResourceVar(left)) { return { [leftVal]: rightVal }; } else if (this._isResourceVar(right)) { return { [rightVal]: leftVal }; } return {}; case '!=': if (this._isResourceVar(left)) { return { [leftVal]: { $ne: rightVal } }; } return {}; case 'in': if (this._isResourceVar(left)) { return { [leftVal]: { $in: rightVal } }; } else if (this._isResourceVar(right)) { return { [rightVal]: { $in: leftVal } }; } return {}; case 'not in': if (this._isResourceVar(left)) { return { [leftVal]: { $nin: rightVal } }; } return {}; case '>': if (this._isResourceVar(left)) { return { [leftVal]: { $gt: rightVal } }; } break; case '>=': if (this._isResourceVar(left)) { return { [leftVal]: { $gte: rightVal } }; } break; case '<': if (this._isResourceVar(left)) { return { [leftVal]: { $lt: rightVal } }; } break; case '<=': if (this._isResourceVar(left)) { return { [leftVal]: { $lte: rightVal } }; } break; default: return {}; } return {}; } /** * 判断 { var: 'xxx' } 是否为资源变量 */ _isResourceVar(value) { return typeof value === 'object' && value.var && value.var.startsWith('resource.'); } /** * 从 { var: 'user.xxx' } 中解析变量 */ _resolveVar(expr, user) { if (typeof expr !== 'object' || !expr.var) return expr; const path = expr.var.split('.'); if (path[0] === 'user') { return path.slice(1).reduce((obj, key) => obj?.[key], user); } else if (path[0] === 'resource') { return path.slice(1).join('.'); // 资源字段返回为路径字符串 } return expr; } /** * 简单评估条件(判断用户是否符合该策略) */ _evaluateCondition(condition, user) { if (!condition) return true; if (condition.and) return condition.and.every(c => this._evaluateCondition(c, user)); if (condition.or) return condition.or.some(c => this._evaluateCondition(c, user)); const key = Object.keys(condition)[0]; const [left, right] = condition[key]; const leftVal = this._resolveVar(left, user); const rightVal = this._resolveVar(right, user); switch (key) { case '==': return leftVal === rightVal; case '!=': return leftVal !== rightVal; case 'in': return Array.isArray(rightVal) ? rightVal.includes(leftVal) : false; case 'not in': return Array.isArray(rightVal) ? !rightVal.includes(leftVal) : false; case '>': return leftVal > rightVal; case '>=': return leftVal >= rightVal; case '<': return leftVal < rightVal; case '<=': return leftVal <= rightVal; default: return false; } } } ✅ 使用示例 const user = { id: 'u1', roles: ['operator'], projectId: 'p1' }; const qb = new ABACQueryBuilder(policies); // 生成设备列表过滤条件 const mongoFilter = qb.buildQuery(user, 'view', 'device'); console.log(JSON.stringify(mongoFilter, null, 2)); /* 输出: { "$or": [ { "status": "online" } ] } */ // 可直接用于 Mongoose 查询 // DeviceModel.find(mongoFilter) 🧠 特点总结 策略驱动查询:无须在代码中硬编码角色逻辑; 灵活扩展:新增策略只需在数据库或配置中定义; 兼容性好:输出标准 MongoDB 查询条件; 安全可控:未匹配策略默认拒绝访问。 非常好 👍,我们现在在上面的 ABACQueryBuilder 基础上,扩展出一个适用于 Node.js + Express + MongoDB (Mongoose) 的 通用权限中间件系统。 ...

2025年10月18日 · 8 分钟 · Eric

混合型权限系统(RBAC + ABAC Hybrid Access Control)

在 IoT SaaS 系统(物联网多租户云平台)中,权限体系的设计至关重要,因为它不仅要满足传统的 用户-角色-权限 管理,还要处理 设备、产品、项目、组织、租户、数据流、操作权限 等多维场景。 单一的 RBAC 模型在 IoT 场景中往往不够灵活,因此需要引入 RBAC + ABAC 的混合设计。 下面将分 7 个部分为你完整讲解 IoT SaaS 系统中的 RBAC + ABAC 混合权限模型设计,并提供可直接落地的通用范例。 🧩 一、IoT SaaS 系统的权限需求特征 IoT 平台的典型多维结构如下: 租户(Tenant) └── 项目(Project) ├── 产品(Product) │ ├── 设备(Device) │ ├── 功能点(Feature) │ └── 数据流(Telemetry) └── 成员(User) 主要权限控制目标: 维度 示例需求 用户 → 资源 某个用户是否能查看设备详情 用户 → 动作 某个用户是否能远程控制设备 状态条件 设备在线时才允许下发指令 数据隔离 不同租户、项目、产品的数据隔离 动态策略 不同产品状态、设备类型、标签影响权限 运维与监管 部分角色仅能查看但不能操作设备 这些场景无法单靠 RBAC 静态角色覆盖,因此引入 ABAC 动态属性判定。 ...

2025年10月13日 · 10 分钟 · Eric

AI学英语计划

来源:deepseek 第一阶段:基础搭建(1-3个月) 目标:掌握技术场景高频词汇,建立基本听力反应能力 1. 每日学习模块(6:00-7:30) 时间 内容 具体方法 6:00 唤醒耳朵(15min) 听慢速技术播客(如《Software Engineering Daily》慢速版),仅专注识别关键词 6:15 核心词汇突破(30min) - 用Anki记忆卡背技术高频词(附推荐词表)- 结合代码注释练习造句 6:45 结构化输入(30min) - 精读GitHub英文README文件- 用彩笔标注:功能描述/报错处理/API用法 7:15 影子跟读(15min) 跟读技术教程短视频(如Fireship.io),模仿语调,不求全懂 重点工具: 词汇表:Tech English 3000词表(优先掌握前500词) 听力材料:YouTube频道《Learn English with Code》慢速版 阅读材料:精选10个Star>1k的GitHub项目文档 第二阶段:实战强化(4-6个月) 目标:听懂技术视频核心逻辑,流畅阅读官方文档 1. 每日学习模块(6:00-7:30) 时间 内容 具体方法 6:00 沉浸式听力(30min) 看YouTube技术视频(如AWS re:Invent演讲):- 第一遍关字幕抓主干- 第二遍开英文字幕补细节 6:30 文档解剖术(30min) 精读Stack Overflow高票答案+官方文档(如React Docs):- 用思维导图梳理逻辑链- 摘录万能句式(如"How to troubleshoot X") 7:00 场景输出(30min) - 用英语写代码注释- 在Reddit的r/learnprogramming版块回答简单问题 关键技巧: 听力突破:使用Chrome插件Language Reactor,自动生成双语字幕并标记高频词 阅读加速:安装Readwise高亮整理工具,建立个人技术英语语料库 查词策略:用剑桥技术词典而非普通词典,理解术语精准定义 第三阶段:自主应用(7-9个月) 目标:无字幕看懂技术会议视频,30分钟内速读英文RFC文档 ...

2025年10月6日 · 1 分钟 · Eric