android学习android相关Android开发

Room使用详解及常用数据库对比

2020-12-31  本文已影响0人  Jerck_NING

Android Jetpack组件 —— Room使用详解及常用数据库对比

一、 Room介绍

image.png

二、 Room接入以及基础使用

Room引用配置

dependencies {
  def room_version = "2.2.5"

  implementation "androidx.room:room-runtime:$room_version"
  annotationProcessor "androidx.room:room-compiler:$room_version"

  // optional - RxJava support for Room
  implementation "androidx.room:room-rxjava2:$room_version"

  // optional - Guava support for Room, including Optional and ListenableFuture
  implementation "androidx.room:room-guava:$room_version"

  // optional - Test helpers
  testImplementation "androidx.room:room-testing:$room_version"

}

Room使用

第一步 创建实体类
@Entity(tableName = UserModel.USER_TABLE_NAME,
        indices = {@Index(value = {UserModel.FACE_ID}, unique = true),
                @Index(value = {UserModel.NAME}, unique = true)})
public class UserModel implements Parcelable {

    public static final String USER_TABLE_NAME = "user" ;


    public static final String NAME = "name";
    public static final String FACE_ID = "faceId";

    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = BaseColumns._ID)
    public long id;

    @NonNull
    @ColumnInfo(name = FACE_ID)
    public String faceId;

    @NonNull
    @ColumnInfo(name = NAME)
    public String name;

    public UserModel(@NonNull String faceId, @NonNull String name) {
        this.faceId = faceId;
        this.name = name;
    }
   
}
第二步 创建Dao
    @Dao
    public interface UserDao {
    
        @Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME + " WHERE "+
                UserModel.NAME + " = :name")
        LiveData<UserModel> queryByName2Lv(String name);
    
    
        @Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME + " WHERE "+
                UserModel.NAME + " = :name")
        UserModel queryByName2Model(String name);
    
    
        @Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME + " WHERE "+
                UserModel.FACE_ID + " = :faceId")
        LiveData<UserModel> queryByFaceId2Lv(String faceId);

        @Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME + " WHERE "+
                UserModel.FACE_ID + " = :faceId")
        UserModel queryByFaceId2Model(String faceId);
    
        @Query("SELECT COUNT(*) FROM " + UserModel.USER_TABLE_NAME)
        int count();
    
    
        @Query("SELECT * FROM " + UserModel.USER_TABLE_NAME)
        LiveData<List<UserModel>> queryAllByLv();
    
    
        @Query("SELECT * FROM " + UserModel.USER_TABLE_NAME)
        List<UserModel> queryAll();
    
        @Update
        public int updateUsers(List<UserModel> userModels);
    
        @Insert(onConflict = OnConflictStrategy.REPLACE)
        long insertUser(UserModel userModel);
    
        @Insert(onConflict = OnConflictStrategy.REPLACE)
        long[] insertAllUser(List<UserModel> userModels);

        @Delete
        void delete(UserModel... userModels);

        @Delete
        void deleteAll(List<UserModel> userModels);

        @Query("DELETE FROM " + UserModel.USER_TABLE_NAME + " WHERE " +
                UserModel.FACE_ID + " = :faceId")
        int deleteByFaceId(String faceId);

    }
第三步 创建Database
@Database(entities =  {
        UserModel.class
},
        version = 1, exportSchema = true)
public abstract class RoomDemoDatabase extends RoomDatabase {

    public abstract UserDao userDao();

    public static final String DATABASE_NAME = "room_demo";

    private static RoomDemoDatabase sInstance;

    public static RoomDemoDatabase getInstance(Context context) {
        if (sInstance == null) {
            synchronized (RoomDemoDatabase.class) {
                if (sInstance == null) {
                    sInstance = buildDatabase(context);
                }
            }
        }
        return sInstance;
    }


