better-sqlite3之exec方法

better-sqlite3 中,.exec() 方法用于执行包含多个 SQL 语句的字符串。与预编译语句相比,这种方法性能较差且安全性较低,但有时它是必要的,特别是当你需要从外部文件(如 SQL 脚本)中执行多个 SQL 语句时。

使用 .exec() 方法

以下是如何使用 .exec() 方法来执行从文件中读取的 SQL 脚本,并确保正确处理错误和事务回滚。

示例代码

假设你有一个名为 migrate-schema.sql 的 SQL 文件,其中包含多个 SQL 语句,以下是完整的示例代码:

-- 创建 users 表
CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    age INTEGER NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 创建 posts 表
CREATE TABLE IF NOT EXISTS posts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    title TEXT NOT NULL,
    content TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

-- 插入一些初始用户数据
INSERT INTO users (name, age) VALUES ('Alice', 28);
INSERT INTO users (name, age) VALUES ('Bob', 25);
INSERT INTO users (name, age) VALUES ('Charlie', 30);

-- 插入一些初始帖子数据
INSERT INTO posts (user_id, title, content) VALUES (1, 'My First Post', 'This is my first post.');
INSERT INTO posts (user_id, title, content) VALUES (1, 'Another Post', 'This is another post.');
INSERT INTO posts (user_id, title, content) VALUES (2, 'Hello World', 'Hello everyone!');

-- 更新 Alice 的年龄为 29
UPDATE users SET age = 29 WHERE name = 'Alice';

-- 删除 Bob 的所有帖子
DELETE FROM posts WHERE user_id = (SELECT id FROM users WHERE name = 'Bob');

-- 查询所有用户及其帖子
SELECT u.id AS user_id, u.name, p.id AS post_id, p.title, p.content
FROM users u
LEFT JOIN posts p ON u.id = p.user_id;
const fs = require('fs');
const path = require('path');
const Database = require('better-sqlite3');

// 打开数据库连接
const db = new Database('mydb.sqlite');

// 读取 SQL 文件内容
const migrationFilePath = path.join(__dirname, 'migrate-schema.sql');
const migration = fs.readFileSync(migrationFilePath, 'utf8');

try {
    // 开始事务
    db.exec('BEGIN TRANSACTION;');

    // 执行 SQL 文件中的所有语句
    db.exec(migration);

    // 提交事务
    db.exec('COMMIT;');
    console.log('Migration completed successfully.');
} catch (error) {
    // 如果发生错误,回滚事务
    db.exec('ROLLBACK;');
    console.error('An error occurred during migration:', error.message);
}

// 关闭数据库连接
db.close();
console.log('Database connection closed.');

详细解释

  1. 读取 SQL 文件

    • 使用 fs.readFileSync() 读取 SQL 文件的内容。这里我们使用 path.join() 来确保路径的兼容性。
  2. 开始事务

    • 在执行 SQL 语句之前,首先调用 db.exec('BEGIN TRANSACTION;') 开始一个事务。这可以确保所有的 SQL 语句要么全部成功,要么全部失败,从而保持数据的一致性。
  3. 执行 SQL 文件中的所有语句

    • 使用 db.exec(migration) 执行从文件中读取的所有 SQL 语句。注意,.exec() 可以执行包含多个 SQL 语句的字符串。
  4. 提交事务

    • 如果所有 SQL 语句都成功执行,则调用 db.exec('COMMIT;') 提交事务。
  5. 错误处理和事务回滚

    • 如果在执行 SQL 语句的过程中发生错误,捕获异常并调用 db.exec('ROLLBACK;') 回滚事务,以防止部分更新导致的数据不一致问题。
  6. 关闭数据库连接

    • 最后,调用 db.close() 关闭数据库连接。

错误处理和日志记录

为了更好地调试和维护,建议增加更多的错误处理和日志记录。例如,可以在捕获异常时记录详细的错误信息:

try {
    // 开始事务
    db.exec('BEGIN TRANSACTION;');

    // 执行 SQL 文件中的所有语句
    db.exec(migration);

    // 提交事务
    db.exec('COMMIT;');
    console.log('Migration completed successfully.');
} catch (error) {
    // 如果发生错误,回滚事务
    db.exec('ROLLBACK;');
    
    // 记录详细的错误信息
    console.error('An error occurred during migration:');
    console.error('Error message:', error.message);
    console.error('Stack trace:', error.stack);
}

注意事项

  • 安全性:由于 .exec() 直接执行 SQL 字符串,因此存在 SQL 注入的风险。尽量避免直接将用户输入插入到 .exec() 调用中。如果必须这样做,请先进行严格的验证和清理。

  • 性能:与预编译语句相比,.exec() 的性能较差。如果可能的话,尽量使用预编译语句来提高性能和安全性。

  • 事务管理:当执行多个 SQL 语句时,务必使用事务来确保数据一致性。如果没有使用事务,部分语句的成功执行可能会导致数据库处于不一致状态。

