2012-01-18 8 views
8

私は、コミットとロールバックの違いと、これらの操作が何をすべきかを知っています。 しかし、私はcommit()、rollback()を使うときや、何もしないときに同じ振る舞いをすることができる場合に何をすべきかはわかりません。Java:セマンティクスが変更されていない場合、vs rollbackと何も関係ない?

たとえば、dbに書き込まずにクエリを実行するコードがあるとします。 SQLiteデータベースと通信するアプリケーションで作業しています。

try { 
    if (deleteById(2)) 
    // a) delete successful (1 row deleted) 
    else 
    // b) delete unsuccessful (0 row deleted, no errors) 
} catch (SQLException e) { 
    // c) delete failed (because of an error (possibly due to constraint violation in DB)) 
} 

がコミットまたは場合によってはロールバックやって、意味的な観点からそれを守っb)及びc)の結果:

try { 
    doSomeQuery() 
    // b) success 
} catch (SQLException e) { 
    // a) failed (because of exception) 
} 

あるいはさらに興味深いは、単一の行を削除し、次のコードを、考えます同じ行動。

は一般的に、いくつかの選択肢は、各ケース内に行うことがある(A、B、C):

  • ロールバック
  • をコミット何

しない任意のガイドラインはありますか特定の操作を選択するとパフォーマンスが向上しますか?正しい方法は何ですか?

注:自動コミットが無効であるとします。

+1

データベースが開いているトランザクションがある場合、おそらくコミットするより速くなります。

この例では、私は、ベストプラクティス(miantainabilityワイズ)であると考えているかを示しています。ロールバックの場合、DBはトランザクションログをチェックし、変更を元に戻す必要があります。これが「変更なし」であっても、引き続きチェックが行われます。 – JNK

+0

ロールバックは、同じトランザクションで実行された他の更新も元に戻します。あなたが持っているところは違いがありませんが(JNKの説明は例外ですが)、後で別のものを追加してそれを処理することを忘れると、噛む可能性があります。に入る良い習慣。 –

+1

@ JNK、これはRDBMにわずかに依存しています - INSTEAD OFトリガーとの潜在的な競合もありますが、それはやや複雑です。 – Andrew

答えて

2

単なる選択であれば、私は取引を開こうとはせず、したがっていかなる場合も何もしません。既にパラメータを渡しているので、おそらくあなたはすでに更新/挿入があることを知っています。 操作を行うつもりが面白いです。削除する場合は、コミットしたいことが明らかです。例外がある場合は、何かが失敗したためにDBを一貫性を保つためにロールバックする必要があります。私は3つの理由のためにコミットしたい削除するためには何もありませんでしたので、削除が失敗した場合:意味的に

  • が、操作が 技術的に成功したと指定されたとおりに実行するので、より正確なようです。

  • 誰かが 取引に多くのコードを追加する場合、それはロールバックされると 1だけで何もしませんでした(彼らはその例外 に期待削除ので、彼らは驚かないだろうので、それはより多くの将来の証拠でありますトランザクションがロールバックされます)

  • 実行する操作がある場合、コミットは高速ですが、この場合はI は重要ではないと考えます。

+0

+1ですが、(1)「選択しただけの場合、トランザクションを開けません」というのはDBMSに依存します。 (2)例外を除いてケースをロールバックすべきだと私は同意しますが、OPはロールバックを指定してこのケースについて具体的に質問しているので、コミットは意味的に同等です。 – ruakh

+0

@ruakh(1)私は完全に同意します。 (2)コメントを編集するための回答を編集しました – Luis

+0

JDBCは常にトランザクションを開始します(自動コミットまたは手動でコミット/ロールバックする必要があります)。トランザクションを開始しないオプションはありません。データベースの中には、その接続に対してより安価なトランザクション処理を意味する「読み取り専用」接続オプションがあります。 –

1

重要なアプリケーションには、複数のSQL文が必要です。最初のSQL文の後で最後のSQL文の前にエラーが発生すると、データに矛盾が生じます。

トランザクションは、複数のステートメント操作を、現在作業している単一ステートメント操作ほどアトミックにするように設計されています。

1

あなたが言っていることは、コードが呼び出されているかどうか、テストするためのフラグを返すか、何か問題が生じた場合に例外をスローするかどうかです。

このような状況は、多くのことを発生し、あなたがあなたの中で指摘したように、それは、それが困難な呼び出し元のコードは、両方の条件を処理できるようになり:|

