【问题标题】:Comparing byte[] in android room Daos比较 android room Daos 中的 byte[]
【发布时间】:2021-06-12 20:01:11
【问题描述】:

在我的项目中,有一个登录系统,其中用户名、电子邮件和密码存储在 android room 的 sqlite 数据库中。它们都通过 android Chiper 算法进行哈希处理,然后通过类型转换器转换为 String 到数据库。但我无法将它们与以下语句进行比较,它只会返回 null...

那么我如何正确比较那些字节[]?还是应该这样工作而我的错误在其他地方?

@Query("select passwordHashed from login where userHashed = :userHashGiven")
byte[] getPasswordHashByUserHash(userHashGiven byte[])

我的 TypeConverter 和 Login 对象如下所示:

@TypeConverter
fun stringToBytes(s: String) : ByteArray {
    return s.toByteArray(EncrypterUtil.charset)
}

@TypeConverter
fun bytesToString(bytes: ByteArray) : String {
    return String(bytes, EncrypterUtil.charset)
}
@Entity(tableName = "login")
public class Login {

@NonNull
@PrimaryKey
private byte[] userHashed;

@ColumnInfo
private byte[] emailHashed;

@ColumnInfo
private byte[] passwordHashed;

@ColumnInfo
private int biometric;

public Login(@NotNull byte[] userHashed, byte[] emailHashed, byte[] passwordHashed, int biometric) {
    this.userHashed = userHashed;
    this.emailHashed = emailHashed;
    this.passwordHashed = passwordHashed;
    this.biometric = biometric;
}

@NonNull
public byte[] getUserHashed() {
    return userHashed;
}

public void setUserHashed(@NonNull byte[] userHashed) {
    this.userHashed = userHashed;
}

public byte[] getEmailHashed() {
    return emailHashed;
}

public void setEmailHashed(byte[] emailHashed) {
    this.emailHashed = emailHashed;
}

public byte[] getPasswordHashed() {
    return passwordHashed;
}

public void setPasswordHashed(byte[] passwordHashed) {
    this.passwordHashed = passwordHashed;
}

public int getBiometric() {
    return biometric;
}

public void setBiometric(int biometric) {
    this.biometric = biometric;
}

数据库中的结果如下:

【问题讨论】:

    标签: android arrays database sqlite android-room


    【解决方案1】:

    根据您显示的Login类(实体)。

    @Query 不正确,因为它使用了 passwordHashuserHash 列,而实体具有名为 passwordHasheduserHashed 的相应列。

    • 应该改为@Query("select passwordHashed from login where userHashed = :userHashGiven")

    • 由于您混合使用了 Java 和 Kotlin,因此您可能无意中将要从中提取数据的表与要插入数据的表混淆了。

    关于比较 BLOB,SQLite 使用内存比较,因此比较应该有效。例如,考虑以下内容:-

    DROP TABLE IF EXISTS login;
    CREATE TABLE IF NOT EXISTS login (userHashed BLOB);
    INSERT INTO login VALUES
        (x'B1C1D1E1F1'),
        (x'F1E1D1C1B1'),
        (x'0101010101'),
        (x'FFEEDDCCBB')
    ;
    SELECT userHashed, hex(userHashed) FROM login WHERE userHashed = x'B1C1D1E1F1';
    

    这个

    1. 如果存在login 表,则删除它,
    2. 创建登录表(只有一个 BLOB 列),
    3. 插入 4 行,所有的 BLOB 值都不同,最后
    4. 提取行(应仅是与参数匹配的行)

    运行上述返回预期结果:-

    • 请注意,Navicat 用于上述情况,这就是它显示 BLOBS 的方式,因此为什么使用 SQLite 十六进制函数将值显示为字符串表示,从而确认已返回预期的行.

    示例

    根据您提供的更正(查询)代码确实有效

    假设 Dao 是调用 AllDao 那么下面的 MainActivity 被用来测试代码。

    请注意,还添加了以下@Query:-

    @Query("SELECT * FROM login WHERE userHashed = :userHashGiven")
        Login[] getLoginsByUserHash(byte[] userHashGiven);
    
    • 这会提取一个登录对象而不是一个字节[]

    使用的代码是:-

    public class MainActivity extends AppCompatActivity {
    
        Database db;
        AllDao allDao;
        byte[] t1 = new byte[]{0,1,2,3,4,5,6,7,8,9},
            t2 = new byte[]{10,11,12,13,14,15,16,17,18,19},
            t3 = new byte[]{20,21,22,23,24,25,26,27,28,29},
            t4 = new byte[]{30,31,32,33,34,35,36,37,38,39}
        ;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            db = Room.databaseBuilder(this,Database.class,"mydb")
                    .allowMainThreadQueries()
                    .build();
            allDao = db.allDao();
            Login l1 = new Login(t1,t2,t3,10);
            Login l2 = new Login(t2,t3,t4,20);
            Login l3 = new Login(t3,t4,t1,30);
            Login l4 = new Login(t4,t1,t2,40);
            allDao.insertLogin(l1);
            allDao.insertLogin(l2);
            allDao.insertLogin(l3);
            allDao.insertLogin(l4);
            Login[] extractedLogins = allDao.getLoginsByUserHash(t2);
            Log.d("LOGINTEST","Extracted " + extractedLogins.length +  " rows");
            byte[] passwordHash = allDao.getPasswordHashByUserHash(t2);
            Log.d("LOGINTEST","Extracted " + passwordHash.length +  " rows");
            Log.d("LOGINTEST",passwordHash.toString());
        }
    }
    

    如您所见,这会使用一些预定义的字节 [] 根据 t1 - t4 向登录表添加 4 行(对于 4 行,userHashed 分别为 t1-t4)。

    插入数据后,使用新查询提取登录数组,该查询应根据 WHERE 子句仅检索 1 个登录。

    然后使用原始查询提取字节[]。

    当在带有断点的调试模式下运行时,Log.d("LOGINTEST",passwordHash.toString());

    可以看到如下结果。

    日志包括:-

    D/LOGINTEST:提取 1 行 D/LOGINTEST:提取 10 行

    • 即第一个(新)查询已提取 1 个登录对象,第二个(原始)查询已返回 10 个字节长的 byte[]。

    调试屏幕显示(如预期):-

    extractedLoginsLogin 对象数组)有 1 个对象,passwordHashed 值为 t4(第 2 行的第 3 个值)

    而且提取的 byte[] 是 t4(再次符合预期)。

    还是应该这样工作而我的错误在其他地方?

    我相信您的问题在其他地方(因为工作示例向您展示了查询有效)。

    【讨论】:

    • 我很抱歉错误的查询,它是我直接写到stackOverflow中的,而其余的被复制了......现在正在编辑
    • @CaipiDE 我添加了一个工作测试示例,显示您的查询工作(尽管它使用简化的数据)
    • 我重建了系统......现在它在你的帮助下工作了,谢谢......我仍然想知道错误来自哪里......
    猜你喜欢
    • 1970-01-01
    • 2015-03-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-28
    • 1970-01-01
    • 2018-12-21
    • 2020-05-06
    • 2012-03-18
    相关资源
    最近更新 更多