2017-03-08 8 views
0

私は、UPDATEを最初に実行した後にUNIQUEキー制約に違反するINSERTを実行して、アプリケーション内のnode-mysqlトランザクションをテストしています。 INSERTが失敗している間、ROLLBACKとのトランザクションにもかかわらず、最初のUPDATEが成功しています。 MySQL UPDATEは暗黙的なコミットを実行しないので、ここでは正確に何が起こっているのか分かりません。ユニークなキー違反の後にnode-mysqlトランザクションがロールバックされない

pool.getConnection(function (err, connection) { 

    connection.beginTransaction(function (err) { 
     if (err) { 
      console.log(" --- error 1: " + JSON.stringify(err)); 
     } 

     console.log(" --- A"); 

     connection.query('update course_person set rescheduled_date = CURDATE() where idperson = ? and rescheduled_date is null', [idperson], function (err, rows, fields) { 

      if (err) { 
       connection.rollback(function() { 
        console.log(" --- error 2: " + JSON.stringify(err)); 
       }); 

       console.log(" --- B"); 

      } 

      console.log(" --- C"); 

     }); 

     connection.query('insert into course_person (idcourse, idperson) VALUES (?, ?)', [newidcourse, idperson], function (err, rows, fields) { 

      if (err) { 
       connection.rollback(function() { 
        console.log(" --- error 3: " + JSON.stringify(err)); 
       }); 

       console.log(" --- D"); 

      } 

      console.log(" --- E"); 

     }); 

     connection.commit(function (err) { 
      if (err) { 
       connection.rollback(function() { 
        console.log(" --- error 4: " + JSON.stringify(err)); 
       }); 

       console.log(" --- F"); 

      } 

      console.log(" --- G"); 

      req.flash('success', 'Person was updated successfully.'); 
      res.redirect('/person/' + idperson); 

      connection.release(); 
     }); 

    }); 

}); 

私は、次の出力シーケンスを取得しています:

--- A 
--- C 
--- D 
--- E 
--- G 
--- error 3: {"code":"ER_DUP_ENTRY","errno":1062,"sqlState":"23000","index":0} 

そして、ここでは私の証拠だ:)

enter image description here

答えて

1

あなたは非同期機能を順次実行する場合は、あなた'LLそれらをネストするか、またはそれらを一連の約束の一部として呼び出すか、async/awaitスタイルコードを使用する必要があります。あなたがここでやっていることはオフ

  1. pool.getConnection
  2. connection.beginTransaction
  3. connection.query & connection.query & connection.commitすべて同時に

を呼んでいます私の頭の上に、私はこのような何かを試してみたい:

router.get('/myfunc', async (req, res) => { 

    try { 

    const connection = await pool.getConnection(); 

    try { 

     await connection.beginTransaction(); 

     // update statement 
     const sql_update = `update course_person 
          set rescheduled_date = CURDATE() 
          where idperson = ? 
          and rescheduled_date is null`; 
     await connection.query(sql_update, [idperson]); 

     // insert statement 
     const sql_insert = `insert into course_person (idcourse, idperson) VALUES (?, ?)`; 
     await connection.query(sql_insert, [newidcourse, idperson]); 

     // commit 
     await connection.commit(); 

     req.flash('success', 'Person was updated successfully.'); 
     return res.redirect('/person/' + idperson); 

    } finally { 
     pool.releaseConnection(connection);  
    } 

    } catch (err) { 
    await connection.rollback(); 
    console.log(err); 
    } 

}); 

注:このコードはテストしていません。しかし、これは私が使用するパターンです。

このようにするには、node-mysqlの代わりにpromise-mysqlを使用する必要があります。これは、async/await構文では動作することを約束する必要があるためです。 Bluebirdを使ってnode-mysqlを宣言することもできます。また、あなたのバージョンのノードがまだ非同期/待機をサポートしていない場合は、それを削減するために、babelのようなものを使用する必要があります。 (私は私のワークフローでバベルを使用しています。)

あなたはこのような何か行うことができ、より伝統的なコーディングスタイルの非同期の代わりに呼び出すだけで巣、したい場合は、次の

pool.getConnection(function (err, connection) { 

    connection.beginTransaction(function (err) { 
    if (err) { 
     console.log(" --- error 1: " + JSON.stringify(err)); 
     throw err; 
    } 

    connection.query('update course_person set rescheduled_date = CURDATE() where idperson = ? and rescheduled_date is null', [idperson], function (err, rows, fields) { 
     if (err) { 
     connection.rollback(function() { 
      console.log(" --- error 2: " + JSON.stringify(err)); 
      throw err; 
     }); 
     } 

     connection.query('insert into course_person (idcourse, idperson) VALUES (?, ?)', [newidcourse, idperson], function (err, rows, fields) { 
     if (err) { 
      connection.rollback(function() { 
      console.log(" --- error 3: " + JSON.stringify(err)); 
      throw err; 
      }); 
     } 

     connection.commit(function (err) { 
      if (err) { 
      connection.rollback(function() { 
       console.log(" --- error 4: " + JSON.stringify(err)); 
       throw err; 
      }); 
      } 

      req.flash('success', 'Person was updated successfully.'); 
      res.redirect('/person/' + idperson); 

      connection.release(); 
     }); 
     }); 
    }); 
    }); 
}); 

注各コールがネストされているかを前の呼び出しのコールバック関数の内部これは、すべての字下げ(すなわち、「コールバック地獄」)で乱雑になり始める。約束または非同期/待機を使用するコードは、長期間に渡ってより読みやすく、維持しやすくなります。

+0

ありがとうございます、特に例のために!私はそれが何か非同期関連でなければならないと考えました。少なくとも、ノードがバージョン8で非同期/待機を正式にサポートするまで、ネストされたバージョンに固執すると思います。これにより、約束を使用して学習し、練習する時間が与えられます。 – littleK

関連する問題