Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

blob处理有有缺陷 #1192

Closed
gqwei opened this issue Nov 3, 2016 · 11 comments
Closed

blob处理有有缺陷 #1192

gqwei opened this issue Nov 3, 2016 · 11 comments

Comments

@gqwei
Copy link

gqwei commented Nov 3, 2016

在存储blob数据的时候,mycat先将byte[]转行为utf8 string,然后再转换为byte[],如果blob中存在特殊字符,如byte=-119,转行为string,然后再转换为byte的时候,byte的字节长度为3了。
byte[] data = new byte[]{-119};
String s = new String(data,"utf-8");
System.out.println(s);
byte[] ndata = s.getBytes("utf-8");
System.out.println("weird:"+data.length+" : "+ndata.length);
String s1 = new String(ndata,"utf-8");
System.out.println(s1);
这样导致存储到数据库中的数据库错误。读出来也是错误的。

@ZzzCrazyPig
Copy link
Contributor

可以提供完整的复现场景?

@gqwei
Copy link
Author

gqwei commented Nov 3, 2016

很容易的。建立一个table,有一列是blob,存储一个png图像。然后就可以重现了。
@test
public void testWrite() throws InstantiationException, IllegalAccessException, ClassNotFoundException, IOException {
Class.forName("com.mysql.jdbc.Driver").newInstance();
try {
Connection conn = getMysqlConn();
String template = new String();
template = "SELECT * FROM act_ge_bytearray WHERE ID_ = ?";
PreparedStatement pstmt = conn.prepareStatement(template);
//pstmt.setString(1, "bd12df4f-9fe0-11e6-851e-0242b88ae6c1");
pstmt.setString(1, "bd12df4f-9fe0-11e6-851e-0242b88ae6c1");
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
Blob blob = rs.getBlob("BYTES_");
inspect(blob);
Connection conn2 = getMysqlConn();
writeback(blob,conn2);
Connection conn1 = getMycatConn();
writeback(blob,conn1);
}
rs.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}

private Connection getMysqlConn() throws SQLException {
    String jdbcURL = "jdbc:mysql://10.74.156.168:3306/eflow";
    Connection conn = null;
    String user = "yyyy";
    String passwd = "yyyyy";
    conn = DriverManager.getConnection(jdbcURL, user, passwd);
    return conn;
}

private Connection getMycatConn() throws SQLException {
    String jdbcURL = "jdbc:mysql://10.74.214.31:4306/EFLOW";
    Connection conn = null;
    String user = "xxxx";
    String passwd = "xxxxx";
    conn = DriverManager.getConnection(jdbcURL, user, passwd);
    return conn;
}

private static int count=0;

private void writeback(Blob blob,Connection conn) {
    try {
        // InputStream fis = new FileInputStream(infile);
        PreparedStatement pstmt = conn.prepareStatement("insert into act_ge_bytearray(ID_,BYTES_) values(?,?)");
        pstmt.setString(1, "test"+count++); // 把传过来的第一个参数设为文件名
        // pstmt.setBinaryStream(2,fis,(int)file.length());
        // //这种方法原理上会丢数据,因为file.length()返回的是long型
        pstmt.setBinaryStream(2, blob.getBinaryStream(), blob.length()); // 第二个参数为文件的内容
        pstmt.executeUpdate();

        pstmt.close();
        conn.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

private byte[] inspect(Blob blob) throws SQLException, IOException {
    System.out.println(blob.toString());
    long len = blob.length();
    byte[] data = blob.getBytes((long) 1, (int) len);
    FileOutputStream fos = new FileOutputStream("test.png");
    fos.write(data);
    fos.close();
    return data;
}

@magicdoom
Copy link
Contributor

用X'十六进制' 这种形式可以 或者使用1.6的server端预编译

@gqwei
Copy link
Author

gqwei commented Nov 3, 2016

预编译怎么处理?能否详细告知一下。
这个代码主要是第三方软件activiti的代码,不好修改成16进制或者改变结构。
有没有更好的解决办法?完全的兼容jdbc,而不需要应用层修改?

@ZzzCrazyPig
Copy link
Contributor

mysql预编译参考 http://blog.csdn.net/axman/article/details/6913527

@gqwei
Copy link
Author

gqwei commented Nov 4, 2016

谢谢楼上各位。
这些解决方案都还是应用层进行规避解决。
能否考虑在mycat解决,如将_binary''的内容进行特殊处理掉?

@magicdoom
Copy link
Contributor

希望能有志愿者来实现

@magicdoom
Copy link
Contributor

预编译只是一个全局的开关 开启即可 比如jdbc'就是url里加个参数

@btfak
Copy link

btfak commented May 6, 2018

这个问题也可以把 blob 使用 base64 编码一下再存储,就可以绕开这个 bug

@939598604
Copy link

预编译怎么处理?能否详细告知一下。
这个代码主要是第三方软件activiti的代码,不好修改成16进制或者改变结构。
有没有更好的解决办法?完全的兼容jdbc,而不需要应用层修改?

您好,请问一下,activiti和mycat出现的Blob问题,您解决了吗?解决的话,求指教~~~

@mindfn
Copy link

mindfn commented Mar 25, 2021

预编译怎么处理?能否详细告知一下。
这个代码主要是第三方软件activiti的代码,不好修改成16进制或者改变结构。
有没有更好的解决办法?完全的兼容jdbc,而不需要应用层修改?

您好,请问一下,activiti和mycat出现的Blob问题,您解决了吗?解决的话,求指教~~~

JDBCURL中增加 useServerPrepStmts=true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants