2010-12-15 7 views
28

私は、JDBC APIが自動コミットモード(java.sql.Connection.setAutocommit())を提供しているのに長い間不思議に思っています。人々を困惑させる魅力的な迷惑のようだ。私の理論は、JDBCを使用してSQLを編集して実行するためのツールを作成したいベンダーの生活を簡単にするためにJDBCに追加されただけです。自動コミットをオンにする他の理由はありますか、それとも常に間違いですか?なぜAutocommitをtrueに設定するのですか?

答えて

11

残念ながら、自動コミットを使用するのは、データベース固有のものです(トランザクションの動作と同様)。私はあなたがグローバルなプログラム的なトランザクション戦略を持っていないと、誰もがトランザクションを適切にクローズ/ロールバックすることを望むよりも、おそらく自動コミットが優れていると思います。

MySQLについて言えば、デフォルトでautocommit = trueのままにしておくと、トランザクションを開始するときに自動的にオフになります。 autocommit = falseを設定する唯一の理由は、誰かがBEGINなしでトランザクションを開始しようとするとエラーを強制したい場合です。

今日の典型的なJava + MySQLアプリケーションを簡単にするために、私は多かれ少なかれ、自動コミット設定を無視し、オープンセッションインビューのパターンを使用し、それを良いものと呼んでいます。

明示的なRDBMS行ロックを強く推奨し、代わりに楽観的ロックを使用します。 Hibernateはオプティミスティックロックの組み込みサポートを提供していますが、手作業コードでも採用するのは簡単なパターンであり、より良いパフォーマンスを提供します。

+2

典型的なJa va + MySQLアプリケーション:auto-commitをtrueのままにしておきます。着信リクエストの開始時に(WebページまたはREST/JSONのいずれか)セッションを開いて(トランザクションを開始する)要求が正常に処理される場合は、要求処理の最後にトランザクションをコミットします。次に、リクエストの500ページレンダリングにロールバックを追加します。これは、基本的にPlay Frameworkが物事をどのように処理するかです。ユーザーと開発者にとって直感的です。 –

+0

これは良い答えです。「Webリクエスト」は、Webアプリケーションの「DBトランザクション」とかなり関連しているはずです。したがって、私たちはDBロックではなく楽観的に頼る必要があります。 OpenSessionInViewを使用して、リクエストの全体を通して開いているセッションを保持し、ビューのレンダリングを行い、要求の最後にフラッシュ/コミットすることができます。 –

+0

典型的なJava + MySQLアプリケーションが「数週間のプロジェクト」以上のものであれば、セッションオープンインビューを反パターンとして考えると、私の意見では良い答えではありません。アプリケーションで何が起こっているのかをすぐに失われ、パフォーマンスや同時実行の問題が発生することがあります。自動コミットは、トランザクションタイムアウトやトランザクションタイムアウトがなくても「一般リクエスト処理タイムアウト」として働きます。私は90%以上のケースでSQLトランザクションでのWebリクエストのNO関連付けを記述します –

5

コミットモードは、dbのロックの保持方法を変更します。

自動コミットモードは、トランザクションモードでのみ無効にすることをお勧めします。この方法では、複数のステートメントに対するデータベースロックを保持しないようにするため、他のユーザーと競合する可能性が高くなります。

...

トランザクションの間の衝突を回避するために、DBMSは、トランザクションによってアクセスされているデータに他の人によるアクセスをブロックするためのロック、メカニズムを使用しています。私が見ることができる(なお、それぞれの文は、トランザクションで自動コミットモードで、ロックが一つだけの文のために保持されていること。)

http://download.oracle.com/javase/tutorial/jdbc/basics/transactions.html

+0

最近では、mySQLとDB2でもマルチバージョン化されていることを考えると、このチュートリアルはやや時代遅れになりつつあります。 : – Affe

+0

スナップショットの隔離レベルは無料ではありません:http://blogs.msdn.com/b/sqlserverstorageengine/archive/2008/03/30/overhead-of-row-versioning.aspxスナップショット隔離と並行性を得る – hythlodayr

+0

ロックを取得する方法を理解することは常に関連しています。 –

18

唯一の合理的な理由がconnection.commit()を取り除くことであり、 connection.rollback()小さなアプリケーションでの単純な単一クエリトランザクションの定型文。未加工のままのJDBCは、それ自体が既に多くの定型文を必要とします。すべての行を少なくすることで、JDBCは初心者にとって怖くなくなります。

3

私が今作業しているコードベースの95%は、自動コミットが完全に合理的な単一の更新を含みます。それで、デフォルトでそれをオンにします。トランザクションに必要なコードのセクションを実行できるだけの時間だけオフにするだけで、自動コミットがすぐに開始されます。

+0

トランザクションは、トランザクションマネージャからトランザクションタイムアウトを与えることもできます。それぞれのクエリでタイムアウトを設定していますか? –

8

私はほとんど常にautocommit = trueで実行します。 99%の時間、私の更新はアトミックです。確かに、デビットを書いて、ロールバックしたいクレジットを書き込もうとしても失敗する場合があります。しかし、私の経験では、これらは比較的まれです。通常、私が書いた各レコードは、それ自身の上に立っています。その場合、各書き込みの後にコミットすることを気にする必要はありません。それはここにコードの行を保存します。プログラムの構造上、try/catchブロックを追加する必要がないこと、あるいは関数間で接続オブジェクトを渡す必要がないことを意味します。誰かがコミットするのを忘れてしまった迷惑なバグを助長します。