APIは例外をスローしますが、またブール(偽true)を返します。 OP。あなたはこのような状況で行うことができます一つのことは、次のとおりです。

問題ありません:

// Initialize a var we can test against later 
// Lol, didn't realize this was for java, please excuse the var 
// initialization, as it's demonstrative only 
$queryStatus = false; 

try { 
    if (deleteById(2)) { 
     $queryStatus = true; 
    } else { 
     // I can do a few things here 
     // Skip it, because the $queryStatus was initialized as false, so 
     // nothing changes 
     // Or throw an exception to be caught 
     throw new SQLException('Delete failed'); 
    }   
} catch (SQLException $e) { 
    // This can also be skipped, because the $queryStatus was initialized as 
    // false, however you may want to do some logging 
    error_log($e->getMessage());  
} 

// Because we have a converged variable which covers both cases where the API 
// may return a bool, or throw an exception we can test the value and determine 
// whether rollback or commit 
if (true === $queryStatus) { 
    commit(); 
} else { 
    rollback(); 
} 

APIは、排他的な例外(戻り値なし)をスローします。例外がキャッチされなかった場合、操作はエラーなく完了し、try/catchブロック内にrollback()/ commit()を追加できると想定できます。

try { 
    deleteById(2); 

    // Because the API dev had a good grasp of error handling by using 
    // exceptions, we can also do some other calls 
    updateById(7); 

    insertByName('Chargers rule'); 

    // No exception thrown from above API calls? sweet, lets commit 
    commit(); 

} catch (SQLException $e) { 

    // Oops exception was thrown from API, lets roll back 
    rollback(); 
} 

APIはブール値を返し、例外をスローしません(真|偽):

これは、あなたが持っている場合は

if (deleteById(2)) { 
    commit(); 
} else { 
    rollback(); 
} 

をチェック/バック古い学校のエラー処理へ行きますトランザクションを構成する複数のクエリを使用すると、シナリオ#1から単一のvarのアイデアを借りることができます。

$queryStatus = true; 

if (!deleteById(2)) { 
    $queryStatus = false; 
} 

if (!updateById(7)) { 
    $queryStatus = false; 
} 

... 

if (true === $queryStatus) { 
    commit(); 
} else { 
    rollback(); 
} 

"注:自動コミットが無効であると仮定します。

  • あなたは自動コミット無効にしたら、あなたは再度有効になり、自動コミットするまで、あなたが今からコミットの制御を取っているRDBMSを言っているので、IMO、それはどちらかロールバックすることをお勧めしますまたは対トランザクションをコミット任意のクエリをlimboに残します。
1

私はまったく同じ質問をしました。最後に、私は常に成功したトランザクションをコミットし、いつも成功していないトランザクションをロールバックするソリューションに行きました。アサルトの効果があります。これによりコードが単純化され、より明確になり、読みやすくなりました。

私はNHibernate + SQLite onで使用したアプリケーションで大きなパフォーマンス上の問題はありませんでした。あなたの人数は変わるかもしれません。

1

他の人が回答に述べたように、これはパフォーマンスの問題ではありませんが、それは無視できると思いますが、保守性の問題です。

あなたのコードがきれいに保守されるために、私はいつもあなたのtryブロックの最下部にコミットするために、常にあなたのfinallyブロックであなたのConnectionを閉じるように(どんな)をお勧めしません。 finallyブロックでは、コミットされていないトランザクションがある場合(つまり、tryブロックの最後にコミットに達していないことを意味します)、ロールバックする必要があります。

public boolean example() 
{ 
    Connection conn; 
    ... 
    try 
    { 
     ... 
     //Do your SQL magic (that can throw exceptions) 
     ... 
     conn.commit(); 
     return true; 
    } 
    catch(...) 
    { 
     ... 
     return false; 
    } 
    finally 
    {//Close statements, connections, etc 
     ... 
     closeConn(conn); 
    } 
} 

public static void closeConn(Connection conn) 
{ 
    if (conn != null) 
     if (!conn.isClosed()) 
     { 
      if (!conn.getAutoCommit()) 
       conn.rollback();//If we need to close() but there are uncommitted transacitons (meaning there have been problems) 
      conn.close(); 
      conn = null; 
     } 
} 
+0

ニース。私は途中でエラーメッセージなどの有用なエラー情報を失わないように、例外をバブルさせることもできますが、falseを返すだけではありません。 – vidstige

関連する問題