最近開發(fā)app的時(shí)候由于會(huì)用到數(shù)據(jù)庫所以采用了開源庫GreenDao晌涕,于是開啟了采坑之旅
1巍耗、greendao升級(jí)數(shù)據(jù)庫的時(shí)候居然會(huì)刪除原有的數(shù)據(jù),這不是坑嗎?于是在網(wǎng)上尋求各種方案
推薦使用升級(jí)輔助庫 GreenDaoUpgradeHelper(可參見https://github.com/yuweiguocn/GreenDaoUpgradeHelper/blob/master/README_CH.md)。該庫通過 MigrationHelper在刪表重建的過程中渐排,使用臨時(shí)表保存數(shù)據(jù)并還原炬太。輔助博客請(qǐng)參考:https://blog.csdn.net/wjk343977868/article/details/53943135以及https://github.com/WJKCharlie/GreenDaoExample.做了一下版本升級(jí)測(cè)試,修改一下數(shù)據(jù)庫版本號(hào)。發(fā)現(xiàn)數(shù)據(jù)被完整保存下來了驯耻。于是乎,進(jìn)行第二次測(cè)試,測(cè)試一下增加字段或者刪除字段,看看效果如何亲族。
2、基本類型(如:int)默認(rèn)會(huì)添加非空約束
于是,第二坑來了,刪除字段之后,數(shù)據(jù)可以完整保存可缚,然后隨機(jī)增加了一個(gè)int的字段test之后,發(fā)現(xiàn)數(shù)據(jù)庫升級(jí)失敗,定位到log,發(fā)現(xiàn)拋出這樣一個(gè)異常
Android:android.database.sqlite.SQLiteConstraintException:UNIQUE constraint failed
查找相關(guān)資料之后,發(fā)現(xiàn)可能是以下兩種原因:?
可能發(fā)生這種BUG的兩種情況?
1:定義的字段為NOT NULL,而插入時(shí)對(duì)應(yīng)的字段為NULL?
2:你定義的自動(dòng)為PRIMARY,而插入時(shí)想插入的值已經(jīng)在表中存在霎迫。?
首先排除第二種情況,那么只能是第一種情況了。新增的test不能非空導(dǎo)致數(shù)據(jù)庫遷移的時(shí)候失敗帘靡。首先懷疑是MigrationHelper的sql語句由問題,定位到將臨時(shí)表數(shù)據(jù)轉(zhuǎn)移到新表的那行sql語句(insert into table (?,?,?) select (?,?,?) from tempTable),發(fā)現(xiàn)sql語句沒有問題知给。?
于是我去查找看看greendao有沒有數(shù)據(jù)非空的注解,發(fā)現(xiàn)并沒有。
查看greendao的相關(guān)issus,發(fā)現(xiàn)以下兩個(gè)有用信息?
https://github.com/yuweiguocn/GreenDaoUpgradeHelper/issues/23?
https://github.com/greenrobot/greenDAO/issues/17
結(jié)論在于:由于greenDAO 3.0 生成的字段添加了非空約束。字段的類型設(shè)置為基本類型(如:int)默認(rèn)會(huì)添加非空約束,字段類型設(shè)置為對(duì)象類型(如:Integer)默認(rèn)不會(huì)添加非空約束,而且最終生成的sql會(huì)使用對(duì)象類型涩赢。
從源碼角度看,我們可以查看生成的VersionDao類,發(fā)現(xiàn)以下代碼,當(dāng)我們使用int類型的時(shí)候,默認(rèn)創(chuàng)建的字段是非空(NOT NULL),而使用Integer的時(shí)候,創(chuàng)建的字段沒有添加限制戈次。自己可以試一下,看看區(qū)別。