在 Android 上使用 Room 使用 UUID 作为主键

lcj*_*lcj 7 android android-room

我需要将我的 Android 移动应用程序与云中的多租户数据库同步。我认为最好的方法是使用 UUID 作为我的表的主键。我刚开始使用 Room 并想知道我在哪里/如何做到这一点,并正在寻找 1) 关于使用 UUID 作为与 Room 的 PK 的意见和 2) 我将在何处实现这一点(在初始化 id 列的模型中,因为这是使用@NonNull 的唯一方法)?

更新

我使用了 INT,但我不相信这是正确的方法。我在 android 开发者网站上看到了一个例子,它显示了正在使用的 uuid。当然会帮助我的云同步例程,但以速度和空间为代价。我正在考虑一种混合方法,其中 INT 用于 PK,而 UUID 作为附加字段。这样我就不必为 FK 复制每个 UUID。我做了一些建模,看起来混合方法将是完整 UUID 方法大小的 50%(INT 只有 25%)。

有没有人在同样的问题上挣扎过?您是否选择了一个方向(UUID、INT 或混合)并且您对此感到后悔还是做得很好?

zz-*_*z-m 4

  1. 您必须使用 UUID 而不是 int 作为主键有几个原因。例如,您的应用程序是一个分布式应用程序,就像许多人使用许多设备编辑一个文档一样,您将记录每个人的编辑日志以用于版本控制功能。如果您的应用程序是集中式的(大多数情况),最好使用 int,或者从服务器请求主键(可以是 int、long 或其他)。如果必须使用 UUID,那就使用它。否则 int 或 long 是更好的选择。

  2. 最后我将附上一个使用 UUID 作为 android Room 主键的示例。

  3. UUID存储空间和计算速度不应该是首要考虑的,除非你遇到过这些问题(不需要过度优化)。例如:一张图片的存储空间可能约为1MB,UUID以String的形式保存在数据库中,采用utf-8格式,最大为144 Byte(int为4 Byte),约为1/7000的一张图片。在服务器端,不建议使用UUID作为主键,因为服务器同时服务上万个用户,同时有很多查询。虽然手机CPU远弱于服务器CPU,但它一次只能服务一个用户。再次强调,在必须使用UUID的场景下,不需要提前考虑优化问题。

书本类

@Entity(tableName = "books")
public class Book{
@PrimaryKey
@NonNull
private UUID id;
private String title;
private Date date;

public Book() {
    this.id = UUID.randomUUID();
    date = new Date();
}

public UUID getId() {
    return id;
}

public void setId(UUID id) {
    this.id = id;
}

public String getTitle() {
    return title;
}

public void setTitle(String title) {
    this.title = title;
}

public Date getDate() {
    return date;
}

public void setDate(Date date) {
    this.date = date;
}

}
Run Code Online (Sandbox Code Playgroud)

应用程序数据库.类

@Database(entities = {Book.class}, version = 1, exportSchema = false)
@TypeConverters({UUIDConverter.class, DateConverter.class})
public abstract class AppDatabase extends RoomDatabase {
    private static AppDatabase INSTANCE;
    private static final String DATABASE_NAME = "BookDatabase";

    public abstract BookDao bookDao();

    public static void init(Context context) {
        if (INSTANCE == null) {
            INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME).build();
        }
    }

    public static AppDatabase getINSTANCE() {
        if (INSTANCE == null) throw new IllegalStateException("init in MyApplication.class");
        return INSTANCE;
    }
}
Run Code Online (Sandbox Code Playgroud)

转换器:转换器将 uuid 或 sqlite 不支持的其他格式转换为支持类型。编辑:从版本 2.4.0-alpha05开始,存在 UUID 的默认转换器,它使用字节数组而不是字符串。链接更改可以方便迁移。

public class UUIDConverter {

    @TypeConverter
    public static String fromUUID(UUID uuid) {
        return uuid.toString();
    }

    @TypeConverter
    public static UUID uuidFromString(String string) {
        return UUID.fromString(string);
    }
}

public class DateConverter {

    @TypeConverter
    public static long timestampFromDate(Date date) {
        return date.getTime();
    }

    @TypeConverter
    public static Date dateFromTimestamp(long timestamp) {
        return new Date(timestamp);
    }
}
Run Code Online (Sandbox Code Playgroud)