完整示例

以下是一个更完整的示例,展示了如何结合信号处理机制来确保在应用程序退出时正确关闭数据库连接:

const fs = require('fs');
const path = require('path');
const process = require('process');
const Database = require('better-sqlite3');

// 打开数据库连接
const db = new Database('mydb.sqlite');

// 监听进程退出事件和其他终止信号
function handleExit() {
    try {
        db.close();
        console.log('Database connection closed gracefully.');
    } catch (error) {
        console.error('Error closing database:', error.message);
    }
}

['exit', 'SIGINT', 'SIGTERM', 'SIGHUP'].forEach((signal) => {
    process.on(signal, handleExit);
});

// 读取 SQL 文件内容
const migrationFilePath = path.join(__dirname, 'migrate-schema.sql');
const migration = fs.readFileSync(migrationFilePath, 'utf8');

try {
    // 开始事务
    db.exec('BEGIN TRANSACTION;');

    // 执行 SQL 文件中的所有语句
    db.exec(migration);

    // 提交事务
    db.exec('COMMIT;');
    console.log('Migration completed successfully.');
} catch (error) {
    // 如果发生错误,回滚事务
    db.exec('ROLLBACK;');
    console.error('An error occurred during migration:');
    console.error('Error message:', error.message);
    console.error('Stack trace:', error.stack);
}

// 模拟长时间运行的任务
setTimeout(() => {
    console.log('Long-running task completed.');
}, 60000); // 1分钟

通过这种方式,你可以确保在任何情况下都能正确关闭数据库连接,并且在执行复杂的 SQL 脚本时保持数据的一致性和完整性。如果有更多问题或需要进一步的帮助,请随时提问!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/984318.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++:string容器(下篇)

1.string浅拷贝的问题 // 为了和标准库区分,此处使用String class String { public :/*String():_str(new char[1]){*_str \0;}*///String(const char* str "\0") // 错误示范//String(const char* str nullptr) // 错误示范String(const char* str …

基于Harbor构建docker私有仓库

Harbor 是一个开源的企业级容器镜像仓库,主要用于存储、签名和扫描容器镜像。Harbor 基于 Docker Registry 构建,并在此基础上增加了许多企业级特性,以满足企业对安全性、可扩展性和易用性的需求。Harbor 的架构由多个组件组成,包…

阿里发布新开源视频生成模型Wan-Video,支持文生图和图生图,最低6G就能跑,ComFyUI可用!

Wan-Video 模型介绍:包括 Wan-Video-1.3B-T2V 和 Wan-Video-14B-T2V 两个版本,分别支持文本到视频(T2V)和图像到视频(I2V)生成。14B 版本需要更高的 VRAM 配置。 Wan2.1 是一套全面开放的视频基础模型&…

运动控制卡--概述学习

目录 概述 技术背景 常见的运动控制卡分类: 国外品牌 国内品牌 各个品牌官网 国外品牌 国内品牌 概述 运动控制卡被称作控制卡,只是因为它做成卡的形式,可以插进工控机主板上,一般走pci或pcie通讯。运动控制卡负责接收计算…

网络编程-----服务器(多路复用IO 和 TCP并发模型)

一、单循环服务器模型 1. 核心特征 while(1){newfd accept();recv();close(newfd);}2. 典型应用场景 HTTP短连接服务&#xff08;早期Apache&#xff09;CGI快速处理简单测试服务器 3. 综合代码 #include <stdio.h> #include <sys/types.h> /* See NO…

Java【网络原理】(3)网络编程续

目录 1.前言 2.正文 2.1ServerSocket类 2.2Socket类 2.3Tcp回显服务器 2.3.1TcpEchoServer 2.3.2TcpEchoClient 3.小结 1.前言 哈喽大家好&#xff0c;今天继续进行计算机网络的初阶学习&#xff0c;今天学习的是tcp回显服务器的实现&#xff0c;正文开始 2.正文 在…

SpringMvc与Struts2

一、Spring MVC 1.1 概述 Spring MVC 是 Spring 框架的一部分&#xff0c;是一个基于 MVC 设计模式的轻量级 Web 框架。它提供了灵活的配置和强大的扩展能力&#xff0c;适合构建复杂的 Web 应用程序。 1.2 特点 轻量级&#xff1a;与 Spring 框架无缝集成&#xff0c;依赖…

web—HTML

什么是web ●Web:全球广域网&#xff0c;也称为万维网(www World Wide Web),能够通过浏览器访问的网站。 在浏览器中呈现精美的网页。 1.网页由那几部分组成&#xff1f; >文字、图片、视频、音频、超链接&#xff0c;&#xff0c;&#xff0c; 2.我们看到的网页&#xf…

