質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
SQLite

SQLiteはリレーショナルデータベース管理システムの1つで、サーバーではなくライブラリとして使用されている。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Xamarin

Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

Q&A

解決済

1回答

616閲覧

[Xamarin.Android]SqLite DBファイル削除直後にDBを操作したい

PeerGynt

総合スコア8

SQLite

SQLiteはリレーショナルデータベース管理システムの1つで、サーバーではなくライブラリとして使用されている。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Xamarin

Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

0グッド

0クリップ

投稿2023/03/04 15:49

度々お世話になります。Androidアプリ開発の初心者です。
Microsoft Learn等のサイトを参考に、見様見真似で販売管理ツールを組んでいます。

■やりたいこと

SQL Serverから、Androidスマート端末内SqLite DBに、データをインポートします。

その前に、端末内DBファイルを削除したいのです。
それから、

・Drop Table if exists
・Create Table if not exists
・Insert Into
・……

という具合にデータのインポート処理しています。

■問題点

前述のインポート処理前に、Java.IO.Fileにて File.Delete() を実行。SqLite DBファイルを削除。
ここで一旦アプリを終了し、再起動すると、前述のインポート処理は上手くいきます(色々試してみて判明。つまり単純なソース記述ミスではない)

ところがSqLite DBファイルを削除した後、(アプリを終了させず)続けてインポート処理を行おうとすると、「Disk I/O Error」が発生し処理が通りません。

色々試してみたのですが、「Attempt to write for read only database~」(ちょっとうろ覚え)というエラーが発生。或いは「Database is locked」の時もありました。要するにDBに書き込めないためエラーが発生しているようです。

■開発環境等

Xamarin.Androidプロジェクト
最小Android 9.0(API28) ~ ターゲットAndroid 11.0(API30)
Win11 Pro + Visual Studio 2019(開発環境)
Android9タブレット端末 / Android11スマート端末(デバッグ用端末)
DBはそれぞれにプリインストールされているSqLite
using Microsoft.Data.Sqlite

■試してみたこと

DBファイル削除に時間がかかっているのかも、とDelayを最大1分実行し、それからインポート処理続行。NGでした。

先に明示的にSqLite Connectionをクローズしてから削除するも、NG。

Activityを再起動してからインポート処理実行。→NG。

SqLite ConnectionをオープンしてからDelayを措いてみた。→NG。

Journalモード/WALモードの指定。→NG。
(再起動後ならモード変更を受け付けてくれるが、DBファイル削除直後だとNG)

■削除処理ソース

C#

