Android第十九課 attempt to write a readonly database解決

場景
         Jni下編譯SQLite源碼作爲數據庫,在測試手機:型號(Redmi Note 2) Android版本(5.0.2 LRX22G)系統下使用,嘗試寫數據庫的時候,返回錯誤信息:attempt to write a readonly database


解決
在sqlite.c文件中查找
ino_t ino; /* Inode number */
修改爲
unsigned long long ino; /* Inode number */


錯誤說明
Store inodes in unsigned long long In 32 bit ABIs, ino_t is a 32 bit type, while the st_ino field in struct stat is 64 bits wide in both 32 and 64 bit processes. This means that struct stat can expose inode numbers that are truncated when stored in an ino_t. The SDCard fuse daemon (/system/bin/sdcard) uses raw pointer values as inode numbers, so on 64 bit devices, we're very likely to observe inodes that need > 32 bits to represent. The fileHasMoved function in sqlite compares the stored inode value with a new one from stat, and when the stored value is truncated, this check will falsely indicate that the file has been moved. When the fileHasMoved function triggers, other functions start returning errors indicating that the database is in read-only mode. NOTE: Bionic differs from glibc in that struct stat's st_ino is *always* 64 bits wide, and not the same width as ino_t.


參考
http://www.jianshu.com/p/30139ef31230

解決過程:
1 懷疑是讀寫權限的問題,但是其他文件也有讀寫,明顯不成立,並且已經提供了讀寫的權限:
<uses-permission android:name="android.permission.INTERNET" />

2 懷疑是使用MTP模式共享機身存儲到電腦,導致兩邊同時編輯,通過關閉MTP媒體共享,不成立
Redmi Note 2手機請勿關閉MTP媒體設備,否則需要恢復出廠設置才能夠重新共享到電腦。

3 拷貝test.db和test.db-journal文件到Windows系統,並且使用SQLite控制檯進行修改,沒有任何的
問題。當前使用的是相同的SQLite源碼編譯的控制檯程序。進行數據的插入過程中,會自動刪除journal歸檔文件,並沒有提示只讀。另外單獨拷貝test.db,直接操作,也沒有任何的問題。

4 嘗試關閉Java層對數據庫的讀寫訪問,只是允許NDK層直接操作數據庫,防止多線程訪問數據庫,還是出現同樣的結果,當然不知道是否是sqlite3_open與sqlite3_open_v2的接口是否會產生不同的結果,目前採用第一種方法訪問數據庫。

5 嘗試獲取Android系統中SQLite的版本,調用getVersion返回1,沒有實質上的幫助。

6 是否是其他的Java層獲取數據庫的連接,沒有關閉導致問題的出現?SQliteOpenHelper內部只緩存一個數據庫的連接,在多線程的使用過程中,不要頻繁的調用close,而應該保存一個唯一的一個訪問實例,但是對於多進程之間的訪問,也帶來問題http://blog.sina.com.cn/s/blog_5de73d0b0102w0g0.html


7 雖然NDK無法修改數據,但是可以讀取數據,而Java層卻可以輕鬆的完成數據庫的修改操作。

8 嘗試調用beginTransaction和endTransaction對數據庫的操作進行事務加鎖還是沒有任何的效果

9 懷疑是Android目錄的讀取問題,NDK層的SQLite讀取數據庫文件,發現有問題,但是沒有辦法找到journal歸檔文件,因此認爲是隻讀,也是合理的
總結
    經過上述種種的研究分析,得到如下的猜測:NDK層的SQLite實例在系統開機啓動之後,會檢查是否存在journal檔案。如果是通過程序自動刪除該journal檔案。但是如果程序無法自動刪除,目前懷疑就是因爲版本之間的不對稱,導致無法刪除journal,SQLite數據庫因此數據庫變成只讀的狀態。

折中方案
    NDK層只是負責只讀數據,如果有任何的修改,都需要調用Java的接口進行修改數據,雖然有SQLite的源碼,但是NDK層不好調試。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章