Knex: كيف تنفذ استعلامات متعددة في تشغيل واحد؟

تم إنشاؤها على ٢٩ أبريل ٢٠١٤  ·  40تعليقات  ·  مصدر: knex/knex

أواجه مشكلة أود تنفيذ استعلامات متعددة مفصولة بعلامة "؛" بواسطة exec واحد ، هل هذا ممكن؟

يبدو رمز الاختبار الخاص بي الذي فشل على النحو التالي:

      var query = '' +
        'UPDATE "records_raw" ' +
        'SET "title" = ? ' +
        'WHERE "id" = ?' +
        ';' +
        'UPDATE "records_raw" ' +
        'SET "title" = ? ' +
        'WHERE "id" = ?' +
        ';';

      var bindings = [
        "x", "1",
        "y", "2"
      ];

      knex.raw(query, bindings).exec(function(err, result) {
        assert.isNotError(err);
      });

الخطأ:

Error(cannot insert multiple commands into a prepared statement, ...

هل هناك طريقة لتعطيل البيانات المعدة لمثل هذه الاستفسارات؟

feature request

التعليق الأكثر فائدة

أي تحديث ؟
هل من الممكن الآن عمل استعلام متعدد؟
إذا كان الأمر كذلك ، فما استخدام بناء الجملة؟

ال 40 كومينتر

كلا ، سيتعين عليك تنفيذها كبيارتين.

حسنًا ، هذا حل محدود بعض الشيء

يمكنك محاولة استدعاء toString() للاستعلام وتنفيذ ذلك ، لكنني لا أوصي بذلك حقًا.

knex.raw(knex.raw(query, bindings) + '').exec(function(err, result) {
  assert.isNotError(err);
});

حسنًا ، سأرى ما يجب القيام به بهذا ، في الأساس ، أود فقط إيقاف تشغيل العبارات المعدة والاحتفاظ بالقدرة على وجود سلسلة استعلام وارتباطات ، لكنني لا أعرف ما إذا كان ذلك ممكنًا ، لم أجد أي وثائق متعلقة بهذه.

على أي حال ، حاولت

knex.raw(query, bindings) + ''

لكنه يرمي - كائن الكائن ليس له طريقة "استنساخ".

إذا كنت تريد تجربة الفرع 0.6.0 ، فأنا أعلم أنه سيعمل هناك ، ويجب تحريره بمجرد الانتهاء من الاختبارات لبعض الأشياء.

لماذا رغم ذلك ، هل تحتاج إلى تنفيذ عبارتين من طلبات البحث باستخدام سلسلة واحدة من هذا القبيل؟ أليس هذا نوعًا ما يتعارض مع الغرض من استخدام الحزمة؟

أنا شخصياً أحتاج إلى كسب عدة INSERT ... ON DUPLICATE KEY UPDATE في وقت واحد. لا يمكنني إجراء إدراج بقيم متعددة لأنني أرغب في معرفة الصف الذي تم تحديثه وأي صف تم إنشاؤه (التحقق من قيمة الصف المتأثر).

لقد كنت ألعب مع منشئي استعلام مختلفين لـ node.js بعد أن وجدنا قيود Knex (والتي نتجت أساسًا عن استخدام الاستعلامات الأولية في معظم الأوقات). في النهاية ، قمت للتو بترميز SQL builder بنفسي -

عرض توضيحي رائع جدًا ، كنت أخطط لإضافة شيء من هذا القبيل بعد الإصدار التالي - من الغريب ، هل قمت بتجربة الفرع 0.6؟

أتساءل عما إذا كان هناك أي مجال للتعاون هنا ، حيث قد تتمكن QSQL من تلبية الحاجة إلى منشئ استعلام أكثر قوة ، بينما تتعامل Knex مع تجميع الاتصالات وتنعيم الثآليل بين اللهجات المختلفة.

على أي حال ، عمل جيد ، سألقي نظرة عليه!

حسنًا ، لا ، لم نحاول 0.6 حيث كان لدينا الكثير من التعليمات البرمجية باستخدام knex في مكان واحد ثم إجراء بعض الاستعلامات الأولية في مكان آخر. بعد إجراء بعض الأبحاث ، قررت استبدال المكدس بالكامل بشيء يمكن صيانته وحيث يمكن إضافة الميزات على الفور.

حسنًا ، أعتقد أن هناك بالتأكيد مجالًا للتعاون ، ولكن الأمر سيستغرق بعض الوقت لتحقيق الاستقرار في QSql أولاً. أعني تحديد واجهة برمجة تطبيقات لطيفة تتوافق مع 99٪ من الاحتياجات وحالات الاستخدام (كما ترى ، لا تزال بعض التركيبات قبيحة بعض الشيء) وتنفيذ التجريد المناسب بحيث يمكن إضافة خلفيات أخرى.

ربما القدرة على تمرير مجموعة من الاستفسارات ومن ثم النتائج هي مصفوفة كذلك؟ شيء بسيط مثل هذا سيكون رائعًا ، يمكن أن يستخدم شيئًا مثل غير متزامن

niftylettuce Bluebird يأتي بالفعل مع ميزة "async.parallel" خارج الصندوق. لكن هذه ليست المشكلة. نحتاج حقًا إلى طريقة لتنفيذ استعلامات منفصلة عن الغيبوبة في جولة واحدة.

أليس هذا ممكنًا بمجرد وضع العلامات

    multipleStatements: true

في كتلة الاتصال لتكوين الشخص:
على سبيل المثال

    connection: {
        host: 'localhost',
        user: 'superSecret',
        password: 'notGonnaTell',
         port: 8889,
        database: 'babelverse_core',
        multipleStatements: true
    }

حسنًا ، إذا كان أي شخص هنا مهتمًا - فأنا أعمل على بعض الأشياء الجديدة في إعادة البناء القادمة لجعل هذا ممكنًا.

أنا أتساءل عما سيكون عليه api المثالي لهذا ... هل نريد أن يكون لدينا سلسلة واحدة؟

knex
  .update('records_raw')
  .set({title: x}).where({id: 1})
  .end()
  .update('records_raw')
  .set({title: y}).where({id: 2})
  .spread((resultA, resultB) => {

  })

أو شيء من هذا القبيل:

knex.multiQuery([
  knex.update('records_raw').set({title: x}).where({id: 1})
  knex.update('records_raw').set({title: y}).where({id: 2})
]).spread((resultA, resultB) => {

})

النظر أيضًا في إمكانية جعل حالة knex.raw تعمل تلقائيًا عن طريق تقسيم الفاصلة المنقوطة.

سيكون التقسيم على الفاصلة المنقوطة على الاستعلامات الأولية بداية رائعة.

أواجه مشكلة الآن حيث لم يكتمل الحذف في الوقت المناسب قبل الإدراج ، لذلك أتلقى أخطاء رئيسية مكررة يتم إلقاؤها.

أنا أفعل شيئًا مثل

knex("mytable")
.where({
  id: 32423
})
.del()
.then( ->
  knex("mytable")
  .insert()
 ..... 

تحصل على جوهر ..

لا يكتمل ديل في الوقت المناسب.

tgriesser تصويتي هو knex.multiQuery

tgriesser أي تحديث للقدرة على تنفيذ عبارات متعددة في استعلام واحد؟ انا افضل:

.update ('records_raw')
.set ({title: x}). حيث ({id: 1})
.نهاية()
.update ('records_raw')
.set ({title: y}). حيث ({id: 2})
ثم (وظيفة (نتيجة) {
النتيجة [0] // النتيجة 1
النتيجة [1] // النتيجة 2
})
.catch (وظيفة (يخطئ) {
console.log (يخطئ) ؛
}) ؛

+1

من أجل القيام بالتقسيم الصحيح للفواصل المنقوطة ، سنحتاج إلى تحليل الاستعلام الخام بالكامل باستخدام محلل خاص باللهجة. على وجه التحديد ، إذا كانت السلاسل تحتوي على ; ، فيجب تجاهلها. فيما يلي مثالان على SQL الصالحة التي قد تكون غير بديهية لتحليلها.

-- generic SQL
SELECT * FROM book WHERE title = 'Lord of the Rings; The Fellowship of the Ring';
-- MySQL specific
CREATE PROCEDURE dorepeat(p1 INT)
  BEGIN
    SET <strong i="9">@x</strong> = 0;
    REPEAT SET <strong i="10">@x</strong> = <strong i="11">@x</strong> + 1; UNTIL <strong i="12">@x</strong> > p1 END REPEAT;
  END

لاحظ أيضًا في الحالة الأولى أننا سننتهي بعبارتين ، لذلك سيحتاج الكود إلى مراعاة النتائج الفارغة من الانقسام.

بصراحة ، بشكل عام ، أعتقد أن هذه فكرة سيئة. هناك فرصة كبيرة جدًا لإدخال SQL وعدم تقسيم الاستعلامات بشكل صحيح.

أيضًا ، عند تنفيذ عدة كشوفات ، فأنت تريد دائمًا أن يحدث ذلك في نفس المعاملة. لقد نجحت Knex بالفعل في حل هذه المشكلة بشكل جيد باستخدام صيغة .transacting(function(transaction) { /* code */ }) . في الحالة النادرة التي لا تحتاج فيها إلى معاملة ، يمكنك ببساطة استخدام بلوبيرد للانضمام إلى كشوف حساباتك في knex والحصول على النتائج.

لذلك بسبب هذه القضايا ، فإن رأيي هو أن هذا لا ينبغي أن يحدث.

: -1:

أيضًا ، عند تنفيذ عدة كشوفات ، فأنت تريد دائمًا أن يحدث ذلك في نفس المعاملة. لقد نجحت Knex بالفعل في حل هذه المشكلة بشكل جيد باستخدام صيغة .transacting(function(transaction) { /* code */ }) . في الحالة النادرة التي لا تحتاج فيها إلى معاملة ، يمكنك ببساطة استخدام بلوبيرد للانضمام إلى كشوف حساباتك في knex والحصول على النتائج.

يمكنني أن أخبرك من التجربة أنه في حالات معينة ، هناك فرق كبير في الأداء بين هذين النهجين وتجميع قيم متعددة إلى الخادم كأمر واحد.

أتفهم أنه من الصعب جدًا التنفيذ بشكل نظيف ، وهذا هو سبب عدم القيام بذلك حتى الآن ، ولكن هذه المشكلة حدت بشكل كبير من استخدامي لـ knex لمشروع ما.

كانت لدي مشكلة مماثلة وتمكنت من حلها. انظر هنا. https://github.com/tgriesser/knex/issues/1075

أنا أخفق في رؤية أي حالة استخدام لهذه الميزة. أود إغلاق هذه التذكرة لأنها لن تصلح. إذا كان أحدهم يعتمد على ترتيب الاستعلامات التي يتم تشغيلها على نفس الاتصال ، فمن المحتمل أنك تريد استخدام المعاملات.

الشيء الوحيد الذي أراه يجعل استخدام "الاستعلام المتعدد" هذا في شيء نرغب في الحصول عليه هو أنه يفوز بالأداء المحتمل في بعض الحالات. يتطلب عددًا أقل من الرحلات ذهابًا وإيابًا لتوصيل جميع الاستفسارات والنتائج من الخادم وإليه.

لكن الأمر لا يعني أن لدي حالة استخدام قابلة للقياس. التحدث فقط من تجربة / ذاكرة سابقة ...

@ Jurko-gospodnetic قد يكون الأمر كذلك عندما لا يكون لديك تجميع للاتصالات. مع التجميع ، يتم إرسال استعلامات متعددة بشكل أساسي إلى مجرد وضع البيانات في مقبس TCP الذي تم إنشاؤه بالفعل. أيضًا إذا كان أداؤك يعتمد على عدم امتلاء مخازن TCP المؤقتة بشكل كافٍ ، فإن knex يكون بالفعل بطيئًا جدًا بالنسبة لك :) في هذه الحالة ، من الأفضل استخدام برنامج التشغيل مباشرة.

@ jurko-gospodnetic علق في 20 مايو

الشيء الوحيد الذي أراه يجعل استخدام "الاستعلام المتعدد" هذا في شيء نرغب في الحصول عليه هو أنه يفوز بالأداء المحتمل في بعض الحالات. يتطلب عددًا أقل من الرحلات ذهابًا وإيابًا لتوصيل جميع الاستفسارات والنتائج من الخادم وإليه.

أنا أستخدم node-mysql (mysqljs) في مشروع على مستوى المؤسسة لهذا السبب بالذات. نحن نتطلع إلى ترحيل المشروع بأكمله إلى knex.js لعدة أسباب

هناك تحسن كبير في الأداء في مثل هذه العمليات التي يمكنني الاستفادة منها من خلال الاستفادة من ميزة استعلامات العبارات المتعددة لبرنامج تشغيل node-mysql (mysqljs) .

قد يكون الأمر بمثابة أداة عرض بالنسبة لي إذا لم تدعم Knex ذلك. لذا سأحيي هذا الموضوع لأطلب ذلك فقط.

هل الاستعلامات المتعددة في بيان واحد مدعومة في Knex.js الآن؟

nicholaswmin ، هل يمكنك أن تقول بشكل أكثر تحديدًا ما الذي

elhigu لا توجد معايير ولكن على

تؤدي مكالمة واحدة إلى قاعدة البيانات (معبأة بجميع البيانات) إلى التخلص من الرحلات ذهابًا وإيابًا لشبكة الخادم.

من ناحية أخرى ، فإن إرسال استعلامات متعددة من خلال نفس الاتصال ليس رصاصة فضية. لن يعمل هذا الحل إلا مع التدفقات غير المتعلقة بالمعاملات ، راجع هذه المشكلة

nicholaswmin هل ترسل قدرًا هائلاً من الاستفسارات الصغيرة وغالباً ما يتم تجاهلها أو نتائج صغيرة؟ في هذه الحالة ، أفترض أن الاختلاف قد يكون ملحوظًا ، لأنه يسمح للسائق بحزم استعلامات متعددة لكل حزمة TCP ، وإلا فسيكون لكل حزمة TCP رؤوس في الغالب وكمية صغيرة من الحمولة.

يجب أن يكون هذا النوع من الاختلاف في الأداء قابلاً للقياس بسهولة حتى من حجم حركة مرور الشبكة.

لا أعرف ما إذا كانت برامج التشغيل تدعم إرسال استعلامات متعددة من مكالمات منفصلة connection.query إلى DB دون الانتظار أولاً لنتائج المكالمات السابقة. إذا فعلوا ذلك ، فلا ينبغي أن يكون هناك اختلاف كبير في حركة مرور TCP بين إرسال عدة connection.query أو استعلام متعدد واحد مدعوم من قبل مشغل mysql.

elhigu إنها استعلامات صغيرة بالفعل ولكن نتائجها مطلوبة حتى يمكن استخدامها بشكل أكبر أسفل سلسلة المعاملات / الاستعلام.

هل هناك أي طريقة يمكنني من خلالها رؤية حزم TCP التي يتم إرسالها عبر تصحيح الأخطاء أو خيار مشابه؟ لا يتم إرسال الاستعلامات نفسها ولكن الحزم الفعلية.

حالة استخدام:

عند تحديث بيانات مستخدم في نظامي ، أود حساب مسار التدقيق (ما تغير) لهذا المستخدم.

// # PSEUDOCODE

// get current data of user
getUserData();
// set data of user
setUserData()
// get new data of user
getUserData()
// compute the audit trail by comparing the difference between before-set/after-set datums
computeAuditTrail(previousData, newData);

تقوم كل من المكالمات المذكورة أعلاه بإجراء مكالمات DB متعددة ، لذا يمكنك أن تتخيل أن هذه هي الكثير من الرحلات ذهابًا وإيابًا عبر الشبكة.

كما هو مذكور في # 1806 ، يمكنني التغلب على هذا باستخدام Promise.all() للاستعلامات التي لا تحتاج إلى أن تكون متسلسلة (في الغالب لا تحتاج مكالمات DB في getData/setData إلى أن تكون متسلسلة).

سيعمل ذلك مع التدفقات غير المتعلقة بالمعاملات ، حيث يمكن إرسال الاستعلامات عبر اتصالات مختلفة من المجمع. بمجرد استخدام معاملة لأداء التدفق أعلاه ، فإنها تبطئ (حوالي 4x) حيث يتم إرسال الاستعلامات على اتصال واحد.

كملاحظة جانبية ، أستخدم MSSQL.

Wireshark هي أداة مشتركة بين الأنظمة الأساسية تُستخدم لتحليل حركة مرور الشبكة.

لا أعتقد أن هناك أي طريقة للوصول إلى هذا المستوى مع العقدة.

قد تكون إحدى الطرق هي استخدام iptraf أو أي شيء لقياس كمية البيانات المرسلة / المستلمة عند إرسال نفس القدر من الاستعلامات مع حزم استعلام واحد أو تمريرها بشكل منفصل إلى السائق.

أود أن أرى بناء جملة multiQuery .

أي تحديث ؟
هل من الممكن الآن عمل استعلام متعدد؟
إذا كان الأمر كذلك ، فما استخدام بناء الجملة؟

var knex = require("knex");
var _ = require("lodash");
var Promise = require("bluebird");

var knex = require('knex')({
    client: 'sqlite3',
    connection: {
        filename: "./data.sqlite"
    }
});

// Create Schema
let createScript = `

CREATE TABLE Class ( 
    Id                   integer NOT NULL  ,
    Name                 varchar(100)   ,
    CONSTRAINT Pk_Classes_Id PRIMARY KEY ( Id )
 );

CREATE TABLE Material ( 
    Id                   integer NOT NULL  ,
    Description          varchar(500)   ,
    CONSTRAINT Pk_Material_Id PRIMARY KEY ( Id )
 )

-- ... and so on (leave off the last semi or remove it later) ... 

`;

let statementPromises = _.map(createScript.split(';'), (statement) => {
    return knex.raw(statement);
});

Promise.all(statementPromises).then(function() {
    console.log('Schema generated. Populating...');

     // ...

هذه مجرد حلقة ، وليست طلبات متعددة يتم إجراؤها في واحد ، وهي بطيئة

mscheffer كان السؤال:

أواجه مشكلة أود تنفيذ استعلامات متعددة مفصولة بعلامة "؛" بواسطة exec واحد ، هل هذا ممكن؟

الذي يحل إجابتي. إذا كان لديك حل أسرع وأفضل ، يرجى تقديمه.

VictorioBerra تقسيم من ; لا يعمل في الحالة العامة ، حيث يمكن أن يكون هناك ; داخل السلسلة الحرفية والتعليقات. إذا كنت تقرأ في تفريغ البيانات ، أود أن أقول إن أسهل طريقة هي توجيه كود تفريغ SQL إلى قشرة sqlite. للأسف هذا لا يعمل مع قواعد البيانات في الذاكرة ، لأنها مجرد اتصال واحد.

أيضًا في حالتك ، حيث تقوم بإنشاء سلاسل SQL في سلسلة قالب داخلية ثم تقسيمها ، باستخدام أدوات إنشاء knex.schema.* بشكل فعال نفس الشيء ، ولكن أكثر أمانًا.

على حد علمي ، لا توجد طريقة لتحقيق هذه الميزة المتمثلة في تشغيل استعلامات متعددة في أمر واحد لجميع محركات اللهجات. أعتقد أنه كان mysql و oracledb أو mssql ، اللذين كان لهما هذا الدعم ومع mysql ، لا تزال تحصل على نتيجة الاستعلام الأخير فقط كرد (والذي قد يكون جيدًا رغم ذلك).

تذكر استخدام المعاملات إذا كنت تقوم بتعديل البيانات باستخدام استعلامات متعددة بحيث يمكنك التأكد من أنها تعمل على التوالي!

تنفيذ استعلام متعدد باستخدام RAW SQL
واجهت موقفًا مشابهًا حيث احتاجت إحدى عمليات ترحيل knex إلى تشغيل CREATE DATABASE عدة مرات متتالية. كنت أتمنى فصل الاستعلامات بفواصل منقوطة ، لكن knex ألقى خطأً في بناء الجملة. الحل لذلك هو تضمين "multipleStatements": true في كائن الاتصال الخاص بك ، لذلك قد تبدو النتيجة النهائية لذلك كما يلي:

"host": "192.168.x.x",
"user": "userLogin",
"password": "userPassword",
"database": "schemaToUse",
"multipleStatements": true

بعد ذلك ، يمكنك استخدام عبارة خام مثل:

return knex.raw("CREATE DATABASE schema0; CREATE DATABASE schema1; CREATE DATABASE schema2")
   .then((result) => {
   })
   .catch((error) => {
   });

تنفيذ استعلام متعدد باستخدام منشئ استعلام KNEX
إذا كنت بحاجة إلى استخدام منشئ استعلام knex بدلاً من كتابة SQL الخام بنفسك ، فعليك تحويل النتائج في Knex.QueryBuilder إلى سلسلة ، ثم ضم استعلامات متعددة معًا. هذا مثال واحد:

// Suppose that we wanted to add 100 currency for all players in multiple games
const addCurrency = 100;
const updateCurrency = { currency: "currency + " + addCurrency };
const queries = [
   knex.table("game0.stats").update(updateCurrency),
   knex.table("game1.stats").update(updateCurrency),
   knex.table("game2.stats").update(updateCurrency),
];
const multiQuery = queries.join(";");
console.log(multiQuery);
return knex.raw(multiQuery)
   .then((result) => {
   })
   .catch((error) => {
   });

يساعد هذا أيضًا في تقليل الخطأ البشري عند كتابة استعلامات زائدة يجب تنفيذها على التوالي. مرة أخرى بشيء مثل هذا أود أن أقترح تغليفه في معاملة.

أعتقد أنه يمكن إغلاق هذا لأن هذا مقيد في الغالب بسائقي db. مطلوب على الأقل طلب الميزة المناسبة.

AksharaKarikalan حتى لو قمت بإجراء استعلامات فرعية متعددة وطرح بينها ، فإنك لا تزال تقوم باستعلام واحد فقط. لذلك أزلت التعليق الذي لا علاقة له بهذه القضية. Stackoverflow هو المكان الصحيح لطلبات استخدام knex.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات