搜索
首页web前端js教程使用 Knex.js 批量更新记录的 QL 方法

QL Approaches to Bulk Update Records with Knex.js

在 Web 开发领域,有效地使用数据库至关重要,尤其是在处理批量操作(例如一次更新多个记录)时。无论您是管理库存、处理用户数据还是处理交易,以高效可靠的方式执行批量更新的能力都是至关重要的。

在本指南中,我们将详细介绍使用 Knex.js(Node.js 的多功能查询构建器)批量更新记录的三种基本 SQL 技术。每种方法都针对不同的场景量身定制,根据您的具体用例提供独特的优势。我们将介绍:

  1. 具有多个条件的单个更新:一种允许您在单个查询中更新多个记录的方法,利用条件逻辑根据特定条件应用不同的更新。

  2. 在事务中使用单个查询进行批量更新:这种方法利用事务来确保原子性,安全高效地执行多个更新查询。

  3. 使用 onConflict 进行更新插入(插入或更新):非常适合需要插入新记录或更新现有记录而不冒重复数据风险的场景。

在以下部分中,我们将更深入地研究每种方法,检查它们的实现、优点和最佳用例。通过了解这些方法,您可以选择最适合您的特定需求的技术,从而优化应用程序中的性能和数据完整性。


1. 多条件单次更新

当涉及到更新数据库中的多条记录时,效率是关键。一项强大的技术是使用具有多个条件的单个 UPDATE 查询。当您需要根据特定条件对不同记录应用不同的更新(所有这些都在单个 SQL 语句中)时,此方法特别有用。

概念:

“多条件单次更新”方法背后的核心思想是使用单个 UPDATE 查询来修改多行,每行可能根据其独特的特征接收不同的值。这是通过在 UPDATE 查询中使用 CASE 语句来实现的,允许您为需要更新的每个字段指定条件逻辑。

为什么使用这种方法:

  • 效率:对于少量到中等数量的记录(例如几十到几百),将多个更新合并到单个查询中可以通过减少数量来显着提高性能数据库往返次数。这在处理高频更新时尤其有用。然而,对于非常大的数据集(数千或更多),这种方法可能不那么有效。我们稍后将在本指南中讨论处理大型数据集的替代方法。

  • 简单性:与执行多个单独的查询相比,使用单个查询管理更新通常更简单且更易于维护。这种方法降低了数据库交互的复杂性,并使代码更易于理解,尤其是在处理适度数量的更新时。

  • 减少开销:更少的查询意味着更少的数据库开销,这可以带来更好的整体性能。这在网络延迟或数据库负载可能影响操作速度的情况下尤其重要。
    对于大量记录,我们在本指南中探讨了其他策略,以更有效地管理潜在开销。

示例实现:

下面是一个实际示例,说明如何使用 Knex.js(Node.js 的流行 SQL 查询构建器)来实现此方法。此示例演示如何一次性更新多条记录的多个字段,使用条件逻辑根据记录的 ID 应用不同的更新:

const queryHeaderProductUpdate = 'UPDATE products SET '; // Start of the SQL UPDATE query
const updatesProductUpdate = []; // Array to hold the individual update statements
const parametersProductUpdate = []; // Array to hold the parameters for the query

const updateProducts = [
  { product_id: 1, name: 'New Name 1', price: 100, status: 'Active' },
  { product_id: 2, name: 'New Name 2', price: 150, status: 'Inactive' },
  { product_id: 3, name: 'New Name 3', price: 200, status: 'Active' }
];

// Extract the product IDs to use in the WHERE clause
const productIds = updateProducts.map(p => p.product_id);

// Build the update statements for each field
updateProducts.forEach((item) => {
  // Add conditional logic for updating the 'name' field
  updatesProductUpdate.push('name = CASE WHEN product_id = ? THEN ? ELSE name END');
  parametersProductUpdate.push(item.product_id, item.name);

  // Add conditional logic for updating the 'price' field
  updatesProductUpdate.push('price = CASE WHEN product_id = ? THEN ? ELSE price END');
  parametersProductUpdate.push(item.product_id, item.price);

  // Add conditional logic for updating the 'status' field
  updatesProductUpdate.push('status = CASE WHEN product_id = ? THEN ? ELSE status END');
  parametersProductUpdate.push(item.product_id, item.status);

  // Add 'updated_at' field with the current timestamp
  updatesProductUpdate.push('updated_at = ?');
  parametersProductUpdate.push(knex.fn.now());

  // Add 'updated_by' field with the user ID
  updatesProductUpdate.push('updated_by = ?');
  parametersProductUpdate.push(req.user.userId);
});

// Construct the full query by joining the individual update statements and adding the WHERE clause
const queryProductUpdate = `${queryHeaderProductUpdate + updatesProductUpdate.join(', ')} WHERE product_id IN (${productIds.join(', ')})`;

// Execute the update query
await db.raw(queryProductUpdate, parametersProductUpdate);

