2

SQL(Androidで使用)に関するバグを修正しようとしています。ステートメントは基本的に次のようになります。

INSERT INTO log (time, message) VALUES (datetime('now'),<a_message>);

「datetime(now)」はデータベースの鍵のようですが、問題は1ミリ秒以内に2回呼び出せることです。その場合、キーが一意ではないため、SQLでエラーがスローされます。

REPLACEを使用できますが、1つ(または複数)のエントリが上書きされます。エラーコードを確認し、しばらくスリープしてから再試行することもできます。誰かがこの問題のより良い解決策を持っているかどうか疑問に思っていますか?私はSQLの経験があまりありません。

ありがとう。

4

2 に答える 2

4

タイムゾーン、閏秒、その他多くの驚くべき事柄のワイルドで毛むくじゃらの世界のため、いずれにせよ、datetime を主キーとして使用することをはるかに躊躇する必要があります。a1 = datetime('now')が常に次の呼び出し以下であるという保証はまったくありません。a2 = datetime('now')

この記事を読んでください。彼が日付、時刻、タイムゾーンについて話し始めたところから約 3 分の 1 を読んでください。これにより、この質問で求めていることを実行しようとするべきではないことがわかります。

https://msmvps.com/blogs/jon_skeet/archive/2009/11/02/omg-ponies-aka-humanity-epic-fail.aspx

手早く汚いハックの回避策が必要な場合は、挿入を while ループに入れて、挿入が失敗したときにエラーをキャッチし、1 ミリ秒後に再試行します。これは悪いことであり、寝室に大きな混乱を残すようなものですが、賢明な主キーを持つようにテーブルを再設計するには時間がかかりすぎるため、必要になる場合があります。

ただし、これを行う場合、コードがその while ループに座って、数十ミリ秒の間辛抱強く待って、最終的に開いているスロットを見つけたときに、期待どおりに動作しないように準備してください。将来発生した別のエントリの前 (実際には過去)。そう考えると頭が痛くなる。

于 2012-10-15T13:23:52.387 に答える
2

単純。時間値を主キーとして使用しません。代わりに、自動的にインクリメントされる 1 つの余分な列 (代理キー) を持つテーブルを作成します。

CREATE TABLE log (
  id         INTEGER PRIMARY KEY AUTOINCREMENT,
  time       REAL,
  message    TEXT
)

その後、既存の INSERT は正常に機能するはずです。

時間フィールドに基づいてレコードの取得を最適化する必要がある場合でも、それを行うことができます。そのフィールドのインデックスを追加するだけです。そのフィールドで結合を使用する場合、特定の時間を持つことは、単一の特定のレコードと同じではないことに注意してください。

于 2012-10-15T13:24:12.527 に答える