Android - 多个数据库一个项目
Android - Multiple database one project
请问是否可以在一个项目下拥有多个数据库,使用Room Persistence Library?动态更改数据库的选择。
谢谢
有可能。
假设您有两组实体和两组 DAO。您可以通过以下方式获得对两个数据库的访问权限:
- 创建两个扩展 RoomDatabase 的 类:
应用程序数据库 1:
@Database(entities = {/*... the first set of entities ...*/}, version = 1)
public abstract class AppDatabase1 extends RoomDatabase {
// the first set of DAOs
}
AppDatabase2:
@Database(entities = {/*... the second set of entities ...*/}, version = 1)
public abstract class AppDatabase2 extends RoomDatabase {
// the second set of DAOs
}
- 实例化两个数据库:
请注意,您将使用两个不同的文件名。
AppDatabase db1 = Room.databaseBuilder(getApplicationContext(), AppDatabase1.class, "database1.db").build();
AppDatabase db2 = Room.databaseBuilder(getApplicationContext(), AppDatabase2.class, "database2.db").build();
在这种情况下,您可以使用这两个数据库,但不能在它们之间创建查询。如果你需要附加这两个数据库,那么你应该看看 link @Anees 提供的
如果数据库具有相同的模式并在它们之间动态切换,您可以重用实体和 DAO(如果您想为每个用户使用不同的数据库文件,这很有用)。
实体class
@Entity
public class User {
@PrimaryKey
@NonNull
public String uid;
@ColumnInfo(name = "first_name")
public String firstName;
@ColumnInfo(name = "last_name")
public String lastName;
}
DAO class
@Dao
public interface UserDao {
@Query("SELECT * FROM user")
List<User> getAll();
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
List<User> loadAllByIds(int[] userIds);
@Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
"last_name LIKE :last LIMIT 1")
User findByName(String first, String last);
@Insert
void insertAll(User... users);
@Delete
void delete(User user);
}
数据库class
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
数据库客户端class
public class DatabaseClient {
private Context mCtx;
private AppDatabase appDatabase;
private static String databaseName;
private static DatabaseClient mInstance;
private DatabaseClient(Context mCtx, String dbName) {
this.mCtx = mCtx;
if(databaseName == null || !databaseName.equalsIgnoreCase(dbName)) {
databaseName = dbName;
}
appDatabase = Room.databaseBuilder(mCtx, AppDatabase.class, databaseName).build();
}
public String getDatabaseName() {
return databaseName;
}
public static synchronized DatabaseClient getInstance(Context mCtx, String dbName) {
if (mInstance == null || databaseName == null || !databaseName.equalsIgnoreCase(dbName)) {
mInstance = new DatabaseClient(mCtx, dbName);
}
return mInstance;
}
public AppDatabase getAppDatabase() {
return appDatabase;
}
}
现在您可以通过在我的例子中的参数中传递数据库的名称来基于特定数据库进行查询,让我们说 myDb
List<User> users = DatabaseClient.getInstance(getApplicationContext(), myDb).getAppDatabase().userDao().getAll()
请记住,每当您使用数据库名称执行第一次调用时,它都会创建数据库文件。如果有新用户来电插入其信息,它会自动创建一个新的数据库文件并将信息数据插入其中。
刚刚用 koin 解决了它。我正在创建一个即时消息应用程序,需要多个帐户登录。 user1登录我的应用程序后,可以获取带有im_id的数据库名称,然后通过注入,我创建了带有id的数据库。然后user1一个logout,我直接卸载datasource模块跳转到loginactivity。然后 User2 登录,我重新加载数据源模块并使用他的 im_id 为 user2 创建数据库。代码如下:
val dataSourceModule = module{
single {
Room.databaseBuilder(androidApplication(), AppDataBase::class.java, get<GsSelectedAndImTokenPersistence>().gsImToken?.gsImId ?: "im_database" )
.build()
}
single { get<AppDataBase>().gsInfoDao() }
single { get<AppDataBase>().gsGameInfoDao() }
single { get<AppDataBase>().gameClientDao() }
single { SharedPreferencesDataSourceImpl(androidContext()) } binds (
arrayOf(
ImDeviceIdPersistence::class,
GsSelectedAndImTokenPersistence::class
))
}
fun unLoadDataSourceModule() {
unloadKoinModules(dataSourceModule)
}
fun reLoadDataSourceModule() {
loadKoinModules(dataSourceModule)
}
有趣的是,即使
get().gsImToken?.gsImId
为空,它不会使用 koin inject.
创建名称为“im_database”的默认数据库
这是我通过注入创建数据库的地方,在我从服务器
获得im_id之后
viewModel.gsImToken.observe(provideLifecycleOwner(), {
ELogger.d("database initial","init database===")
// Incase of the datasource module is not loaded by now
KoinInitializer.reLoadDataSourceModule()
val gs: AppDataBase by inject()
gs.gsGameInfoDao().run {
viewModel.initDao(this)
}
})
以及登出地点:
class SettingViewModel(
...,
val db: AppDataBase
): ViewModel() {
...
fun onLogout(){
...
db.close()
KoinInitializer.unLoadDataSourceModule()
...
}
}
请问是否可以在一个项目下拥有多个数据库,使用Room Persistence Library?动态更改数据库的选择。 谢谢
有可能。 假设您有两组实体和两组 DAO。您可以通过以下方式获得对两个数据库的访问权限:
- 创建两个扩展 RoomDatabase 的 类:
应用程序数据库 1:
@Database(entities = {/*... the first set of entities ...*/}, version = 1)
public abstract class AppDatabase1 extends RoomDatabase {
// the first set of DAOs
}
AppDatabase2:
@Database(entities = {/*... the second set of entities ...*/}, version = 1)
public abstract class AppDatabase2 extends RoomDatabase {
// the second set of DAOs
}
- 实例化两个数据库:
请注意,您将使用两个不同的文件名。
AppDatabase db1 = Room.databaseBuilder(getApplicationContext(), AppDatabase1.class, "database1.db").build();
AppDatabase db2 = Room.databaseBuilder(getApplicationContext(), AppDatabase2.class, "database2.db").build();
在这种情况下,您可以使用这两个数据库,但不能在它们之间创建查询。如果你需要附加这两个数据库,那么你应该看看 link @Anees 提供的
如果数据库具有相同的模式并在它们之间动态切换,您可以重用实体和 DAO(如果您想为每个用户使用不同的数据库文件,这很有用)。
实体class
@Entity
public class User {
@PrimaryKey
@NonNull
public String uid;
@ColumnInfo(name = "first_name")
public String firstName;
@ColumnInfo(name = "last_name")
public String lastName;
}
DAO class
@Dao
public interface UserDao {
@Query("SELECT * FROM user")
List<User> getAll();
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
List<User> loadAllByIds(int[] userIds);
@Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
"last_name LIKE :last LIMIT 1")
User findByName(String first, String last);
@Insert
void insertAll(User... users);
@Delete
void delete(User user);
}
数据库class
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
数据库客户端class
public class DatabaseClient {
private Context mCtx;
private AppDatabase appDatabase;
private static String databaseName;
private static DatabaseClient mInstance;
private DatabaseClient(Context mCtx, String dbName) {
this.mCtx = mCtx;
if(databaseName == null || !databaseName.equalsIgnoreCase(dbName)) {
databaseName = dbName;
}
appDatabase = Room.databaseBuilder(mCtx, AppDatabase.class, databaseName).build();
}
public String getDatabaseName() {
return databaseName;
}
public static synchronized DatabaseClient getInstance(Context mCtx, String dbName) {
if (mInstance == null || databaseName == null || !databaseName.equalsIgnoreCase(dbName)) {
mInstance = new DatabaseClient(mCtx, dbName);
}
return mInstance;
}
public AppDatabase getAppDatabase() {
return appDatabase;
}
}
现在您可以通过在我的例子中的参数中传递数据库的名称来基于特定数据库进行查询,让我们说 myDb
List<User> users = DatabaseClient.getInstance(getApplicationContext(), myDb).getAppDatabase().userDao().getAll()
请记住,每当您使用数据库名称执行第一次调用时,它都会创建数据库文件。如果有新用户来电插入其信息,它会自动创建一个新的数据库文件并将信息数据插入其中。
刚刚用 koin 解决了它。我正在创建一个即时消息应用程序,需要多个帐户登录。 user1登录我的应用程序后,可以获取带有im_id的数据库名称,然后通过注入,我创建了带有id的数据库。然后user1一个logout,我直接卸载datasource模块跳转到loginactivity。然后 User2 登录,我重新加载数据源模块并使用他的 im_id 为 user2 创建数据库。代码如下:
val dataSourceModule = module{
single {
Room.databaseBuilder(androidApplication(), AppDataBase::class.java, get<GsSelectedAndImTokenPersistence>().gsImToken?.gsImId ?: "im_database" )
.build()
}
single { get<AppDataBase>().gsInfoDao() }
single { get<AppDataBase>().gsGameInfoDao() }
single { get<AppDataBase>().gameClientDao() }
single { SharedPreferencesDataSourceImpl(androidContext()) } binds (
arrayOf(
ImDeviceIdPersistence::class,
GsSelectedAndImTokenPersistence::class
))
}
fun unLoadDataSourceModule() {
unloadKoinModules(dataSourceModule)
}
fun reLoadDataSourceModule() {
loadKoinModules(dataSourceModule)
}
有趣的是,即使 get().gsImToken?.gsImId 为空,它不会使用 koin inject.
创建名称为“im_database”的默认数据库这是我通过注入创建数据库的地方,在我从服务器
获得im_id之后 viewModel.gsImToken.observe(provideLifecycleOwner(), {
ELogger.d("database initial","init database===")
// Incase of the datasource module is not loaded by now
KoinInitializer.reLoadDataSourceModule()
val gs: AppDataBase by inject()
gs.gsGameInfoDao().run {
viewModel.initDao(this)
}
})
以及登出地点:
class SettingViewModel(
...,
val db: AppDataBase
): ViewModel() {
...
fun onLogout(){
...
db.close()
KoinInitializer.unLoadDataSourceModule()
...
}
}