在 Java 中转义 MySQL 字符串...没有准备好的语句

Posted

技术标签:

【中文标题】在 Java 中转义 MySQL 字符串...没有准备好的语句【英文标题】:Escape MySQL strings in Java... without prepared statements 【发布时间】:2017-12-29 19:01:39 【问题描述】:

我正在寻找一种使用 Java 为 mysql 查询转义字符串的方法。

但是等等,在你们中的一些人直接跳到“准备好的陈述”的结论之前,我想再解释一下。

问题是,我没有 MySQL 连接。我没有直接从 Java 执行任何 MySQL 查询。我对准备好的语句了解不多,但是AFAIK,准备好的语句需要实时连接才能工作。

我想让我的代码读入一堆 CSV/XLS 文件,获取数据,然后为 MySQL 生成一个巨大的 INSERT 查询。但是这个查询现在将存储在一个文本文件中。在有人开绿灯并将这个文本文件转储到数据库之前,它不会执行。

有没有一种简单的方法可以做到这一点,而无需使用过度的框架/库?谢谢你们。

【问题讨论】:

这听起来像是一个奇怪的设置。如果您的代码不能直接访问数据库,为什么要创建 SQL 语句?更新 XML 并让代码访问数据库执行 SQL 操作难道还不够吗? @TimothyTruckle 好吧,我不是将查询转储到数据库的人。将要运行查询的人可能知道也可能不知道 Java,她也可能知道也可能不太了解编码。她可能只是简单地复制查询并在一些 GUI SQL 程序中运行查询。或者...简单地说,我的任务是从大量 CSV 中提取所有数据并将数据转换为巨大的 INSERT 查询,Java 只是我选择的自动化工具。你有更好的主意吗? Escaping SQL Strings in Java的可能重复 这意味着你的问题是一个未定义/损坏的工作流程,你必须绕过一个被设计破坏的解决方案。我会尝试向我的客户出售一个连接到数据库的附加程序,最终用户可以将 XML 文件拖放到执行 SQL 的操作。 @OHGODSPIDERS 问题是......对于 MySQL,有两种转义特殊字符的样式 - 双字符样式和斜线样式。可能我只是写一个字符串操作方法并相应地添加斜杠? 【参考方案1】:

似乎没有任何现有的库/框架可以做这样的事情。所以我猜一个简单的String 操纵器会做吗?

class xxx 

    private String escapeStringForMySQL(String s) 
        return s.replaceAll("\\", "\\\\")
                .replaceAll("\b","\\b")
                .replaceAll("\n","\\n")
                .replaceAll("\r", "\\r")
                .replaceAll("\t", "\\t")
                .replaceAll("\\x1A", "\\Z")
                .replaceAll("\\x00", "\\0")
                .replaceAll("'", "\\'")
                .replaceAll("\"", "\\\"");
    

    private String escapeWildcardsForMySQL(String s) 
        return escapeStringForMySQL(s)
                .replaceAll("%", "\\%")
                .replaceAll("_","\\_");
    


【讨论】:

replaceAll("\\", "\\\\") 抛出 java.util.regex.PatternSyntaxException: 索引 1 附近出现意外内部错误,因为 replaceAll 将参数解释为正则表达式,因此需要更多转义。这是正确的方法:replaceAll("\\\\", "\\\\\\\\") 否则,只需使用 replace("\\", "\\\\")。请参阅此处的讨论:***.com/questions/1701839/…【参考方案2】:

MySQL 可以使用指定的Special Character Escape Sequences

Escape Sequence Character Represented by Sequence
\0  An ASCII NUL (X'00') character
\'  A single quote (') character
\"  A double quote (") character
\b  A backspace character
\n  A newline (linefeed) character
\r  A carriage return character
\t  A tab character
\Z  ASCII 26 (Control+Z); see note following the table
\\  A backslash (\) character
\%  A % character; see note following the table
\_  A _ character; see note following the table

【讨论】:

非常感谢。似乎没有任何现有的库/框架可以做这样的事情。我想我必须编写自己的方法来替换这些字符。 派对迟到了,但正如 Mindas 在最近的回答中所说,OWASP's ESAPI 做到了。这是旧版本的GitHub repo,它实际上是维护的,也可以通过Maven Repo 获得。【参考方案3】:

您可以使用专为此目的而设计的OWASP's ESAPI。它有 MySQL 编解码器。

【讨论】:

【参考方案4】:

试试StringEscapeUtils.escapeSql() 这将满足您的期望。

【讨论】:

此方法似乎已在 lang 3.7 中删除 这个方法只是用双引号代替单引号,不建议【参考方案5】:

我使用了 org.apache.commons.lang3.StringEscapeUtils.escapehtml4(input);

您可以在此处查看文档 String Escape Util (Commons Lang 3.1 API)

public static final String escapeHtml4(String input) 转义 使用 HTML 实体的字符串中的字符。

例如:

“面包”和“黄油”

变成:"bread" & "butter".

支持所有已知的 HTML 4.0 实体,包括时髦的口音。笔记 常用的撇号转义字符 (') 不是 不支持法人实体等)。

参数:input - 要转义的字符串,可以为 null 返回:一个新的 转义字符串,如果为空字符串输入则为空 3.0

【讨论】:

【参考方案6】:
package io.github.sinri.Keel.test.mysql;

public class MySQLTest 
    public static void main(String[] args) 
        StringBuilder sb=new StringBuilder();
        sb.append('\0').append('\'').append('"').append('\b').append('\n').append('\t').append('\r')
                .append(Character.toChars(26)).append('\\').append('_').append('%');

        String raw=sb.toString();
        System.out.println("raw: "+raw);
        System.out.println("escapeStringForMySQL: "+escapeStringForMySQL(raw));
        System.out.println("escapeWildcardsForMySQL: "+escapeWildcardsForMySQL(raw));

    

    private static String escapeStringForMySQL(String s) 
        return s.replace("\\", "\\\\")
                .replace("\b","\\b")
                .replace("\n","\\n")
                .replace("\r", "\\r")
                .replace("\t", "\\t")
                .replace(new String(Character.toChars(26)), "\\Z")
                .replace(new String(Character.toChars(0)), "\\0")
                .replace("'", "\\'")
                .replace("\"", "\\\"");
    

    private static String escapeWildcardsForMySQL(String s) 
        return escapeStringForMySQL(s)
                .replace("%", "\\%")
                .replace("_","\\_");
    


【讨论】:

以上是关于在 Java 中转义 MySQL 字符串...没有准备好的语句的主要内容,如果未能解决你的问题,请参考以下文章

在速度模板中转义引号

在 MySQL 中转义用户输入正则表达式的最佳方法是啥?

在 PHP/MySQL 插入中转义单引号不起作用

在java中转义javascript字符串

需要在正则表达式中转义的所有特殊字符的列表

如何在 MySQL 中转义单引号