4

テーブルに挿入したいデータのセット全体があります。すべてを挿入/更新するか、ロールバックしようとしています。私はトランザクションでそれを行うつもりでしたが、sql_exec()コマンドが同じことをしたかどうかはわかりませんでした。

私の目標は、リストを反復処理することでした。主キーに基づいて各反復から選択します。

If result was found:
  append update to string;
else
  append insert to string;

次に、ループを繰り返した後、巨大な文字列があり、次のように言います。

sql_exec(文字列); sql_close(デシベル);

それは私がそれを行うべきですか?ループの反復ごとに実行するつもりでしたが、エラーが発生した場合にグローバル ロールバックを行うとは考えていませんでした。

4

1 に答える 1

6

いいえ、すべてを巨大な文字列に追加するべきではありません。その場合、実行中に大量のメモリを割り当てる必要があり、文字列全体に対して単一のエラーが発生するだけなので、個々のステートメントごとに適切なエラー メッセージを作成するのが難しくなります。SQLite が再び個々のステートメントに解析し直さなければならないのに、なぜ 1 つの大きな文字列を構築するためにそのすべての労力を費やすのでしょうか?

代わりに、@Chad が示唆するように、トランザクションを開始するステートメントで使用する必要がありsqlite3_exec()ますBEGIN。次にsqlite3_exec()、各ステートメントを順番に実行し、最後にすべての進行状況に応じて or を実行しsqlite3_exec()ますCOMMITROLLBACKステートメントはトランザクションを開始し、その後に実行されるすべてのBEGINステートメントはそのトランザクション内にあるため、一緒にコミットまたはロールバックされます。それがACIDの「A」の略です。トランザクション内のすべてのステートメントが、単一のアトミック操作であるかのようにコミットまたはロールバックされるため、アトミック。

sqlite3_exec()さらに、ファイルから読み取られるなど、一部のデータが各ステートメント内で異なる場合は、おそらく使用しないでください。そうした場合、ミスによって簡単にSQL インジェクションのバグが残る可能性があります。たとえば、文字列を追加してクエリを作成char *str = "it's a string"し、挿入したい文字列がある場合、それを適切に引用しないと、ステートメントが のようINSERT INTO table VALUES ('it's a string');になり、エラーになります。または、悪意のある人物がこのファイルにデータを書き込むことができた場合、必要な SQL ステートメントを実行させる可能性があります (文字列が"'); DROP TABLE my_important_table; --". 悪意のある人は誰も入力を提供しないと思うかもしれませんが、誰かが SQL パーサーを混乱させる文字を文字列に挿入すると、偶発的な問題が発生する可能性があります。

代わりに and を使用する必要がsqlite3_prepare_v2()ありますsqlite3_bind_...()(はorまたは...のような型です)。これを行うには、 のようなステートメントを使用します。ここで、パラメーターを配置する場所をa に置き換え、を使用して準備し、 を使用してパラメーターをバインドし、 を使用してステートメントを実行します。ステートメントが何らかのデータを返す場合、 を取得し、さまざまな関数を使用してデータにアクセスできます。ドキュメントを注意深く読んでください。私が示したパラメータの例のいくつかは、これをどのように使用するかに応じて変更する必要があるかもしれません.intdoubletextchar *query = "INSERT INTO table VALUES (?)"?sqlite3_prepare_v2(db, query, -1, &stmt, NULL)sqlite3_bind_text(stmt, 1, str, -1, SQLITE_STATIC)sqlite3_step(stmt)SQLITE_ROWsqlite3_columne_...()

はい、これは を呼び出すよりも少し手間sqlite3_exec()がかかりますが、クエリに外部ソース (ファイル、ユーザー入力) からロードされたデータがある場合、これが正しく行う唯一の方法です。and orステートメントsqlite3_exec()など、クエリのテキスト全体がソース内に含まれている場合、またはプログラムの外部からの部分がない事前に作成されたクエリが含まれている場合は、呼び出しても問題ありません。予期しない文字列が入る可能性があります。BEGINCOMMITROLLBACK

最後に、何かが既にデータベースにあるかどうかを照会してから、挿入または更新する必要はありません。レコードを挿入するか、レコードを一致する主キーに置き換えるクエリを実行できINSERT OR REPLACEます。これは、選択してからINSERTまたはを実行するのと同じですUPDATEが、はるかに迅速かつ簡単です。詳細については、INSERTおよび「on conflict」ドキュメントを参照してください。

于 2012-11-08T05:17:27.133 に答える