5

我使用 PostgreSQL 作为我的数据库和 java servlet 与 PostgreSQL 通信。我的应用程序要求我从数据库中获取数据以获取匹配的输入文件。所有文件都存储在数据库中的 bytea 列中。这是我的代码:

String checkdb="select * from key where certificate = '"+c+"';";
Statement stcheck=conn.createStatement(
    ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
ResultSet newrs=stcheck.executeQuery(checkdb);
newrs.last();
int rowcount=newrs.getRow();
if(rowcount!=0)
throw new ArithmeticException();

其中certificate是包含 bytea 数据的列的名称,c(上传的)是byte[]表单中的证书。所以在这里我检查上传的证书是否已经存在于数据库中。如果它存在,那么我将抛出异常。

但问题是多次上传同一个证书并没有抛出异常,就好像两个证书不同一样。

我是否正确比较了字节值。我应该怎么做才能纠正这个?
编辑
我尝试将证书列设置为主键。但是证书仍然被插入到数据库中。这怎么可能发生?由于某种原因,内部比较也失败了。
编辑
我尝试检索一个文件并将其转换为字符串:

InputStream input13 = retrs.getBinaryStream("certificate");
       ByteArrayOutputStream output13 = new ByteArrayOutputStream();
         byte buf[]=new byte[1024];
            int len;
    IOUtils.copy(input13, output13);
    input13.close();
    byte[] retvalue=output13.toByteArray();
    String s1=new String(retvalue);

String s2=new String(c);
System.out.println("in--------------"+s2);


System.out.println("out----------------"+s1);


retrs 是包含刚刚存储的证书的结果集。c 是 byte[] 中的输入证书。我得到的输出是:

19:05:43,156 INFO  [STDOUT] in-------------------BEGIN CERTIFICATE-----
MIICIjCCAYsCAQMwDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCYXMxCzAJBgNV
BAgMAmFzMQswCQYDVQQHDAJhczELMAkGA1UECgwCYXMxCzAJBgNVBAsMAmFzMQsw
CQYDVQQDDAJjYTERMA8GCSqGSIb3DQEJARYCYXMwHhcNMTIwNDEwMDY0ODQ3WhcN
MTMwNDEwMDY0ODQ3WjBSMQswCQYDVQQGEwJhczELMAkGA1UECBMCYXMxCzAJBgNV
BAcTAmFzMQswCQYDVQQKEwJhczELMAkGA1UECxMCYXMxDzANBgNVBAMTBmNsaWVu
dDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsfJq9TVgTLqz84nuWpDm+dvI
do2HIWoHkmEPNowK4xn1+qWUPCy30aASWI92YMtE6njtQGyZBYij0iTAxldDktqd
bMdpKAONDlSv71rn+fZPuyenbBFYZexybNVsRMFzTD/F/hiPPXT7E1j9CrgIMxVz
ScZeNATh/dPLwuNQ0dsCAwEAATANBgkqhkiG9w0BAQUFAAOBgQDDUyeIWlKaMMkM
8VRGuDJyKFC8miQfmul6zE4+6RTswHKjcUoje2vhTQgV+GBfqx8ai+ziujx8CeyR
eJWcb1G8gg+LMUNDcTOlXTeBG9L2c/gMOEu7BEjtpojSYmFyEvJEQ5Yep44HKZZb
FSPFVNxGiXBhNxtKQdAu6/smQ/eBNg==
-----END CERTIFICATE-----
19:05:43,156 INFO  [STDOUT] out----------------[B@17f8b39


是我的检索方式错误。因为[B@17f8b39看起来像一个内存位置或类似的东西。
答案
正如@jarnbjo 所说,必须牢记一件事。当您在 postgressql 中使用字节数组时,是否retieving or inserting仅使用setBytes().Else 仅插入 byte[] 的内存位置(java 中的哈希码)。

4

3 回答 3

1

显然,您没有根据所看到的结果正确地进行比较。您需要进行一些调试以找出问题所在。我建议按照以下方式进行简单的测试:

  • 从一个干净的数据库开始
  • 从客户端获取证书
  • 将其插入数据库
  • 立即再次读回(它应该是唯一的) - 将您插入的数据与您读回的数据进行比较。他们应该是一样的。如果它们不相同,请找出原因
  • 一旦可行,扩展测试用例以运行与您问题中的查询类似的查询。如果返回零记录,找出原因。

在弄清楚为什么存在差异方面,您可能会发现从一个简单的测试用例开始会有所帮助,在该测试用例中插入一个简单的字节数组 - 例如由单个字节组成的数组。

于 2012-05-07T12:12:05.760 回答
1

使用 PreparedStatement:

PreparedStatement pstat = conn.prepareStatement(
      "select * from key where certificate = ?");
pstat.setBytes(1, c);
ResultSet newrs = pstat.executeQuery();

当然,您在插入数据时也应该这样做。

于 2012-05-07T12:05:38.170 回答
1

我建议您生成文件的校验和并存储在数据库中,并根据校验和而不是文件的字节检查文件内容

table key{
    id int,
    certificate blob,
    checksum varchar(32)
}

并使用以下方法生成校验和byte[] buffer

public String getCheckSum(byte[] buffer) {
    StringBuilder builder = new StringBuilder();
    try {
        MessageDigest complete;
        complete = MessageDigest.getInstance("MD5");
        byte[] rawCheckSum = complete.digest(buffer);
        for(byte b: rawCheckSum) {
            builder.append(Integer.toString( ( b & 0xff ) + 0x100, 16).substring( 1 ));
        }
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    }
    return builder.toString();
}

最后,

String checkdb="select * from key where checksum = '" + getCheckSum(c) + "';";

编辑:

将字节插入数据库时​​,您应该使用:

String query = "INSERT INTO key (certificate) VALUES (?)";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setBytes(1, c);

代替

String query = "INSERT INTO key (certificate) VALUES ('" + c + "')";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.execute();
于 2012-05-07T13:16:08.057 回答