1public void RemoveDbFile() 2 { 3 Java.IO.File _file = new File(Definitions.DbPath); 4 _file.Delete(); 5 6 // 念のため関連ファイルも削除 7 _file = new File(Definitions.DbPath + "-journal"); 8 _file.Delete(); 9 10 _file = new File(Definitions.DbPath + "-shm"); 11 _file.Delete(); 12 13 _file = new File(Definitions.DbPath + "-wal"); 14 _file.Delete(); 15 }

■教えて頂きたいこと

なぜ、DBファイル削除後に一旦アプリを終了させればOKなのか。
なぜ、DBファイル削除に続けて処理実行すると、(ソースコードは同一なのに)DBに書き込めないのか。
まずはそこが謎です。何が原因なのでしょうか。

SqLiteのDB削除は、DBファイルを削除すればよいだけだ、という記述をWeb上にてよく見かけます。
ですが、実際はそれだけではダメなのでしょうか。
Androidの仕組み上、何らかのコツがあるのでしょうか。

SqLiteのDBファイルは、フルパスの名称さえ指定してコネクションをオープンすれば、ファイルが存在しなくても勝手に作成される、とMicrosoft Learnに記述があります。
ですが、実際はそれだけではダメなのでしょうか。
Androidの仕組み上、何らかのコツがあるのでしょうか。

或いは削除前にトランザクションを破棄しておくだとか、DBファイルが作成された直後に何らかのDB設定コマンドを送信しておくべきなのでしょうか。要するに削除前なり削除後なりに、何か処理が必要なのでしょうか。

以上、何でも結構ですので、対処の取っ掛かりとなるようなナレッジがあればご教示頂きたいと思います。
Android Studioでの開発における、類似の問題の対処法でも構いません。

よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

PeerGynt

2023/03/05 09:46 編集

>hoshi-takanoriさん 情報、どうもありがとうございます。 藁にもすがる思いで早速試してみたのですが……うまくいかないです。 というか、色々やってみたのですが実装方法が判りません。折角教えて頂いたのに、残念。 mono.android とあるので、Xamarin.androidプロジェクトだと使えないのかも。 そのへんも含め、よくわかりません。 もしご存知の方がおられましたら、教えて下さい。 なお、DBはご指摘のように、セッション切断後にファイル削除。そして開き直しています。 が、関連クラスの破棄だけで本当にセッションが切断されているのか(C#的にはそれで良いはずなのですが)、諸エラーメッセージから想像するに、どうも怪しいです。 DB側がセッション切断を把握しておらず、次回勝手にRead Onlyでセッションを開いているような……。
jimbe

2023/03/05 10:20

DROP TABLE するなら DB ファイルを消さなくても良いような気もするのですが、何故 DB ファイルを消す必要があるのでしょうか。
PeerGynt

2023/03/05 10:53

>jimbeさん いつもお世話になっております。 まだ設計が固まっていないんですが……。 まず特別なメンテ用に、DBファイル自体を削除する機能を設けています。これが、DBファイル削除&アプリ終了、そして手動でのアプリ再起動です。 こちらは上手くいっています。 で、通常時はDBファイルを削除せずDBインポート処理を実行するのですが、どうも動作が不安定なのです。 こちらの場合、なぜか途中で「Database is locked」だの「Read Onlyなのに書き込みを企ててる」だのと妙なエラーが出まくっていまして……(同一コードなのに) そもそもSqLiteで十数万件のレコード追加は大丈夫なのか、などといった点も不安なのですが、その辺の情報も見つけきれていないので暗中模索状態なのです。 なので毎回DBファイル削除した方がラクだなあ……などと考えつつ、今日は朝からエラー原因を丁寧に紐解いている状況です。 というわけで、インポート及びその後の動作が安定すれば、DBファイルを削除する必要はありません。 ですがインポートは日次処理でして……。 もし、大量のデータを回すこと自体が問題だとすれば、毎回DBファイルを削除した方がいいかな、などと悩んでいます。
jimbe

2023/03/05 11:11

>通常時はDBファイルを削除せずDBインポート処理を実行するのですが、どうも動作が不安定 こちらをまず掘り下げたほうが良いように思いますが。 データが多過ぎるかどうかは、インポート(insert)が成功するかどうか、ファイルサイズがどれほどになっているか、端末の動作に異常は見られないか等を調べることで判断するしかないでしょうね。
PeerGynt

2023/03/05 14:43

>Jimbeさん そうですね。おっしゃる通りだと思います。 インポート処理に一度成功し、メインメニューのActivityに戻る(DB処理クラスを破棄) 再びインポート処理Activityに移動し、再度インポート処理を行うと、 ・Drop table →OK ・Create table →OK ・Insert into(2万件強) →NG エラーは「Database is locked」 前者と後者で処理分岐なし。 同一のDB処理クラスで、Drop/Create/Insert into はプロシージャこそ異なるもののロジックは同一。 SqLiteTransactionオブジェクトはプロシージャ内ローカル。抜ける際にDispose。 謎です。 Drop/Create は通っているので、DBにロックがかかるのはその後ですよね。
jimbe

2023/03/05 15:47 編集

Database のロックというと複数のトランザクションがぶつかっているような印象ですが、 insert はどのようなタイミングで動いているのでしょうか。例えばトランザクションをセットしないで、デフォルトの insert 毎にコミットされる状態では、ロックエラーは発生するのでしょうか。(成功しても遅くて使えないかもしれませんが。) xamarin アプリでローカルでも sqlite の書き込みプロセスで保持してるものが何かあるとか、逆に xamarin アプリでは有効と思っているのが sqlite 上ではそうでは無いとか、深めなことも調べることになるのかもしれませんね。
guest

回答1

0

自己解決

DBファイルを削除しない方法で、一応解決したようですので報告致します。

■判明したこと

Drop table/Create table 実行後、レコードを数万件単位で追加。
敢えてトランザクションをかけずに実行したところ、DBファイル削除直後は成功するが、2度目以降はエラー発生。→NG
原因は、DB接続セッションが途中で切れていた。

直前のSQL文に問題はなく、切れるタイミングもバラバラ。つまり負荷が大き過ぎて、SqLite側が耐えられないと想像。
なので Insert into 実行時、毎回DB接続セッションの状態を確認し、Closed状態ならば再Openしてやる。→OK

但しやはり、トランザクションをかけずに処理すること自体、負荷が大きいらしく、2度目以降はエラー発生。

■解決策

  • トランザクションをかける。
  • 数万件のレコードを一度に追加しコミットしていたが(時間不足のため手抜き)、レコード20件毎にコミットするよう処理変更。
  • プログレスバー表示のため非同期処理にしていたが、同期処理に変更。
  • 1テーブル分処理し終わる毎に、ディレイ/DBセッション切断。

要するにSqLiteへ大きな負荷をかけてはいけない、と判明し、ソース上で負荷を減らすチューニングを実施しました。

SqLiteのSQL文はGBレベルの長さに耐えられる、という仕様をどこかで見かけたので、数万件のレコードを一度に追加しコミットしていたわけですが、実際に意識すべきは同時に処理するレコード数のようです。
レコード数が多ければトランザクション処理に負荷がかかる。一気にトランザクトするのではなく、逐次実行させないと、後続処理に影響する……ということではないかと想像します。

以上、一応解決です。
アプリ側の処理速度が早いため、SqLiteに次々と処理要求を出すとSqLite側が耐えられないのでしょう。そこを考慮し、アプリ側でSqLite負荷軽減の工夫が必要と理解しました。

いろいろとアドバイスを下さった方々、どうもありがとうございます。今回も色々と勉強になりました。

投稿2023/03/06 12:02

PeerGynt

総合スコア8

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問