「誰かを迷惑にさせる」という唯一の方法は、自動コミットをオフにしてコミットまたはロールバックを行うことが大変なので、個別のトランザクション内にある更新を行うことです。トランザクションを中止すべきことが何も起こらない限り、すべてうまく動作するはずです。テストシナリオが不十分な場合、私はこれが生産に入ると想像することができます。

しかし、言語のほとんどの機能についても同じことが言えます。同様に、時間の90%が長時間に収まるような数値を処理するプログラムを作成したとしますが、今はすべてが大きくなる可能性があります。このような状況に直面したら、BigIntegerを使用するか、より大きい数値を処理するために新しいクラスを作成します。怠惰なプログラマーは、通常は動作し、他の選択肢はあまりにも多くの問題があるため、長い間使って誘惑されるかもしれません。したがって、Javaがlong(またはint)を含むべきではないと結論付けるのは、誰かが適切でないときにそれらを使うことに誘惑されるかもしれないからですか?

プログラムでトランザクションのコンテキスト内で大部分の更新を行う必要がある場合は、自動コミットをオフにします。その存在があなたを傷つけることはありません。それは便利なときにはそこにありますが、そうでないときはオフにすることができます。

+1

JDBC 3仕様のため、「自動コミット」モードの接続では、複数のStatementを開くことはできません。したがって、ネストされたUPDATEまたはSELECTの外部ループ内のSELECTによって問題が発生します。 –

+0

アトミック性だけでなく、トランザクションマネージャがサポートしている場合、トランザクションにタイムアウトを割り当てることもできます。自動コミット&no query timeoutを使用すると、検出されないSQLパフォーマンスの問題や重い問い合わせなどが発生する可能性があります。 –

+0

私はJavalandを数年前から使い続けていましたので、新しいバージョンのJavaが異なるかもしれません。しかし、私は、自動コミットを使ってクエリを実行するときにSQLタイムアウトが発生していることは間違いありません。私は、開発環境で見つかったが、時間がかかるようなクエリの思い出がたくさんあります。多分、デフォルトは違うかもしれません。いずれにしても、パフォーマンスの問題があることをタイムアウトに依頼することは、非常に鈍いツールです。 – Jay

6

自動コミットが便利です。 JDBC 3の仕様が変更されても、それほど有用性は低くなりました。

「自動コミット」モードのJDBC 3接続では、複数のStatementを開くことができないため、別のステートメントを実行すると、ResultSetを含む最初のステートメントを閉じます。

したがって、SELECT内でのループ処理とUPDATE(またはネストされたSELECT)の発行は失敗する傾向があります。明らかにそれは犯罪で、実際には何かを行うにはあなたの外側のSELECTの結果!


はとにかく、特定のドライバ&バージョンに依存します..しかし、一般的にはJDBC 3仕様では、この役に立たない行動を強制するように見えます。ドライバをアップグレードすることで、この動作を「役に立たなく」発見することもできます。

なぜ自動コミットを使用しますか?もともと、便利でした&便利でした。他の回答が言うように、JDBCは... JDBCは本当にうまく設計されたAPI :(


これらの日は、あなたがより良いだろうにHibernateやSpringのJdbcTemplateを使用していない、正しく呼び出すためにGUFFや取り扱いの大量を必要とします。あなたがサーブレット/ Webアプリケーションを実行している場合は、 "User Request"の境界でトランザクション管理(begin/end)またはHibernateセッション(thread-localにバインド)を配置してください。

たとえばget

javax.servlet.Filterなどを使用してバインドできます。

:スレッドローカルに、それを得るために、静的なヘルパーを作るかそれを必要とする、など

+0

ウェブリクエストANTIパターンに接続/トランザクション/セッションをバインドしてください。リクエスト処理、マルチパートアップロード処理、遅い接続でクライアントにボディを送信することができますが、ほとんどの場合、非常に悪いアイデアと言えます。 –

+0

ありがとう@PiotrMüller - 推論または参照?ほとんどのパターンで0.001%の悪いケースが浮かび上がると思いますが、「問題のあるコーナーケースが可能です」と「ほぼすべてのケース」を区別する方が良いでしょう。 (2012)、私はそれが良いアドバイスだと思う。ユーザーリクエストの境界は、HTTPサービスアプリケーションで最も基本的かつ重要な境界です。そのため、それは堅牢で明解な設計の候補です。他の解決方法はもっと複雑になるでしょう。 –

+0

ウェブアプリケーションでは、上記の「悪いケース」のほとんどが(一般的なウェブアプリの場合)適用されます。セッションでセッションを有効にすると、多くの技術的側面が即座に解決されるようにする必要があります。レスポンスバッファリング:トランザクションとSQL接続がクライアント接続の全期間にわたってスパンではないことを確認します(なぜクライアントが低帯域幅であれば長い間SQL接続を保持します)。成長する。短期間であれば小規模なプロジェクトでは解決策になるかもしれませんが、大きなものはお勧めしません –

2

まあ、グローバルレベルで「自動コミット」を可能にしながら慎重な表情を必要とする一定の条件がありますa。)クエリーレベルでのトランザクション管理は、成功または失敗のいずれかのクエリを必要とする場合はインスタンスに対して、BEGINおよびコミットトランザクションの下でラップする必要がある場合、ユーザーに委ねられます。

b。)「自動コミット」を有効にすると、ロールバックが発生しません。

c。)トランザクションごとに書き込み(コミット)するオーバーヘッドもあります。

d。)読み取り専用クエリの場合、「自動コミット」は明示的に必要ありませんが、「自動コミット」を有効にすると、すべてのクエリに対して自動的に適用されます。

自動コミットを有効にするためにテーブルロックが唯一の懸念事項である場合、それは良い考えではなく、より低いロックタイムアウトに頼る可能性があります。

関連する問題