php虚拟站点提示No input file specified时的问题及权限处理方法

访问站点&#xff0c;提示如下 No input file specified. 可能是文件权限有问题&#xff0c;也可能是“.user.ini”文件路径没有配置对&#xff0c;最简单的办法就是直接将它删除掉&#xff0c;还有就是将它设置正确 #配置成自己服务器上正确的路径 open_basedir/mnt/qiy/te…

INFINI Labs 产品更新 | Easysearch 增加异步搜索等新特性

INFINI Labs 产品更新发布&#xff01;此次更新&#xff0c;Easysearch 增加了新的功能和数据类型&#xff0c;包括 wildcard 数据类型、Point in time 搜索 API、异步搜索 API、数值和日期字段的 doc-values 搜索支持&#xff0c;Console 新增了日志查询功能。 INFINI Easyse…

关于OceanBase与CDH适配的经验分享

CDH是Cloudera早期推出的一个开源平台版本&#xff0c;它实质上成为了Apache Hadoop生态系统内公认的安装与管理平台&#xff0c;专为企业级需求量身打造。CDH为用户提供了即装即用的企业级解决方案。通过整合Hadoop与另外十多项关键开源项目&#xff0c;Cloudera构建了一个功能…

解决VScode 连接不上问题

问题 &#xff1a;VScode 连接不上 解决方案&#xff1a; 1、手动杀死VS Code服务器进程&#xff0c;然后重新尝试登录 打开xshell &#xff0c;远程连接服务器 &#xff0c;查看vscode的进程 &#xff0c;然后全部杀掉 [cxqiZwz9fjj2ssnshikw14avaZ ~]$ ps ajx | grep vsc…

[Python爬虫系列]bilibili

[Python爬虫系列]bilibili 具体逻辑 bv号 -> 处理多P视频 -> 拿到cid -> sign -> 请求下载&#xff0c;其中sign参考前人算法&#xff08;https://github.com/SocialSisterYi/bilibili-API-collect&#xff09; b站视频下载链接 https://api.bilibili.com/x/pl…

Linux——工具(3)git——版本控制器

一、git的使用意义 在实际项目中&#xff0c;我们往往写一个项目会经历很多个版本进行测试查缺补漏&#xff0c;然后再发行&#xff0c;但如果发行后我们发现仍出现问题&#xff0c;这时我们就需要撤回到上一个版本进行修改&#xff0c;可是如果我们此时不保存上一次的修改就不…

基于Python的商品销量的数据分析及推荐系统

一、研究背景及意义 1.1 研究背景 随着电子商务的快速发展&#xff0c;商品销售数据呈现爆炸式增长。这些数据中蕴含着消费者行为、市场趋势、商品关联等有价值的信息。然而&#xff0c;传统的数据分析方法难以处理海量、多源的销售数据&#xff0c;无法满足现代电商的需求。…

对WebSocket做一点简单的理解

1.概念 WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c; 并进行双向数据传输。 HTTP协议和WebSocket协议对比&#xff1a; HTTP是短连接 WebSocke…

【AI深度学习网络】Transformer时代,RNN(循环神经网络)为何仍是时序建模的“秘密武器”?

引言&#xff1a;什么是循环神经网络&#xff08;RNN&#xff09;&#xff1f; 循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09; 是一种专门处理序列数据&#xff08;如文本、语音、时间序列&#xff09;的深度学习模型。与传统神经网络不同&#xff0c;R…

蓝桥杯备考:图论初解

1&#xff1a;图的定义 我们学了线性表和树的结构&#xff0c;那什么是图呢&#xff1f; 线性表是一个串一个是一对一的结构 树是一对多的&#xff0c;每个结点可以有多个孩子&#xff0c;但只能有一个父亲 而我们今天学的图&#xff01;就是多对多的结构了 V表示的是图的顶点集…

01 SQl注入基础步骤(数字、字符、布尔盲注、报错)

目录 1、SQL注入漏洞的概要 2、SQL注入的常规思路 3、数字型注入 4、字符型注入 5、布尔盲注 6、报错注入 1、SQL注入漏洞的概要 原理&#xff1a;通过用户输入的数据未严格过滤&#xff0c;将恶意SQL语句拼接到原始查询中&#xff0c;从而操控数据库执行非预期操作。 …

【Linux】基础IO_文件系统基础

【Linux】基础IO_文件系统基础 文件目录 【Linux】基础IO_文件系统基础C语言文件IOC语言文件接口汇总什么是当前路径&#xff1f;默认打开的三个流 系统文件I/Oopenopen的第一个参数open的第二个参数open的第三个参数open的返回值 closewriteread 文件描述符fd文件描述符的分配…