2016-04-24 48 views
-2

的值時我知道MySQLSyntaxErrorException錯誤中已經有無數條目了,但是我還沒有閱讀任何已解決我的問題的帖子,而且我真的可以使用額外的一組眼睛嘗試指出我出錯的地方。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。

+0

感謝@Andreas,我能夠解決這個問題。如果有人遇到類似的問題,我改變了String sql =「select * from Brewery where name ='」+ bName +「'」; \t \t ResultSet rs = db.runSql(sql); to String sql =「select * from Brewery where name =?;」; \t \t PreparedStatement ps = db.conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS); \t \t ps.setString(1,bName); \t \t ResultSet rs = ps.executeQuery(); – jeffkempf

+0

去除'prepareStatement()'的第二個參數。 'RETURN_GENERATED_KEYS'只能用於自動生成主鍵的'INSERT'語句,例如, 'IDENTITY','SERIAL','AUTO_INCREMENT','SEQUENCE',... – Andreas

+0

@Andreas驅動程序應該忽略選擇語句的Statement.RETURN_GENERATED_KEYS(如:它應該可以正常工作)。 –

回答

4

如果你已經知道如何使用值標記(?)一PreparedStatementINSERT聲明,爲什麼不使用一個用於SELECT說法嗎?

將以正確的方式解決您的錯誤。

+0

這工作。感謝那。現在接下來的一系列問題;) – jeffkempf

1

對這兩個查詢使用PreparedStatement,您不必擔心替換引號,並且您的選擇將與插入行爲一致。現在看來,select與剛剛插入的brewery不匹配,但插入由於重名而失敗。