better-sqlite3之exec方法

打印 上一主题 下一主题

主题 1024|帖子 1024|积分 3072

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

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

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

假设你有一个名为 migrate-schema.sql 的 SQL 文件,其中包罗多个 SQL 语句,以下是完整的示例代码:
  1. -- 创建 users 表
  2. CREATE TABLE IF NOT EXISTS users (
  3.     id INTEGER PRIMARY KEY AUTOINCREMENT,
  4.     name TEXT NOT NULL,
  5.     age INTEGER NOT NULL,
  6.     created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  7. );
  8. -- 创建 posts 表
  9. CREATE TABLE IF NOT EXISTS posts (
  10.     id INTEGER PRIMARY KEY AUTOINCREMENT,
  11.     user_id INTEGER NOT NULL,
  12.     title TEXT NOT NULL,
  13.     content TEXT NOT NULL,
  14.     created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  15.     FOREIGN KEY (user_id) REFERENCES users(id)
  16. );
  17. -- 插入一些初始用户数据
  18. INSERT INTO users (name, age) VALUES ('Alice', 28);
  19. INSERT INTO users (name, age) VALUES ('Bob', 25);
  20. INSERT INTO users (name, age) VALUES ('Charlie', 30);
  21. -- 插入一些初始帖子数据
  22. INSERT INTO posts (user_id, title, content) VALUES (1, 'My First Post', 'This is my first post.');
  23. INSERT INTO posts (user_id, title, content) VALUES (1, 'Another Post', 'This is another post.');
  24. INSERT INTO posts (user_id, title, content) VALUES (2, 'Hello World', 'Hello everyone!');
  25. -- 更新 Alice 的年龄为 29
  26. UPDATE users SET age = 29 WHERE name = 'Alice';
  27. -- 删除 Bob 的所有帖子
  28. DELETE FROM posts WHERE user_id = (SELECT id FROM users WHERE name = 'Bob');
  29. -- 查询所有用户及其帖子
  30. SELECT u.id AS user_id, u.name, p.id AS post_id, p.title, p.content
  31. FROM users u
  32. LEFT JOIN posts p ON u.id = p.user_id;
复制代码
  1. const fs = require('fs');
  2. const path = require('path');
  3. const Database = require('better-sqlite3');
  4. // 打开数据库连接
  5. const db = new Database('mydb.sqlite');
  6. // 读取 SQL 文件内容
  7. const migrationFilePath = path.join(__dirname, 'migrate-schema.sql');
  8. const migration = fs.readFileSync(migrationFilePath, 'utf8');
  9. try {
  10.     // 开始事务
  11.     db.exec('BEGIN TRANSACTION;');
  12.     // 执行 SQL 文件中的所有语句
  13.     db.exec(migration);
  14.     // 提交事务
  15.     db.exec('COMMIT;');
  16.     console.log('Migration completed successfully.');
  17. } catch (error) {
  18.     // 如果发生错误,回滚事务
  19.     db.exec('ROLLBACK;');
  20.     console.error('An error occurred during migration:', error.message);
  21. }
  22. // 关闭数据库连接
  23. db.close();
  24. console.log('Database connection closed.');
复制代码
具体表明


  • 读取 SQL 文件

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

  • 开始事务

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

  • 实验 SQL 文件中的所有语句

    • 使用 db.exec(migration) 实验从文件中读取的所有 SQL 语句。注意,.exec() 可以实验包罗多个 SQL 语句的字符串。

  • 提交事务

    • 如果所有 SQL 语句都乐成实验,则调用 db.exec('COMMIT;') 提交事务。

  • 错误处理和事务回滚

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

  • 关闭数据库连接

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

错误处理和日志记录

为了更好地调试和维护,发起增加更多的错误处理和日志记录。例如,可以在捕获异常时记录具体的错误信息:
  1. try {
  2.     // 开始事务
  3.     db.exec('BEGIN TRANSACTION;');
  4.     // 执行 SQL 文件中的所有语句
  5.     db.exec(migration);
  6.     // 提交事务
  7.     db.exec('COMMIT;');
  8.     console.log('Migration completed successfully.');
  9. } catch (error) {
  10.     // 如果发生错误,回滚事务
  11.     db.exec('ROLLBACK;');
  12.    
  13.     // 记录详细的错误信息
  14.     console.error('An error occurred during migration:');
  15.     console.error('Error message:', error.message);
  16.     console.error('Stack trace:', error.stack);
  17. }
复制代码
注意事项



  • 安全性:由于 .exec() 直接实验 SQL 字符串,因此存在 SQL 注入的风险。只管避免直接将用户输入插入到 .exec() 调用中。如果必须如许做,请先进行严酷的验证和清理。
  • 性能:与预编译语句相比,.exec() 的性能较差。如果大概的话,只管使用预编译语句来进步性能和安全性。
  • 事务管理:当实验多个 SQL 语句时,务必使用事务来确保数据一致性。如果没有使用事务,部分语句的乐成实验大概会导致数据库处于不一致状态。
完整示例

以下是一个更完整的示例,展示了如何联合信号处理机制来确保在应用步伐退出时正确关闭数据库连接:
  1. const fs = require('fs');
  2. const path = require('path');
  3. const process = require('process');
  4. const Database = require('better-sqlite3');
  5. // 打开数据库连接
  6. const db = new Database('mydb.sqlite');
  7. // 监听进程退出事件和其他终止信号
  8. function handleExit() {
  9.     try {
  10.         db.close();
  11.         console.log('Database connection closed gracefully.');
  12.     } catch (error) {
  13.         console.error('Error closing database:', error.message);
  14.     }
  15. }
  16. ['exit', 'SIGINT', 'SIGTERM', 'SIGHUP'].forEach((signal) => {
  17.     process.on(signal, handleExit);
  18. });
  19. // 读取 SQL 文件内容
  20. const migrationFilePath = path.join(__dirname, 'migrate-schema.sql');
  21. const migration = fs.readFileSync(migrationFilePath, 'utf8');
  22. try {
  23.     // 开始事务
  24.     db.exec('BEGIN TRANSACTION;');
  25.     // 执行 SQL 文件中的所有语句
  26.     db.exec(migration);
  27.     // 提交事务
  28.     db.exec('COMMIT;');
  29.     console.log('Migration completed successfully.');
  30. } catch (error) {
  31.     // 如果发生错误,回滚事务
  32.     db.exec('ROLLBACK;');
  33.     console.error('An error occurred during migration:');
  34.     console.error('Error message:', error.message);
  35.     console.error('Stack trace:', error.stack);
  36. }
  37. // 模拟长时间运行的任务
  38. setTimeout(() => {
  39.     console.log('Long-running task completed.');
  40. }, 60000); // 1分钟
复制代码
通过这种方式,你可以确保在任何环境下都能正确关闭数据库连接,并且在实验复杂的 SQL 脚本时保持数据的一致性和完整性。如果有更多问题或需要进一步的资助,请随时提问!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

tsx81429

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表