将 MD5 存储在 MySQL 中

Storing MD5 in MySQL

我不想将 MD5 hash 存储在 32 字节的字段中,而是将其存储在 16 字节的二进制字段中。 Mysql 字段“TEMP_MD5”定义为 Binary(16)。

带有示例行插入的 MySQL CREATE TABLE 是:

CREATE TABLE `mytable` (
    `TEMP_MD5` binary(16) DEFAULT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO mytable (TEMP_MD5) VALUES UNHEX("202cb962ac59075b964b07152d234b70") );

示例代码:

假设在MySQL字段中存储了16字节的二进制字段TEMP_MD5,我检索后如何在Delphi代码中比较这个16字节的字段值?

是否可以跳过MySQLHEX/UNHEX内部函数,直接用Delphi代码比较[=44中的16字节二进制字段(32字节字符串) =]?

例如:

FDQuery1.Open( 'SELECT TEMP_MD5 from mytable;' );

if THashMD5.GetHashBytes('123') = fDQuery1.FieldByName('TEMP_MD5').VALUE then
  SHOWMESSAGE('MATCHED!');

但是,FieldByName('TEMP_MD5').value 的值似乎与 THashMD5.GetHashString('123') 的值

不匹配

另一种使用SELECT语句进行比较的方法也失败了

FDQuery1.Open( 'SELECT TEMP_MD5 mytable ' +
                        'WHERE (TEMP_MD5=:myvalue)',
                               [THashMD5.GetHashBytes('123')] );

以上也未能给出FDQuery1.RecordCount = 1.

基本上我试图将我存储在 MySQL 中的 16 字节二进制文件与一个值进行比较,假设代码中的“123”是否匹配。

我正在使用 Delphi 10.2,明年将升级到 10.4。

下面是一个代码示例,展示了如何将 MD5 写入数据库以及如何读回它并与给定的 MD5 哈希进行比较:

正在插入数据:

procedure TForm1.InsertDataButtonClick(Sender: TObject);
var
    MD5    : TArray<Byte>;
begin
    MD5 := THashMD5.GetHashBytes('123');
    FDConnection1.Connected := TRUE;
    FDQuery1.SQL.Text := 'INSERT INTO mytable (TEMP_MD5) VALUES(:MD5)';
    FDQuery1.ParamByName('MD5').SetBlobRawData(Length(MD5), PByte(MD5));
    FDQuery1.ExecSQL;
    Memo1.Lines.Add('Rows affected = ' + FDQuery1.RowsAffected.ToString);
end;

正在读回数据并与给定的哈希值进行比较:

procedure TForm1.ReadDataButtonClick(Sender: TObject);
var
    MD5      : TArray<Byte>;
    MD5_123  : TArray<Byte>;
    FieldMD5 : TField;
    RecCnt   : Integer;
begin
    MD5_123 := THashMD5.GetHashBytes('123');

    FDConnection1.Connected := TRUE;
    // First version: get all records
    // FDQuery1.SQL.Text := 'SELECT TEMP_MD5 FROM mytable';
    // Second version: Get only records where TEMP_MD5 is hash('123').
    FDQuery1.SQL.Text := 'SELECT TEMP_MD5 FROM mytable WHERE TEMP_MD5 = :MD5';
    FDQuery1.ParamByName('MD5').SetBlobRawData(Length(MD5_123), PByte(MD5_123));
    // Execute the query
    FDQuery1.Open;
    RecCnt := 0;
    while not FDQuery1.Eof do begin
        Inc(RecCnt);
        FieldMD5 := FDQuery1.FieldByName('TEMP_MD5');
        SetLength(MD5, FieldMD5.DataSize);
        FieldMD5.GetData(MD5);
        if (Length(MD5) = Length(MD5_123)) and
           (CompareMem(PByte(MD5), PByte(MD5_123), Length(MD5))) then
            Memo1.Lines.Add(RecCnt.ToString + ') MD5(123) = ' + MD5ToStr(MD5))
        else
            Memo1.Lines.Add(RecCnt.ToString + ') ' + MD5ToStr(MD5));
        FDQuery1.Next;
    end;
end;

正如您在阅读代码时看到的那样,我通过比较包含值(字节数组)的内存,将来自数据库的 MD5 与给定的 MD5 进行比较。

效用函数:

function MD5ToStr(MD5 : TArray<Byte>) : String;
var
    B      : Byte;
begin
    Result := '';
    for B in MD5 do
        Result := Result + B.ToHexString(2);
end;