【问题标题】:MySQLSyntaxErrorException when trying to insert a value containing 'MySQLSyntaxErrorException 尝试插入包含'的值时
【发布时间】:2016-04-24 22:58:13
【问题描述】:

我知道 MySQLSyntaxErrorException 错误已经有无数的条目,但我还没有阅读任何解决我问题的帖子,我真的可以用一双额外的眼睛来尝试指出我哪里出错了.

我正在创建一个简单的网络爬虫,它将维基百科页面上列出的啤酒厂名称存储到使用 WAMP 本地存储的基本 MySQL 表中。在我遇到名称中包含 ' 的啤酒厂名称之前,我现有的代码似乎工作正常。这也是我第一次使用 JSoup 进行 HTML 解析。

这是我当前的代码:

import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class Main {
public static DB db = new DB();

public static void main(String[] args) throws SQLException, IOException {
    db.runSql2("TRUNCATE Brewery;");
    processPage("myBrew");
    System.out.println("done parsing");
}


// recursive method to find brewery names by adding db entry for all <li><a>
// values on site. Might not need recursion for this.
public static void processPage(String bName) throws SQLException,
        IOException {
    // check if the given URL is already in database
    String sql = "select * from Brewery where name = '" + bName + "'";
    ResultSet rs = db.runSql(sql);
    if (rs.next()) {
        // do nothing because already exists
    } else {
        // store the brewery to database to avoid parsing again
        sql = "INSERT INTO  `Crawler`.`Brewery` " + "(`name`) VALUES "
                + "(?);";
        PreparedStatement stmt = db.conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
        stmt.setString(1, bName);
        //stmt.execute();
        stmt.executeUpdate();

        // get useful information
        //research this further to better understand what it's doing
        Document doc = Jsoup.connect("https://en.wikipedia.org/wiki/List_of_microbreweries").get();

        //case-senstive
        if (doc.text().contains("Brewery")) {
            System.out.println(bName);
        }

        // get all links and recursively call the processPage method
        Elements breweries = doc.select("a[href]");
        for (Element link : breweries) {
            //System.out.println("element class: " + link.nodeName());
            //System.out.println("parent class: " + link.parent().nodeName());
            System.out.println("element title: " + link.attr("title"));

            //assumes that all brewery names will be listed in <li><a> html format
            if (link.nodeName() == "a" && link.parent().nodeName() == "li") {
                System.out.println("recursive call tripped");
                String tmp = link.attr("title");
                //String first = tmp.charAt(0) + "";
                if(tmp.contains("'")){
                    String brew = tmp.replaceAll("'", "\\\'");
                    /*System.out.println("new string: '" + brew +"'");
                    processPage("'" + brew + "'");*/
                    System.out.println("new string: " + brew);
                    processPage(brew);
                }
                else {
                    if (tmp.contains(" (page does not exist)")) {
                        String brew = tmp.replaceAll(" (page does not exist)", "");
                        System.out.println("shortened string: " + brew);
                        processPage(brew);
                    }
                    else {
                        //no ' exists in the name
                        processPage(tmp);
                    }
                }

            }
        }
    }
}
}

使用此语法时,我收到以下错误:

Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 's All Natural Brewing Company'' at line 1
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
at com.mysql.jdbc.Util.getInstance(Util.java:387)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:939)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3878)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3814)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2478)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2625)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2547)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2505)
at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1370)
at DB.runSql(DB.java:26)
at Main.processPage(Main.java:57)
at Main.processPage(Main.java:95)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:101)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:101)
at Main.processPage(Main.java:101)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:101)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:101)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.main(Main.java:17)

使用此代码,包含 ' 的啤酒厂名称不会存储在我的 MySQL 表中。但是,如果我替换以下行

String brew = tmp.replaceAll("'", "\\\'");

String brew = tmp.replaceAll("'", "\\\\'");

然后啤酒厂名称确实存储到我的 MySQL 表中,并且在下一个啤酒厂名称被刮掉之前我收到以下错误:

Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'Beau\'s All Natural Brewing Company' for key 'brewery_name'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
at com.mysql.jdbc.Util.getInstance(Util.java:387)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:932)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3878)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3814)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2478)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2625)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2551)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1861)
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2073)
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2009)
at com.mysql.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:5094)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1994)
at Main.processPage(Main.java:67)
at Main.processPage(Main.java:95)
at Main.processPage(Main.java:95)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:101)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:101)
at Main.processPage(Main.java:101)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:101)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:101)
at Main.processPage(Main.java:105)
at Main.processPage(Main.java:105)
at Main.main(Main.java:17)

使用

String brew = tmp.replaceAll("'", "''"); 

而不是

String brew = tmp.replaceAll("'", "\\\\'"); 

导致同样的问题。

我的 DB 类中的 runSql 方法:

public ResultSet runSql(String sql) throws SQLException {
    Statement sta = conn.createStatement();
    return sta.executeQuery(sql);
}

如果有人有任何想法,请告诉我。我花了几个小时尝试不同的转义字符变体等,但我找不到任何东西来解决这个问题。另一双看着我的代码的眼睛可能正是我所需要的。提前感谢您的帮助。

编辑: 我目前没有使用 Spring 或 Hibernate。

【问题讨论】:

  • 感谢@Andreas,我能够解决这个问题。如果有人遇到类似的问题,我更改了 String sql = "select * from Brewery where name = '" + bName + "'"; ResultSet rs = db.runSql(sql);to String sql = "select * from Brewery where name = ?;"; PreparedStatement ps = db.conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); ps.setString(1, bName);结果集 rs = ps.executeQuery();
  • 删除prepareStatement()的第二个参数。 RETURN_GENERATED_KEYS 只能用于自动生成主键的 INSERT 语句,例如IDENTITY, SERIAL, AUTO_INCREMENT, SEQUENCE, ....
  • @Andreas Drivers 应该忽略 Statement.RETURN_GENERATED_KEYS 的 select 语句(如:它应该可以工作)。
  • @MarkRotteveel 实际上,驱动程序需要忽略它 (This parameter is ignored if the SQL statement is not an INSERT statement)。但是,我没有说你不能指定它,我说你不应该这样做。它没用;它会误导代码的任何读者。
  • @Andreas 对不起,我不精确地使用 should 而不是 must ;)

标签: java mysql jdbc jsoup


【解决方案1】:

如果您已经知道如何在 INSERT 语句中使用带有值标记 (?) 的 PreparedStatement,那么为什么不在 SELECT 语句中也使用一个呢?

会以正确的方式修正你的错误。

【讨论】:

  • 那行得通。感谢那。现在是下一系列问题;)
【解决方案2】:

对两个查询都使用 PreparedStatement,您不必担心替换引号,并且您的选择将与您的插入保持一致。现在看来select和刚才插入的啤酒厂不匹配,但是插入失败,因为名字重。

【讨论】:

    猜你喜欢
    • 2011-05-07
    • 1970-01-01
    • 2013-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多