前言
因为遇到需求需要保存数据到本地数据库,一起开发的同事选用了Room数据库框架移植到项目中,于是我也只能去学习使用这种框架。了解之后发现这个框架建库、建表、数据库升级等操作都十分简单,很适合怕麻烦的攻城狮们使用。
正文
1.建表
这里以常用的存储用户信息的user表为例:
/**
* @Description: 存储用户信息到本地数据库
* @author: jesse_android
* @date: 2019/4/19
*/
@Entity(tableName = "user")
public class UserInfo {
@PrimaryKey(autoGenerate = true)
private int id;
private int userId;
private String mobile;
private String nickname;
private String avatar;
private String category;
private String instituteId;
private int role;
private int certify;//认证状态 0未认证 1已认证
private int partner;//是否是合伙人 0不是 1是
public UserInfo(int userId, String mobile) {
this.userId = userId;
this.mobile = mobile;
}
@Ignore
public UserInfo(){}
@Ignore
public UserInfo(OrgLoginBean loginBean) {
this.userId = loginBean.getData().getUserId();
this.mobile = loginBean.getData().getMobile();
this.nickname = loginBean.getData().getNickname();
this.avatar = loginBean.getData().getAvatar();
this.certify = loginBean.getData().getCertify();
this.partner = loginBean.getData().getPartner();
}
@Ignore
public UserInfo(int userId, String mobile, String nickname, String avatar, String category, String instituteId) {
this.userId = userId;
this.mobile = mobile;
this.nickname = nickname;
this.avatar = avatar;
this.category = category;
this.instituteId = instituteId;
}
@Ignore
public UserInfo(int userId, String mobile, String nickname, String avatar, int certify) {
this.userId = userId;
this.mobile = mobile;
this.nickname = nickname;
this.avatar = avatar;
this.certify = certify;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getInstituteId() {
return instituteId;
}
public void setInstituteId(String instituteId) {
this.instituteId = instituteId;
}
public int getRole() {
return role;
}
public void setRole(int role) {
this.role = role;
}
public int getCertify() {
return certify;
}
public void setCertify(int certify) {
this.certify = certify;
}
public int getPartner() {
return partner;
}
public void setPartner(int partner) {
this.partner = partner;
}
@Override
public String toString() {
return "UserInfo{" +
"id=" + id +
", userId=" + userId +
", mobile='" + mobile + '\'' +
", nickname='" + nickname + '\'' +
", avatar='" + avatar + '\'' +
", category='" + category + '\'' +
", instituteId='" + instituteId + '\'' +
", role=" + role +
", certify=" + certify +
", partner=" + partner +
'}';
}
}
细节解析:
1.@Entity(tableName = "user")--定义表明为user;
2.@PrimaryKey(autoGenerate = true)--将下方字段设置为主键并且自增;autoGenerate = true--自增;
3.@Ignore--编译时忽略下方的构造方法;(一个实体类只允许有一个构造方法进入编译,否则报错。因此只能留一个构造方法,其余的都要加上@Ignore标签!!!加上这个标签并不会影响你正常调用)
2.建库
为什么先说建表再说建库?因为建库的时候会用到表。
@Database(entities = {UserInfo.class}, version = 1, exportSchema = false)
public abstract class CoursewareDataBase extends RoomDatabase {
private static final String DB_NAME = "CoursewareDatabase.db";
private static volatile CoursewareDataBase instance;
static synchronized CoursewareDataBase getInstance(Context context) {
if (instance == null) {
instance = create(context);
}
return instance;
}
private static CoursewareDataBase create(final Context context) {
return Room.databaseBuilder(context, CoursewareDataBase.class, DB_NAME)
.addMigrations(migration_1_2)
.addMigrations(migration_2_3)
.addMigrations(migration_3_4)
.addMigrations(migration_4_5)
.build();
}
//@{版本号升级后一定要加migration
private static Migration migration_1_2 = new Migration(1, 2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE user ADD certify INTEGER NOT NULL DEFAULT 0");
}
};
private static Migration migration_2_3 = new Migration(2, 3) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE video_list ADD stage TEXT DEFAULT ''");
}
};
private static Migration migration_3_4 = new Migration(3, 4) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE video_list ADD views INTEGER NOT NULL DEFAULT 0");
}
};
private static Migration migration_4_5 = new Migration(4, 5) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE user ADD partner INTEGER NOT NULL DEFAULT 0");
}
};
//@}
public abstract UserDao getUserDao();
}
细节解析:
1.@Database(entities = {UserInfo.class}, version = 1, exportSchema = false)--声明该类作为一个本地数据库;entities={}--你建的表的实体类必须在花括号中声明;version = 1--当前数据库版本为1,要升级数据库版本的话,需要填入比当前数字更大的数字,比如2;exportSchema = false--如果设置为true,在app目录下会生成一个Schema文件夹,里面会生成数据库版本.json文件,设置为true有报错风险,建议设为false。
2.public abstract class CoursewareDataBase extends RoomDatabase--注意这里必须要设置该类为抽象类,然后继承RoomDataBase类;
3.创建数据库、数据库版本升级:
private static CoursewareDataBase create(final Context context) {
return Room.databaseBuilder(context, CoursewareDataBase.class, DB_NAME)
.addMigrations(migration_1_2)
.addMigrations(migration_2_3)
.addMigrations(migration_3_4)
.addMigrations(migration_4_5)
.build();
}
//@{版本号升级后一定要加migration
private static Migration migration_1_2 = new Migration(1, 2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE user ADD certify INTEGER NOT NULL DEFAULT 0");
}
};
--版本升级照着这样写就行了,不用我多说应该能看懂,如果是初始数据库版本,则不用写addMigrations,直接return Room.databaseBuilder(context, CoursewareDataBase.class, DB_NAME).build();即可。
4.public abstract UserDao getUserDao();--需要用到的Dao文件必须在类中声明。
3.创建Dao文件
@Dao
public interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertUser(UserInfo... userinfo);
@Query("SELECT * FROM user")
List<UserInfo> queryAll();
@Query("SELECT * FROM user where userId = :userId")
UserInfo queryUser(int userId);
@Query("DELETE FROM user where userId = :userId")
void deleteUser(int userId);
}
细节解析:
1.@Dao--声明该类为Dao文件(用来操作表增删改查的文件);
2.@Insert(onConflict = OnConflictStrategy.REPLACE)--插入一条新数据到表中;onConflict = OnConflictStrategy.REPLACE--如果插入的新数据在表中已经存在,即如果遇上数据冲突的情况,新数据直接替换旧数据;
3.@Query("SELECT * FROM user")--@Query标签后方的括号里可用的语句不仅仅限于查询语句,其他所有SQL语句都可以写在里面,比如你可以使用这个标签做delete操作:@Query("DELETE FROM user where userId = :userId");--:userId 表示使用下方传入的userId参数。
4.使用Dao文件操作数据库
private CoursewareDataBase coursewareDataBase;
private UserDao userDao;
coursewareDataBase = CoursewareDataBase.getInstance(context);
userDao = coursewareDataBase.getUserDao();
new Thread(new Runnable() {
@Override
public void run() {
List<UserInfo> userInfoList = userDao.queryAll();
}
}).start();
这里特别要注意的就是userDao.queryAll()这句代码必须放在子线程中,否则会报错。以上是以调用queryAll方法作为例子,调用其他userDao中的方法同样。
附上博主使用的room项目依赖添加代码:
implementation('android.arch.persistence.room:runtime:1.0.0') {
exclude group: 'com.android.support'
}
annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
结语
从创建到数据库升级到使用Dao文件操作数据库,流程相当简单,这就是Room这个框架的优势,但是只能在子线程中进行数据库操作是它的硬伤,如果你能接受这一点的话,那么Room也不失为一个好的android本地数据库框架。
如果这篇文章对你有帮助,点下免费的赞和关注鼓励一下吧,这些都是我更博的动力,谢啦~
有不懂或者使用过程中遇到什么问题的,欢迎下方留言。