我相信删除.fallbackToDestructiveMigration()
将解决您的问题;另一种方法是确保将预填充数据库的USER_VERSION设置为编码的数据库版本.
- note only a coded version 1 has been tested. (see below)
然而,实际上不应该有这种需要,因为只有当数据库版本与编码版本不同并且数据库的版本应该设置为编码版本时,才应该调用销毁.
- i.e. this may well be a bug个
一些基本的测试似乎突出了很可能是一个漏洞.也就是说,如果预填充版本设置为0(使用PRAGMA user_version = 0;
),则复制的数据库看起来会被销毁并再次复制.然而,如果预填充的数据库的版本(PRAGMA user_version = 1
),则该数据库持续存在.
Demonstration个
首先创建了一些基本的@Entity
个带注释的类,如下所示:
@Entity
class DeviceInfo {
@PrimaryKey
Long id=null;
String name;
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
及:-
@Entity
class AddressInfo {
@PrimaryKey
Long id=null;
String name;
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
还有约@Dao
个带注释的接口:-
@Dao
interface DeviceDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
long insert(DeviceInfo deviceInfo);
@Query("SELECT * FROM deviceinfo")
List<DeviceInfo> getAllDeviceInfoRows();
}
及:-
@Dao
interface AddressDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
long insert(AddressInfo addressInfo);
@Query("SELECT * FROM addressinfo")
List<AddressInfo> getAllAddressInfoRows();
@Update
public void updateAddressInfo(AddressInfo addressInfo);
}
然后修改(以添加回调)@Database
注释的AppDataBase类:-
@Database(entities = {DeviceInfo.class, AddressInfo.class},version = 1)
public abstract class AppDataBase extends RoomDatabase {
public abstract DeviceDao deviceDao();
public abstract AddressDao addressDao();
private static AppDataBase instance;
public static synchronized AppDataBase getInstance(Context context){
if(instance == null){
instance = Room.databaseBuilder(context.getApplicationContext(), AppDataBase.class,"device.db")
.createFromAsset("device.db")
.fallbackToDestructiveMigration()
.addCallback(new Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
Log.d(MainActivity.TAG,"ONCREATE INVOKED.");
}
@Override
public void onDestructiveMigration(@NonNull SupportSQLiteDatabase db) {
super.onDestructiveMigration(db);
Log.d(MainActivity.TAG,"ONDESTRUCTIVEMIGRATION INVOKED DBVERSION=" + db.getVersion());
}
@Override
public void onOpen(@NonNull SupportSQLiteDatabase db) {
super.onOpen(db);
Log.d(MainActivity.TAG,"ONOPEN INVOKED");
}
})
.allowMainThreadQueries() /* added for brevity */
.build();
}
return instance;
}
}
- 请注意,添加
.allowMainThreadQueries
是为了利用主线程,从而减少所需的代码.
使用Navicat时,使用以下SQL创建了2个数据库文件,其中一个的User_vesrion为0,另一个为1,使用:-
DROP TABLE IF EXISTS `DeviceInfo`;
DROP TABLE IF EXISTS `AddressInfo`;
CREATE TABLE IF NOT EXISTS `DeviceInfo` (`id` INTEGER, `name` TEXT, PRIMARY KEY(`id`));
CREATE TABLE IF NOT EXISTS `AddressInfo` (`id` INTEGER, `name` TEXT, PRIMARY KEY(`id`));
INSERT OR IGNORE INTO `DeviceInfo` VALUES (100,'PPDEVICE001'),(null,'PPDEVICE002');
INSERT OR IGNORE INTO `AddressInfo` VALUES (100,'PPADDRESS001'),(null,'PPADDRESS002');
PRAGMA user_version = 0;
PRAGMA user_version;
- 显然,对于第二个文件,Pragma USER_VERSION=1.
The files were copied into the assets folder e.g. :-
- 根据正在进行的测试,从相应的其他文件中删除和复制
device.db
个文件.
最后是一些测试代码:
public class MainActivity extends AppCompatActivity {
public static final String TAG = "DBINFO";
AppDataBase db;
AddressDao addressDao;
DeviceDao deviceDao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = AppDataBase.getInstance(this);
deviceDao = db.deviceDao();
addressDao = db.addressDao();
getAll("_S1", db);
for (AddressInfo ai: addressDao.getAllAddressInfoRows()) {
ai.setName(ai.getName() + ai.getName());
addressDao.updateAddressInfo(ai);
}
getAll("S2", db);
}
void getAll(String tag_suffix, AppDataBase adb) {
logDBInfo(tag_suffix, adb);
logDevices(tag_suffix);
logAddresses(tag_suffix);
}
void logDBInfo(String tag_suffix,AppDataBase adb) {
SupportSQLiteDatabase sdb = adb.getOpenHelper().getWritableDatabase();
Log.d(TAG + tag_suffix, "DB VERSION is " + sdb.getVersion() + "DB PATH is " + sdb.getPath());
}
void logDevices(String tag_suffix) {
for(DeviceInfo di: deviceDao.getAllDeviceInfoRows()) {
Log.d(TAG + tag_suffix,"Device ID is " + di.getId() + " NAME is " + di.getName());
}
}
void logAddresses(String tag_suffix) {
for(AddressInfo ai: addressDao.getAllAddressInfoRows()) {
Log.d(TAG + tag_suffix,"Address ID is " + ai.getId() + " NAME is " + ai.getName());
}
}
}
TESTING个
100
最初,device_userversion0.db
被复制为device.db
.该应用程序卸载后运行(即全新安装).导致日志(log)显示:-
2023-12-20 15:58:01.204 D/DBINFO: ONCREATE INVOKED.
2023-12-20 15:58:01.211 D/DBINFO: ONOPEN INVOKED
2023-12-20 15:58:01.214 D/DBINFO_S1: DB VERSION is 1DB PATH is /data/user/0/a.a.so77689044javaroomalwaysprepopulates/databases/device.db
2023-12-20 15:58:01.219 D/DBINFO_S1: Device ID is 100 NAME is PPDEVICE001
2023-12-20 15:58:01.219 D/DBINFO_S1: Device ID is 101 NAME is PPDEVICE002
2023-12-20 15:58:01.220 D/DBINFO_S1: Address ID is 100 NAME is PPADDRESS001
2023-12-20 15:58:01.220 D/DBINFO_S1: Address ID is 101 NAME is PPADDRESS002
2023-12-20 15:58:01.224 D/DBINFOS2: DB VERSION is 1DB PATH is /data/user/0/a.a.so77689044javaroomalwaysprepopulates/databases/device.db
2023-12-20 15:58:01.229 D/DBINFOS2: Device ID is 100 NAME is PPDEVICE001
2023-12-20 15:58:01.229 D/DBINFOS2: Device ID is 101 NAME is PPDEVICE002
2023-12-20 15:58:01.231 D/DBINFOS2: Address ID is 100 NAME is PPADDRESS001PPADDRESS001
2023-12-20 15:58:01.231 D/DBINFOS2: Address ID is 101 NAME is PPADDRESS002PPADDRESS002
- 结果正如预期的那样,数据库已经填充,然后更新了2个地址行(名称现在是原始名称重复).
100
应用程序只需重新运行,输出:-
2023-12-20 16:01:11.520 D/DBINFO: ONCREATE INVOKED.
2023-12-20 16:01:11.527 D/DBINFO: ONOPEN INVOKED
2023-12-20 16:01:11.530 D/DBINFO_S1: DB VERSION is 1DB PATH is /data/user/0/a.a.so77689044javaroomalwaysprepopulates/databases/device.db
2023-12-20 16:01:11.533 D/DBINFO_S1: Device ID is 100 NAME is PPDEVICE001
2023-12-20 16:01:11.533 D/DBINFO_S1: Device ID is 101 NAME is PPDEVICE002
2023-12-20 16:01:11.534 D/DBINFO_S1: Address ID is 100 NAME is PPADDRESS001
2023-12-20 16:01:11.534 D/DBINFO_S1: Address ID is 101 NAME is PPADDRESS002
2023-12-20 16:01:11.538 D/DBINFOS2: DB VERSION is 1DB PATH is /data/user/0/a.a.so77689044javaroomalwaysprepopulates/databases/device.db
2023-12-20 16:01:11.539 D/DBINFOS2: Device ID is 100 NAME is PPDEVICE001
2023-12-20 16:01:11.539 D/DBINFOS2: Device ID is 101 NAME is PPDEVICE002
2023-12-20 16:01:11.542 D/DBINFOS2: Address ID is 100 NAME is PPADDRESS001PPADDRESS001
2023-12-20 16:01:11.542 D/DBINFOS2: Address ID is 101 NAME is PPADDRESS002PPADDRESS002
- 即,除了实际运行时间之外,它是相同的,因此更新的数据没有被保留(原本预计地址名称会更长).
100
The line .fallbackToDestructiveMigration
has been commented out and the App rerun.
这次的输出是:-
2023-12-20 16:05:31.133 D/DBINFO: ONOPEN INVOKED
2023-12-20 16:05:31.136 D/DBINFO_S1: DB VERSION is 1DB PATH is /data/user/0/a.a.so77689044javaroomalwaysprepopulates/databases/device.db
2023-12-20 16:05:31.140 D/DBINFO_S1: Device ID is 100 NAME is PPDEVICE001
2023-12-20 16:05:31.140 D/DBINFO_S1: Device ID is 101 NAME is PPDEVICE002
2023-12-20 16:05:31.142 D/DBINFO_S1: Address ID is 100 NAME is PPADDRESS001PPADDRESS001
2023-12-20 16:05:31.142 D/DBINFO_S1: Address ID is 101 NAME is PPADDRESS002PPADDRESS002
2023-12-20 16:05:31.164 D/DBINFOS2: DB VERSION is 1DB PATH is /data/user/0/a.a.so77689044javaroomalwaysprepopulates/databases/device.db
2023-12-20 16:05:31.166 D/DBINFOS2: Device ID is 100 NAME is PPDEVICE001
2023-12-20 16:05:31.167 D/DBINFOS2: Device ID is 101 NAME is PPDEVICE002
2023-12-20 16:05:31.169 D/DBINFOS2: Address ID is 100 NAME is PPADDRESS001PPADDRESS001PPADDRESS001PPADDRESS001
2023-12-20 16:05:31.169 D/DBINFOS2: Address ID is 101 NAME is PPADDRESS002PPADDRESS002PPADDRESS002PPADDRESS002
- 即数据是持久存在的,而不是被替换的(地址名称现在是原始名称的4次出现).
101应用程序被卸载并运行3次,其中.fallbackToDestructiveMigration
个被注释掉.这次的地址行是:-
D/DBINFOS2: Address ID is 100 NAME is PPADDRESS001PPADDRESS001PPADDRESS001PPADDRESS001PPADDRESS001PPADDRESS001PPADDRESS001PPADDRESS001
D/DBINFOS2: Address ID is 101 NAME is PPADDRESS002PPADDRESS002PPADDRESS002PPADDRESS002PPADDRESS002PPADDRESS002PPADDRESS002PPADDRESS002
** 所以在这个阶段不包括.fallback....
个解决问题的方法(bug).
Test5 The App is uninstalled and the device.db
file is deleted and copied from device_userversion1.db and .fallbackToDestructiveMigration
is reinstated as per:-
第一次运行的输出为:-
2023-12-20 16:16:23.257 D/DBINFO: ONOPEN INVOKED
2023-12-20 16:16:23.260 D/DBINFO_S1: DB VERSION is 1DB PATH is /data/user/0/a.a.so77689044javaroomalwaysprepopulates/databases/device.db
2023-12-20 16:16:23.264 D/DBINFO_S1: Device ID is 100 NAME is PPDEVICE001
2023-12-20 16:16:23.264 D/DBINFO_S1: Device ID is 101 NAME is PPDEVICE002
2023-12-20 16:16:23.266 D/DBINFO_S1: Address ID is 100 NAME is PPADDRESS001
2023-12-20 16:16:23.266 D/DBINFO_S1: Address ID is 101 NAME is PPADDRESS002
2023-12-20 16:16:23.275 D/DBINFOS2: DB VERSION is 1DB PATH is /data/user/0/a.a.so77689044javaroomalwaysprepopulates/databases/device.db
2023-12-20 16:16:23.279 D/DBINFOS2: Device ID is 100 NAME is PPDEVICE001
2023-12-20 16:16:23.279 D/DBINFOS2: Device ID is 101 NAME is PPDEVICE002
2023-12-20 16:16:23.283 D/DBINFOS2: Address ID is 100 NAME is PPADDRESS001PPADDRESS001
2023-12-20 16:16:23.283 D/DBINFOS2: Address ID is 101 NAME is PPADDRESS002PPADDRESS002
- Note that ONCREATE is not called???, whilst previously it was on the first run个
100重新运行应用程序,输出:-
2023-12-20 16:19:39.703 D/DBINFO: ONOPEN INVOKED
2023-12-20 16:19:39.705 D/DBINFO_S1: DB VERSION is 1DB PATH is /data/user/0/a.a.so77689044javaroomalwaysprepopulates/databases/device.db
2023-12-20 16:19:39.709 D/DBINFO_S1: Device ID is 100 NAME is PPDEVICE001
2023-12-20 16:19:39.709 D/DBINFO_S1: Device ID is 101 NAME is PPDEVICE002
2023-12-20 16:19:39.712 D/DBINFO_S1: Address ID is 100 NAME is PPADDRESS001PPADDRESS001
2023-12-20 16:19:39.712 D/DBINFO_S1: Address ID is 101 NAME is PPADDRESS002PPADDRESS002
2023-12-20 16:19:39.728 D/DBINFOS2: DB VERSION is 1DB PATH is /data/user/0/a.a.so77689044javaroomalwaysprepopulates/databases/device.db
2023-12-20 16:19:39.730 D/DBINFOS2: Device ID is 100 NAME is PPDEVICE001
2023-12-20 16:19:39.730 D/DBINFOS2: Device ID is 101 NAME is PPDEVICE002
2023-12-20 16:19:39.731 D/DBINFOS2: Address ID is 100 NAME is PPADDRESS001PPADDRESS001PPADDRESS001PPADDRESS001
2023-12-20 16:19:39.731 D/DBINFOS2: Address ID is 101 NAME is PPADDRESS002PPADDRESS002PPADDRESS002PPADDRESS002
100第三次跑:-
2023-12-20 16:21:52.877 D/DBINFO: ONOPEN INVOKED
2023-12-20 16:21:52.879 D/DBINFO_S1: DB VERSION is 1DB PATH is /data/user/0/a.a.so77689044javaroomalwaysprepopulates/databases/device.db
2023-12-20 16:21:52.883 D/DBINFO_S1: Device ID is 100 NAME is PPDEVICE001
2023-12-20 16:21:52.883 D/DBINFO_S1: Device ID is 101 NAME is PPDEVICE002
2023-12-20 16:21:52.886 D/DBINFO_S1: Address ID is 100 NAME is PPADDRESS001PPADDRESS001PPADDRESS001PPADDRESS001
2023-12-20 16:21:52.886 D/DBINFO_S1: Address ID is 101 NAME is PPADDRESS002PPADDRESS002PPADDRESS002PPADDRESS002
2023-12-20 16:21:52.901 D/DBINFOS2: DB VERSION is 1DB PATH is /data/user/0/a.a.so77689044javaroomalwaysprepopulates/databases/device.db
2023-12-20 16:21:52.904 D/DBINFOS2: Device ID is 100 NAME is PPDEVICE001
2023-12-20 16:21:52.904 D/DBINFOS2: Device ID is 101 NAME is PPDEVICE002
2023-12-20 16:21:52.905 D/DBINFOS2: Address ID is 100 NAME is PPADDRESS001PPADDRESS001PPADDRESS001PPADDRESS001PPADDRESS001PPADDRESS001PPADDRESS001PPADDRESS001
2023-12-20 16:21:52.905 D/DBINFOS2: Address ID is 101 NAME is PPADDRESS002PPADDRESS002PPADDRESS002PPADDRESS002PPADDRESS002PPADDRESS002PPADDRESS002PPADDRESS002
- Again as expected. So setting the user_version to 1 results in the anticipated results.这就是为什么一个bug被怀疑是(the version of the pre-populated database should not influence runs after the database has been populated).