Room数据库仅能插入单条数据,新增/修改操作失效求助
Android Room数据库插入/修改异常排查与解决
现象描述
- 在
PersonRoomDatabase的回调中插入person1和person2,Database Inspector仅显示person1 - MainActivity中插入person3未成功
- 修改person1名称后,数据库中仍显示原名称"saul"
- 仅person1能正常存在,无法新增或修改其他Person对象
相关代码
1. PersonRoomDatabase类
@Database(entities = {Person.class},version = 1,exportSchema = false) public abstract class PersonRoomDatabase extends RoomDatabase { public abstract PersonDAO personRoomDAO(); private static volatile PersonRoomDatabase INSTANCE; public static final int NUMBER_OF_THREADS=4; static final ExecutorService databaseWriteExecutor= Executors.newFixedThreadPool(NUMBER_OF_THREADS); // 单例模式确保仅存在一个数据库实例 static final PersonRoomDatabase getDatabase(final Context context){ if (INSTANCE==null){ synchronized (PersonRoomDatabase.class){ if (INSTANCE==null){ INSTANCE= Room.databaseBuilder(context.getApplicationContext(), PersonRoomDatabase.class,"person_database") .addCallback(sRoomDatabaseCallback) .build(); } } } return INSTANCE; } private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback() { @Override public void onCreate(@NonNull SupportSQLiteDatabase db) { super.onCreate(db); databaseWriteExecutor.execute(() -> { PersonDAO dao = INSTANCE.personRoomDAO(); dao.deleteAll(); Person person1=new Person("saul","goodman"); dao.insert(person1); Person person2=new Person("walter","white"); dao.insert(person2); }); } }; }
2. PersonDAO接口
@Dao public interface PersonDAO { @Insert(onConflict = OnConflictStrategy.IGNORE) void insert(Person person); @Query("DELETE FROM person_table") void deleteAll(); @Query("SELECT * FROM person_table ORDER BY name ASC") LiveData<List<Person>> selectAllPerson(); }
3. PersonViewModel类
public class PersonViewModel extends AndroidViewModel { private PersonRepository personViewModelRepository; private final LiveData<List<Person>> allPersonViewModel; public PersonViewModel(@NonNull Application application) { super(application); personViewModelRepository=new PersonRepository(application); allPersonViewModel=personViewModelRepository.getAllPersonsRepository(); } public LiveData<List<Person>> getAllPersonViewModel(){return allPersonViewModel;} public void insert(Person person){ personViewModelRepository.insert(person);} public void deleteAll(){personViewModelRepository.deleteAll();} }
4. PersonRepository类
public class PersonRepository { private PersonDAO personRepositoryDAO; private LiveData<List<Person>> allPersons; PersonRepository (Application application){ PersonRoomDatabase db=PersonRoomDatabase.getDatabase(application); personRepositoryDAO=db.personRoomDAO(); allPersons=personRepositoryDAO.selectAllPerson(); } LiveData<List<Person>> getAllPersonsRepository() { return allPersons; } void insert(Person person){ PersonRoomDatabase.databaseWriteExecutor.execute(() -> personRepositoryDAO.insert(person)); } void deleteAll(){ PersonRoomDatabase.databaseWriteExecutor.execute(() -> personRepositoryDAO.deleteAll()); } }
5. Person实体类
@Entity(tableName = "person_table") public class Person { @PrimaryKey @ColumnInfo(name = "id") private int id; @ColumnInfo(name = "name") private String name; @ColumnInfo(name = "lastName") private String lastName; public Person(){ } public void setLastName(String lastName) { this.lastName = lastName; } public void setName(String name) { this.name = name; } public Person(String name, String lastName) { this.name = name; this.lastName = lastName; } public void setId(int id) { this.id = id; } public int getId() { return id; } public String getName() { return name; } public String getLastName() { return lastName; } }
6. MainActivity类
public class MainActivity extends AppCompatActivity { public Person person; private PersonViewModel personViewModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); personViewModel= new ViewModelProvider.AndroidViewModelFactory(MainActivity.this .getApplication()) .create(PersonViewModel.class); Person person3=new Person("jesse","pinkman"); personViewModel.insert(person3); personViewModel.getAllPersonViewModel().observe(this,person -> Log.d("Observe", "onCreate: "+person.get(0).getName()) ); } }
问题根源
核心问题出在Person实体类的主键设置:
- 将
id设为@PrimaryKey,但创建Person对象时未给id赋值,默认int类型的id值为0 - 插入person1时,id=0被写入数据库;插入person2、person3时,id同样是0,DAO的
@Insert(onConflict = OnConflictStrategy.IGNORE)注解会在主键冲突时忽略插入操作,导致person2、person3无法写入 - 修改person1名称时,若重新插入id=0的对象,同样触发IGNORE策略,数据库记录不会更新
解决方案
1. 让主键自动生成(推荐)
修改Person实体类的主键注解,添加autoGenerate = true,让Room自动为每条记录生成唯一id:
@PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") private int id;
此后每次插入新Person对象时,Room会自动分配递增的唯一id,避免主键冲突,person2、person3可正常插入。
2. 添加更新方法支持数据修改
在DAO接口中新增更新方法,用于修改已有记录:
@Dao public interface PersonDAO { // ... 原有方法 @Update void update(Person person); }
修改person1时,先查询到该对象,修改属性后调用update()方法,而非重新插入。
3. 验证步骤
- 修改实体类后,卸载App或清除App数据(让Room重新创建数据库)
- 运行App,查看Database Inspector确认person1、person2均显示
- 测试插入person3,确认正常添加
- 测试修改person1名称,调用update方法后确认数据库记录更新
内容的提问来源于stack exchange,提问作者mehmet ali duran
相关产品推荐
相关产品推荐