    private static RoomDemoDatabase buildDatabase(final Context appContext) {
        return Room.databaseBuilder(appContext, RoomDemoDatabase.class, DATABASE_NAME)
                .allowMainThreadQueries()
//                .openHelperFactory(new SafeHelperFactory("123456".toCharArray()))
                .addCallback(new Callback() {
                    @Override
                    public void onCreate(@NonNull SupportSQLiteDatabase db) {
                        super.onCreate(db);

                    }

                    @Override
                    public void onOpen(@NonNull SupportSQLiteDatabase db) {
                        super.onOpen(db);
                    }

                })
                .build();
    }


}

三、 Room 数据库迁移

添加新的实体类

@Entity(tableName = FaceModel.FACE_TABLE_NAME,
        foreignKeys = {
                @ForeignKey(entity = UserModel.class,
                        parentColumns = "faceId",
                        childColumns = "faceId",
                        onUpdate = ForeignKey.CASCADE,
                        onDelete = ForeignKey.CASCADE
                )
        },
        indices = {@Index(value = {"faceId"})}
)
public class FaceModel  {

    public static final String FACE_TABLE_NAME = "face";


    public static final String TYPE = "type";
    public static final String FACE_ID = "faceId";
    public static final String PATH = "path";


    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = BaseColumns._ID)
    public long id;

    @NonNull
    @ColumnInfo(name = PATH)
    public String path;

    @ColumnInfo(name = TYPE)
    public int type;

    @NonNull
    @ColumnInfo(name = FACE_ID)
    public String faceId;

    public FaceModel(@NonNull String path, int type, @NonNull String faceId) {
        this.path = path;
        this.type = type;
        this.faceId = faceId;
    }

}

配置实体类

@Database(entities =  {
    UserModel.class, FaceModel.class
        },
    version = 2, exportSchema = true)

添加Migration

static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        Log.i(TAG, "migrate: ");
        // Create the new table
          String sql = "CREATE TABLE IF NOT EXISTS face (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `path` TEXT NOT NULL, `type` INTEGER NOT NULL, `faceId` TEXT NOT NULL, FOREIGN KEY(`faceId`) REFERENCES `user`(`faceId`) ON UPDATE CASCADE ON DELETE CASCADE )";
        database.execSQL(
                sql);
        String sql2 = "CREATE INDEX IF NOT EXISTS `index_face_faceId` ON face (`faceId`)";
        database.execSQL(
                sql2);
    }
};

private static RoomDemoDatabase buildDatabase(final Context appContext) {
    return Room.databaseBuilder(appContext, RoomDemoDatabase.class, DATABASE_NAME)
            .allowMainThreadQueries()
             .addMigrations(MIGRATION_1_2)
             //.openHelperFactory(new SafeHelperFactory("123456".toCharArray()))
            .addCallback(new Callback() {
                @Override
                public void onCreate(@NonNull SupportSQLiteDatabase db) {
                    super.onCreate(db);

                }

                @Override
                public void onOpen(@NonNull SupportSQLiteDatabase db) {
                    super.onOpen(db);
                }

            })
            .build();
}

多版本升级

.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_1_4)
image

四、 Room 关联表

关联表配置
    @Entity(tableName = FaceModel.FACE_TABLE_NAME,
        foreignKeys = {
                @ForeignKey(entity = UserModel.class,
                        parentColumns = "faceId",
                        childColumns = "faceId",
                        onUpdate = ForeignKey.CASCADE,
                        onDelete = ForeignKey.CASCADE
                )
        },
        indices = {@Index(value = {"faceId"})}
    )
创建嵌套对象
    public class UserAndFaceModel {
    
        @Relation(parentColumn = "faceId", entityColumn = "faceId", entity = FaceModel.class)
        public List<FaceModel> faceModels;
    
        @Embedded
        public UserModel userModel;
    
    }
创建关联Dao
@Dao
public interface UserAndFaceDao {

    @Transaction // 保障事务
    @Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME + " WHERE "+
            UserModel.NAME + " = :name")
    LiveData<UserAndFaceModel> queryByName2Lv(String name);

    @Transaction
    @Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME + " WHERE "+
            UserModel.NAME + " = :name")
    UserAndFaceModel queryByName2Model(String name);

    @Transaction
    @Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME + " WHERE "+
            UserModel.FACE_ID + " = :faceId")
    LiveData<UserAndFaceModel> queryByFaceId2Lv(String faceId);

    @Transaction
    @Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME + " WHERE "+
            UserModel.FACE_ID + " = :faceId")
    UserAndFaceModel queryByFaceId2Model(String faceId);

    @Transaction
    @Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME )
    List<UserAndFaceModel> queryAll();

}
关联表数据插入注意
RoomDemoDatabase.getInstance(MainActivity.this.getApplicationContext()).runInTransaction(new Runnable() {
            @Override
            public void run() {
                UserModel userModel = new UserModel(1, "1", "2");
                RoomDemoDatabase.getInstance(MainActivity.this.getApplicationContext()).userDao().insertUser(userModel);
                FaceModel faceModel = new FaceModel("fa", 1, "fa");
                RoomDemoDatabase.getInstance(MainActivity.this.getApplicationContext()).faceDao().insertFace(faceModel);
            }
        });

五、 数据库数据加密

5.1 文件加密

SQLCipher
SQLCipher是一个在SQLite基础之上进行扩展的开源数据库,它主要是在SQLite的基础之上增加了数据加密功能。
Realm
Realm 介绍:
Realm 加密:

5.2 内容加密

加密算法 描述 优点 缺点
DES,3DES 对称加密算法 算法公开、计算量小、加密速度快、加密效率高 双方都使用同样密钥,安全性得不到保证
AES 对称加密算法 算法公开、计算量小、加密速度快、加密效率高 双方都使用同样密钥,安全性得不到保证
XOR 异或加密 两个变量的互换(不借助第三个变量),简单的数据加密 加密方式简单
Base64 算不上什么加密算法,只是对数据进行编码传输
SHA 非对称加密算法。安全散列算法,数字签名工具。著名的图片加载框架Glide在缓存key时就采用的此加密 破解难度高,不可逆 可以通过穷举法进行破解
RSA 非对称加密算法,最流行的公钥密码算法,使用长度可变的秘钥 不可逆,既能用于数据加密,也可以应用于数字签名 RSA非对称加密内容长度有限制,1024位key的最多只能加密127位数据
MD5 非对称加密算法。全程:Message-Digest Algorithm,翻译为消息摘要算法 不可逆,压缩性,不容易修改,容易计算 穷举法可以破解

5.3 Room数据库数据库加密

集成 swac-saferoom
添加 maven { url "https://s3.amazonaws.com/repo.commonsware.com" }
dependencies {
  implementation 'com.commonsware.cwac:saferoom:1.1.3'
}
添加openHelperFactory
    private static AppDatabase buildDatabase(final Context appContext) {
        return Room.databaseBuilder(appContext, AppDatabase.class, DATABASE_NAME)
            .allowMainThreadQueries()
            .openHelperFactory(new SafeHelperFactory("123456".toCharArray()))
            .addCallback(new Callback() {
                @Override
                public void onCreate(@NonNull SupportSQLiteDatabase db) {
                    super.onCreate(db);
                
                }

                @Override
                public void onOpen(@NonNull SupportSQLiteDatabase db) {
                    super.onOpen(db);
                }
              
            })
            .build();
    }

六、 Room与其他数据库对比

参数 Room GreenDao Realm
集成包大小 0.05M 0.05M 9.06M
插入10000条速度 551ms 806ms 195ms
查询10000条速度 126ms 71ms 4ms
删除10000条速度 3ms 6ms 5ms
更新10000条速度 622ms 838ms 242ms
image

七、 数据库调试工具分享

debug调试

使用debug-db 可以在浏览器查看表结构及数据

普通数据库
    - implementation 'com.amitshekhar.android:debug-db:1.0.6'
加密数据库
    debug {
        resValue("string", "PORT_NUMBER", "8081")
        resValue("string", "DB_PASSWORD_PERSON", "123456")
    }
    
    implementation 'com.amitshekhar.android:debug-db-encrypt:1.0.6'
上一篇下一篇

猜你喜欢

热点阅读