这段代码的作用:

  1. 构造查询标头:开始产品表的 UPDATE 语句。

  2. 构建条件更新:使用CASE语句根据product_id为每个字段指定不同的更新。

  3. 生成完整查询:组合更新语句和 WHERE 子句。

  4. 执行查询:运行构造的查询以将更新应用到指定记录。

通过实施此技术,您可以使用条件逻辑高效处理批量更新,使您的数据库操作更加简化和有效。

Note: In the provided example, we did not use a transaction because the operation involves a single SQL query. Since a single query inherently maintains data integrity and consistency, there's no need for an additional transaction. Adding a transaction would only increase overhead without providing additional benefits in this context.

Having explored the "Single Update with Multiple Conditions" approach, which works well for a moderate number of records and provides simplicity and efficiency, we now turn our attention to a different scenario. As datasets grow larger or when atomicity across multiple operations becomes crucial, managing updates effectively requires a more robust approach.

Batch Updates with Individual Queries in a Transaction is a method designed to address these needs. This approach involves executing multiple update queries within a single transaction, ensuring that all updates are applied atomically. Let's dive into how this method works and its advantages.


2. Batch Updates with Individual Queries in a Transaction

When dealing with bulk updates, especially for a large dataset, managing each update individually within a transaction can be a robust and reliable approach. This method ensures that all updates are applied atomically and can handle errors gracefully.

Why Use This Approach:

  • Scalability: For larger datasets where Single Update with Multiple Conditions might become inefficient, batch updates with transactions offer better control. Each query is executed separately, and a transaction ensures that all changes are committed together, reducing the risk of partial updates.

  • Error Handling: Transactions provide a safety net by ensuring that either all updates succeed or none do. This atomicity guarantees data integrity, making it ideal for scenarios where you need to perform multiple related updates.

  • Concurrency Control: Using transactions can help manage concurrent modifications to the same records, preventing conflicts and ensuring consistency.

Code Example

Here’s how you can implement batch updates with individual queries inside a transaction using Knex.js:

const updateRecordsInBatch = async () => {
    // Example data to update
    const dataToUpdate = [
        { id: 1, name: 'Updated Name 1', price: 100 },
        { id: 2, name: 'Updated Name 2', price: 200 },
        { id: 3, name: 'Updated Name 3', price: 300 }
    ];

    // Start a transaction
    const trx = await db.transaction();
    const promises = [];

    try {
        // Iterate over the data and push update queries to the promises array
        dataToUpdate.forEach(record => {
            promises.push(
                trx('products')
                    .update({
                        name: record.name,
                        price: record.price,
                        updated_at: trx.fn.now()
                    })
                    .where('id', record.id)
            );
        });

        // Execute all queries concurrently
        await Promise.all(promises);

        // Commit the transaction
        await trx.commit();
        console.log('All records updated successfully.');
    } catch (error) {
        // Rollback the transaction in case of error
        await trx.rollback();
        console.error('Update failed:', error);
    }
};

Explanation

  1. Transaction Initialization: The transaction is started using db.transaction(), which ensures that all subsequent queries are executed within this transaction.

  2. Batch Updates: Each update query is constructed and added to an array of promises. This method allows for multiple updates to be performed concurrently.

  3. Executing Queries: Promise.all(promises) is used to execute all update queries concurrently. This approach ensures that all updates are sent to the database in parallel.

  4. Committing or Rolling Back: If all queries succeed, the transaction is committed with trx.commit(). If any query fails, the transaction is rolled back with trx.rollback(), ensuring that no partial updates are applied.

Using batch updates with individual queries inside a transaction provides a reliable way to manage large datasets. It ensures data integrity through atomic transactions and offers better control over concurrent operations. This method is especially useful when Single Update with Multiple Conditions may not be efficient for very large datasets.


3. Upsert (Insert or Update) Using onConflict

When you're working with data that might need to be inserted or updated depending on its existence in the database, an "upsert" operation is the ideal solution. This approach allows you to handle both scenarios—insert new records or update existing ones—in a single, streamlined operation. It's particularly useful when you want to maintain data consistency without having to write separate logic for checking whether a record exists.

Why Use This Approach:

  • Simplicity: An upsert enables you to combine the insert and update operations into a single query, simplifying your code and reducing the need for additional checks.

  • Efficiency: This method is more efficient than performing separate insert and update operations, as it minimizes database round-trips and handles conflicts automatically.

  • Conflict Handling: The onConflict clause lets you specify how to handle conflicts, such as when records with unique constraints already exist, by updating the relevant fields.

const productData = [
  {
    product_id: 1,
    store_id: 101,
    product_name: 'Product A',
    price: 10.99,
    category: 'Electronics',
  },
  {
    product_id: 2,
    store_id: 102,
    product_name: 'Product B',
    price: 12.99,
    category: 'Books',
  },
  {
    product_id: 3,
    store_id: 103,
    product_name: 'Product C',
    price: 9.99,
    category: 'Home',
  },
  {
    product_id: 4,
    store_id: 104,
    product_name: 'Product D',
    price: 15.49,
    category: 'Garden',
  },
];

await knex('products')
  .insert(productData)
  .onConflict(['product_id', 'store_id'])
  .merge({
    product_name: knex.raw('EXCLUDED.product_name'),
    price: knex.raw('EXCLUDED.price'),
    category: knex.raw('EXCLUDED.category'),
  });

Explanation

  1. 数据定义:我们定义productData,它是表示我们要插入或更新的产品记录的对象数组。每个对象包含一个product_id、store_id、product_name、价格和类别。

  2. 插入或更新:knex('products').insert(productData) 函数尝试将 ProductData 数组中的每条记录插入到 products 表中。

  3. 处理冲突:onConflict(['product_id', 'store_id']) 子句指定如果product_id 和 store_id 的组合发生冲突,则应执行下一步。

  4. 合并(冲突时更新):当检测到冲突时,merge({...}) 方法会使用productData 中的新产品名称、价格和类别值更新现有记录。 knex.raw('EXCLUDED.column_name') 语法用于引用已插入的值,允许数据库使用这些值更新现有记录。

为了使 onConflict 子句在 upsert 操作中正确运行,所涉及的列必须是唯一约束的一部分。其工作原理如下:

  • 单个唯一列:如果您在 onConflict 子句中使用单个列,则该列在整个表中必须是唯一的。这种唯一性保证了数据库可以根据该列准确检测记录是否已经存在。
  • 多列:当 onConflict 子句中使用多列时,这些列的组合必须是唯一的。这种唯一性是通过唯一索引或约束来强制执行的,这可确保这些列的组合值在整个表中是唯一的。

索引和约束:
索引:一个或多个列上的唯一索引允许数据库有效地检查值的唯一性。当您定义唯一索引时,数据库将使用它来快速验证指定列中的值是否已存在。这使得 onConflict 子句能够准确地检测和处理冲突。

约束: 唯一约束可确保一列或多列中的值必须是唯一的。此约束对于 onConflict 子句的工作至关重要,因为它强制执行防止重复值的规则,并允许数据库根据这些列检测冲突。

与具有多个条件的单一更新方法类似,更新插入操作不需要事务。由于它涉及插入或更新记录的单个查询,因此它可以高效运行,而无需管理事务的额外开销。


结论

每种技术都具有独特的优势,从简化代码和减少数据库交互到确保数据完整性和有效处理冲突。通过选择最适合您的用例的方法,您可以在应用程序中实现更高效、更可靠的更新。

了解这些方法可以让您根据特定需求定制数据库操作,从而提高性能和可维护性。无论您是处理批量更新还是复杂的数据管理任务,选择正确的策略对于优化工作流程并在开发项目中取得更好的成果至关重要。

以上是使用 Knex.js 批量更新记录的 QL 方法的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
超越浏览器:现实世界中的JavaScript超越浏览器:现实世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

使用Next.js(后端集成)构建多租户SaaS应用程序使用Next.js(后端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

如何使用Next.js(前端集成)构建多租户SaaS应用程序如何使用Next.js(前端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:22 AM

本文展示了与许可证确保的后端的前端集成,并使用Next.js构建功能性Edtech SaaS应用程序。 前端获取用户权限以控制UI的可见性并确保API要求遵守角色库

JavaScript:探索网络语言的多功能性JavaScript:探索网络语言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是现代Web开发的核心语言,因其多样性和灵活性而广泛应用。1)前端开发:通过DOM操作和现代框架(如React、Vue.js、Angular)构建动态网页和单页面应用。2)服务器端开发:Node.js利用非阻塞I/O模型处理高并发和实时应用。3)移动和桌面应用开发:通过ReactNative和Electron实现跨平台开发,提高开发效率。

JavaScript的演变:当前的趋势和未来前景JavaScript的演变:当前的趋势和未来前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

神秘的JavaScript:它的作用以及为什么重要神秘的JavaScript:它的作用以及为什么重要Apr 09, 2025 am 12:07 AM

JavaScript是现代Web开发的基石,它的主要功能包括事件驱动编程、动态内容生成和异步编程。1)事件驱动编程允许网页根据用户操作动态变化。2)动态内容生成使得页面内容可以根据条件调整。3)异步编程确保用户界面不被阻塞。JavaScript广泛应用于网页交互、单页面应用和服务器端开发,极大地提升了用户体验和跨平台开发的灵活性。

Python还是JavaScript更好?Python还是JavaScript更好?Apr 06, 2025 am 12:14 AM

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。 1.Python以简洁语法和丰富库生态着称,适用于数据分析和Web开发。 2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

如何安装JavaScript?如何安装JavaScript?Apr 05, 2025 am 12:16 AM

JavaScript不需要安装,因为它已内置于现代浏览器中。你只需文本编辑器和浏览器即可开始使用。1)在浏览器环境中,通过标签嵌入HTML文件中运行。2)在Node.js环境中,下载并安装Node.js后,通过命令行运行JavaScript文件。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。