使用Spring Batch JdbcBatchItemWriter进行行插入的COMPRESS(Transact-SQL)

时间:2017-05-26 23:50:31

标签: sql-server spring spring-batch spring-jdbc

根据https://docs.microsoft.com/en-us/sql/t-sql/functions/compress-transact-sql,应该能够在表插入期间压缩数据。他们甚至提供了一个示例(如下所示),当您从DB客户端(例如,DBVis)运行查询时,它可以正常工作:

    INSERT INTO player (info )  
    VALUES (COMPRESS(N'{"sport":"Tennis","age": 28,"rank":1,"points":15258, turn":17}'));

我尝试做的是使用Spring Batch的JdbcBatchItemWriter的setSql方法插入/压缩字符串(在以下示例中为字符串payload_compressed)。

    JdbcBatchItemWriter<Consol> itemWriter = new JdbcBatchItemWriter<>();
    itemWriter.setSql("INSERT INTO foo (payload_compressed) VALUES (:payload_compressed)");
但是他们一直在悲惨地失败。

我只需要以某种方式修改预备语句,以便我可以编写类似于此的内容:

    itemWriter.setSql("INSERT INTO foo (payload_compressed) VALUES (COMPRESS(N':payload_compressed'))");

我甚至尝试将 payload_compressed 字段设置为byte []并使用GZIP(假设是用于COMPRESS()函数的SQL服务器)将其压缩,然后将其插入到DB中。它&#34;工作&#34;很好的一个问题,我无法使用SQL Server的DECOMPRESS()函数从数据库中提取和读取数据 - 即,我希望能够直接从数据库客户端查询压缩数据使用DECOMPRESS()函数。

我们将非常感谢任何意见/建议。

**更新**

工作解决方案 - 在Java中压缩/解压缩String而不使用SQL Server的COMPRESS()/ DECOMPRESS() - 如下所示:

压缩/解压缩数据(https://gist.github.com/yfnick/227e0c12957a329ad138):

public class Gzip {

public static byte[] compress(String data) throws IOException {
    ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length());
    GZIPOutputStream gzip = new GZIPOutputStream(bos);
    gzip.write(data.getBytes());
    gzip.close();
    byte[] compressed = bos.toByteArray();
    bos.close();
    return compressed;
}

public static String decompress(byte[] compressed) throws IOException {
    ByteArrayInputStream bis = new ByteArrayInputStream(compressed);
    GZIPInputStream gis = new GZIPInputStream(bis);
    BufferedReader br = new BufferedReader(new InputStreamReader(gis, "UTF-8"));
    StringBuilder sb = new StringBuilder();
    String line;
    while((line = br.readLine()) != null) {
        sb.append(line);
    }
    br.close();
    gis.close();
    bis.close();
    return sb.toString();
}

}

然后是插入片段(一个非常粗略的例子):

public class Consol {
private byte[] payload_compressed;
..
}

 String payload = "{\"sport\":\"Tennis\",\"age\": 28,\"rank\":1,\"points\":15258, turn\":17}";

payload_compressed = Gzip.compress(payload)

JdbcBatchItemWriter<Consol> itemWriter = new JdbcBatchItemWriter<>();
itemWriter.setSql("INSERT INTO consol (payload_compressed) VALUES (:payload_compressed)");

在SQL Server端,&#34; payload_compressed&#34;列设置如下:

payload_compressed VARBINARY(5000) NOT NULL

如果我然后读回数据并使用Gzip.decompress()util解压缩它,那就很好了。但是,如果我尝试使用数据库客户端中的qry直接解压缩字段(DbViz,SQL Server Mgt Studio ...) - 仅作为示例:

select cast(decompress([payload_compressed]) as nvarchar(max)) as "payload_decompressed"
from dbo.consol

我得到一个解压缩的CLOB,但它都是乱码。

话虽这么说,如果我尝试读取使用SQL Server的COMPRESS()函数使用Gzip.decompress()方法压缩的其他字段,它实际上会返回正确的字符串,这可能表明GZIP算法是一样的;虽然在解压缩之后所有单个字符之间还有其他空格,所以我不确定是因为字符集还是其他原因...例如,{&#34; name&#34;:&#34; Paul&#34 ;(使用SQL Server COMPRESS()压缩)将返回{&#34; n a m e&#34; :&#34; P a u l&#34; (使用Gzip util解压缩)。

无论如何,尽管这是一个可行的解决方案,但最终意味着没有人可以直接从客户端查询数据库表,每个人都需要通过Java和GzipUtil,这不一定是理想的。

0 个答案:

没有答案