/ / Sequelize.js का उपयोग कर 2 टेबल के बीच नेस्टेड mysql लेनदेन - mysql, डेटाबेस, लेनदेन, वादा, sequelize.js

Sequelize.js - mysql, डेटाबेस, लेनदेन, वादा, sequelize.js का उपयोग कर 2 टेबल के बीच नेस्टेड mysql लेनदेन

मेरे पास 2 अनुक्रमित मॉडल हैं (इवेंट और इन्वेंटरी2 टेबल से जुड़े)। मैंने एक Event._create विधि बनाई है ताकि मैं ईवेंट डीबी में एक ही समय में इन्वेंट्री डीबी में दर्ज कई उत्पादों के साथ एक ईवेंट बनाने के लिए इसका उपयोग कर सकूं। प्रत्येक सूची नव निर्मित घटना के event_id से जुड़ी है।

चूंकि इन सभी चीजों को सफलतापूर्वक या असफल होना चाहिए, इसलिए मैं इसे प्राप्त करने के लिए अनुक्रमित लेनदेन का उपयोग करता हूं।

शुरुआत में मैं ऐसा कुछ करने के बारे में सोच रहा था।

sequelize.transactionPromise = Promise.promisify(sequelize.transaction, sequelize);

return sequelize.transactionPromise({autocommit: 0})
.then(function(t) {
return Event.create(ev, {transaction: t})
.then(function(event){
var event_id = event.id;  // ------ (*)
return Promise.resolve([1, ..., event_number])
.then(function(){
Inventory.create({product_id: some_product_id, event_id: event_id},
{transaction: t});
});
.then(function(){
return Promise.cast(t.commit())
.then(function() { // successfully committed
return res.json(d);
}).catch(function(err){ // cannot commit somehow
return res.json(500, err.toString());
});
}).catch(function(err){  // error rollback
return Promise.cast(t.rollback())
.then(function() {
return Promise.reject("rollback: " + err.toString());
});
});
});

लेकिन यह काम नहीं करता है क्योंकि लेनदेन शुरू होने से पहले (*) का कोई मूल्य नहीं है और मुझे न्यूल की event_id देता है।

इसके बजाय मैं नीचे कुछ ऐसा करता हूं:

var Event = sequelize.model("Event");
var Inventory = sequelize.model("Inventory");

var _create = function(t, ev){
var ev_id_secret = {secret: "some random secret"};
return Promise.cast(Event.create(ev_id_secret))
.then(function(d){
ev_id_secret.id = d.id;
return true;
}).then(function(){
return Promise.resolve(_.range(ev.number_of_products))
.map(function(){
var inventory = {
event_id: ev_id_secret.id,
product_id: ev.product_id
};
return Promise.cast(Inventory._create(t, inventory));
});
}).then(function(){  // thennable a transaction
return Promise.cast(Event.update(ev, ev_id_secret, {transaction: t}));
});
};

तो मैं ऐसा कुछ कर सकता हूं।

sequelize.transactionPromise=Promise.promisify(sequelize.transaction, sequelize);
return sequelize.transactionPromise({autocommit: 0})
.then(function(t) {
return Event._create(t, ev)
.then(function(){
return Promise.cast(t.commit())
.then(function() {
return res.json(d);
}).catch(function(err){
return res.json(500, err.toString());
});
}).catch(function(err){
return Promise.cast(t.rollback())
.then(function() {
return Promise.reject("rollback: " + err.toString());
});
});
}).catch(function(err){
console.log(err.stack);
res.json(500, {error: err.toString()});
});

मैं _create के साथ क्या करता हूं कि मैं बस एक डालता हूंईवेंट डीबी में रिक्त ईवेंट (यादृच्छिक रूप से जेनरेट किया गया गुप्त) और इन्वेंटरी डीबी में कुछ खाली उत्पाद, बाद में क्वेरी के लिए इस रहस्य का उपयोग करके event_id प्राप्त करें, ईवेंट और सूची को तदनुसार अपडेट करें।

बात यह है कि जब वादा खारिज कर दिया जाता है, तोलेनदेन रोलबैक () को डीबी में खाली घटना और उत्पाद रिकॉर्ड कहा जाता है और छोड़ दिया जाता है। तो मुझे बाद में खाली रिकॉर्ड्स से निपटना होगा, जो वास्तव में परेशान है।

तो मेरा सवाल यह है कि मैं 2 टेबल के बीच सही तरीके से लेनदेन कैसे करूं? क्या मैं सही रास्ते पर हूं?

पी।एस: एक साइड सवाल के रूप में आप देख सकते हैं कि मेरा कोड वापस Promise.xxx कथन से भरा है, यह नियंत्रण प्रवाह सुनिश्चित करता है लेकिन वादा वास्तव में गन्दा हो जाता है। क्या मेरे कोड को बेहतर बनाने के लिए मैं कुछ कर सकता हूं? धन्यवाद।

उत्तर:

जवाब के लिए 3 № 1

आपका मूल कार्यान्वयन सही था। हालांकि, ईवेंट बनाने के बाद, ऑब्जेक्ट को पहले से आबादी वाले आईडी के साथ वापस आना चाहिए (मैं मानता हूं कि आप मानक ऑटो-वृद्धि वाले अनुक्रमित आईडी का उपयोग कर रहे हैं)। सभी SQL डेटाबेस इस तरह से कार्य करते हैं I समस्या की जड़ निर्धारित करने के लिए अपने आवेदन को डीबग करने की सलाह दें।

यहां sequelize का एक नमूना कार्यान्वयन हैमेरे अनुप्रयोगों में से एक से लेनदेन। मैंने अभी परीक्षण किया है और पुष्टि की है कि db.Deposit.create () को वैध आईडी वाले ऑब्जेक्ट पर हल किया गया है। मैं ब्लूबर्ड, सीक्वेलिज 2.0.0-आरसी 2, और पोस्टग्रेस्क्ल 9.3 का उपयोग कर रहा हूं

module.exports.createDeposit = function(deposit) {
return db.sequelize.transaction({isolationLevel: "READ COMMITTED" })
.then(function(t){
var strQuery = "UPDATE "Accounts" "
+ "SET "balance"="balance" + :amount, "updatedAt"=NOW() "
+ "WHERE "id"= :AccountId RETURNING *";

return sql.query(strQuery,
db.Account.build(),
{ raw: true, transaction : t },
{ AccountId: deposit.AccountId, amount: deposit.amount })

.then(function(account){
if (!account) throw new Error("Account does not exist")
return db.Deposit.create(deposit, { transaction: t });
})
.then(function(dbDeposit){
// If successful, dbDeposit object contains a valid id
if (!dbDeposit) throw new Error("Failed to create deposit");
return t.commit()
.then(function(){
return dbDeposit;
});
})
.catch(function(e){
return t.rollback()
.then(function(){
throw e;
});
});
});
};

जवाब के लिए 2 № 2

जहां तक ​​मैं कह सकता हूं, आपका मूल कार्यान्वयन सही था लेकिन सीक्वेलिज़ के नवीनतम संस्करणों में प्रबंधित लेनदेन और पूर्ण वादा समर्थन को लीवर करके बेहतर किया जा सकता है:

return sequelize.transaction({autocommit: false}, function(t) {
return Event.create(ev, {transaction: t}).then(function(event) {
return Promise.map(_.range(event_number), function (number) {
return Inventory.create({product_id: some_product_id, event_id: event.get("id")}, {transaction: t});
});
});
}).then(function(){
// Automatically comitted at this point if the promise chain returned to the transaction successfully resolved
return res.status(200).json(d);
}).catch(function(err){
// Automatically rolledback at this point if the promise chain returned to the transaction was rejected
return res.status(403).json();
});

आप दस्तावेज़ों पर प्रबंधित लेनदेन के बारे में अधिक पढ़ सकते हैं: http://sequelize.readthedocs.org/en/latest/docs/transactions/