您好我在执行以下功能时遇到了问题而没有遇到以下异常。我不确定为什么会这样。我认为它可能与引号有关。如果重要,我正在使用德比数据库。
java.sql.SQLSyntaxErrorException
这是我尝试执行的以下代码:
public void addAlbum(Album album) throws IOException, SQLException {
Properties props = new Properties();
FileInputStream in = new FileInputStream("database.properties");
props.load(in);
in.close();
props.getProperty("jdbc.drivers");
String url = props.getProperty("jdbc.url");
String username = props.getProperty("jdbc.username");
String password = props.getProperty("jdbc.password");
Connection connection = DriverManager.getConnection(url, username, password);
Statement statement = connection.createStatement();
String sql = null;
if(album instanceof CDAlbum) {
CDAlbum cdAlbum = (CDAlbum)album;
sql = "INSERT INTO MyAlbums VALUES ('CD', '" + cdAlbum.getTitle() + "', '" + cdAlbum.getGenre() + "','" + cdAlbum.getArtist() + "', '" + cdAlbum.getTracks() + "');";
}
if(album instanceof DVDAlbum) {
DVDAlbum dvdAlbum = (DVDAlbum)album;
sql = "INSERT INTO MyAlbums VALUES ('DVD', '" + dvdAlbum.getTitle() + "', '" + dvdAlbum.getGenre() + "','" + dvdAlbum.getDirector() + "', '" + dvdAlbum.getPlotOutline() + "');";
}
statement.executeUpdate(sql);
System.out.println("Album Added!");
if(statement != null) {
statement.close();
}
if(connection != null) {
connection.close();
}
}
这是一个例外:
java.sql.SQLSyntaxErrorException: Syntax error: Encountered "t" at line 2, column 5.
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedConnection.handleException(Unknown Source)
at org.apache.derby.impl.jdbc.ConnectionChild.handleException(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedStatement.execute(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedStatement.executeLargeUpdate(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedStatement.executeUpdate(Unknown Source)
at au.edu.uow.CollectionDB.MyCollectionDB.addAlbum(MyCollectionDB.java:194)
at au.edu.uow.Collection.CollectionFactory.loadCollection(CollectionFactory.java:136)
at MyCollection.main(MyCollection.java:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: ERROR 42X01: Syntax error: Encountered "t" at line 2, column 5.
at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
at org.apache.derby.impl.sql.compile.ParserImpl.parseStatementOrSearchCondition(Unknown Source)
at org.apache.derby.impl.sql.compile.ParserImpl.parseStatement(Unknown Source)
at org.apache.derby.impl.sql.GenericStatement.prepMinion(Unknown Source)
at org.apache.derby.impl.sql.GenericStatement.prepare(Unknown Source)
at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(Unknown Source)
... 11 more
答案 0 :(得分:4)
代码中存在两个问题:
SQL语句最后不需要分号;
。它会使代码失败。
代码很容易出现SQL注入,很难维护。改为使用PreparedStatement
:
这应该是工作代码:
String sql = "INSERT INTO MyAlbums VALUES (?, ?, ?, ?, ?)";
PreparedStatement pstmt = connection.prepareStatement(sql);
if(album instanceof CDAlbum) {
pstmt.setString(1, "CD");
CDAlbum cdAlbum = (CDAlbum)album;
pstmt.setString(4, cdAlbum.getArtist());
pstmt.setString(5, cdAlbum.getTracks());
}
if(album instanceof DVDAlbum) {
pstmt.setString(1, "DVD");
DVDAlbum dvdAlbum = (DVDAlbum)album;
pstmt.setString(4, dvdAlbum.getDirector());
pstmt.setString(5, dvdAlbum.getPlotOutline());
}
pstmt.setString(2, album.getTitle());
pstmt.setString(3, album.getGenre());
pstmt.executeUpdate();
普通字符串连接与此方法之间的大区别在于,PreparedStatement
参数将为您迁移任何'
和"
以及其他字符
答案 1 :(得分:3)
可能是“不要为我哭泣,阿根廷”。你看到了吗?
您可以使用错误的值来破坏安全性。
最好使用准备好的声明:
String sql = "INSERT INTO MyAlbums(Title, Genre, X, Y) VALUES (?, ?, ?, ?, ?)";
try (Statement statement = connection.createPreparedStatement(sql)) {
if(album instanceof CDAlbum) {
CDAlbum cdAlbum = (CDAlbum)album;
statement.setString(1, "CD");
statement.setString(2, cdAlbum.getTitle());
statement.setString(3, cdAlbum.getGenre());
statement.setString(4, cdAlbum.getArtist());
statement.setString(5, cdAlbum.getTracks());
} else if(album instanceof DVDAlbum) {
DVDAlbum dvdAlbum = (DVDAlbum)album;
statement.setString(1, "DVD");
statement.setString(2, dvdAlbum.getTitle());
statement.setString(3, dvdAlbum.getGenre());
statement.setString(4, dvdAlbum.getDirector());
statement.setString(5, dvdAlbum.getPlotOutline());
}
int updateCount = statement.executeUpdate();
System.out.println("Album Added! (" + updateCount + " Records updated)");
}
我添加了一些列名作为将来对表格方案进行更改的好方法。并且updateCount应该为1添加。
try-with-resources关闭statement
,无论抛出异常/返回/中断。
P.S。 “不要”可能是罪魁祸首,撇号结束引用的文本, t 出现在您的错误消息中。
答案 2 :(得分:3)
XKCD#327(http://xkcd.com/327/)
使用PreparedStatement
!
我可以建议:
try (final PreparedStatement preparedStatement = con.prepareStatement(sql)) {
if (album instanceof CDAlbum) {
CDAlbum cdAlbum = (CDAlbum) album;
preparedStatement.setString(1, "CD");
preparedStatement.setString(2, cdAlbum.getTitle());
preparedStatement.setString(3, cdAlbum.getGenre());
preparedStatement.setString(4, cdAlbum.getArtist());
preparedStatement.setString(5, cdAlbum.getTracks());
} else if (album instanceof DVDAlbum) {
DVDAlbum dvdAlbum = (DVDAlbum) album;
preparedStatement.setString(1, "DVD");
preparedStatement.setString(2, dvdAlbum.getTitle());
preparedStatement.setString(3, dvdAlbum.getGenre());
preparedStatement.setString(4, dvdAlbum.getDirector());
preparedStatement.setString(5, dvdAlbum.getPlotOutline());
}
dvdAlbum.getPlotOutline();
}
这可以防止导致查询失败的数据中出现奇怪值的任何可能性。另请注意,我使用try-with-resources
构造,这将始终关闭资源。如果查询中存在错误,则当前代码存在内存泄漏 - 将抛出异常并跳过close()
调用。当您阅读文件,打开连接时等许多地方都有此问题......
我还将您的if...if
更改为if...else if
,因为我认为CDAlbum
也不太可能是DVDAlbum
。命名注释 - 类名中的首字母缩略词最好用单词表示 - DvdAlbum
而不是DVDAlbum
。
此外,我建议您了解方法重载以及多态。如果您的代码中instanceof
是代码异味的确定标志,则可以使用。
虽然将完全不同的数据存储在同一个表中的整个想法是设计问题的明确标志。此外,像tracks
这样的字段 - 肯定需要另一个表格?!
答案 3 :(得分:0)
sql = "INSERT INTO MyAlbums VALUES ('DVD', '" + dvdAlbum.getTitle() + "', '" + dvdAlbum.getGenre() + "','" + dvdAlbum.getDirector() + "', '" + dvdAlbum.getPlotOutline() + "');";
我不认为两个;需要。最好调试代码并在DB中进行SQL查询和测试。
答案 4 :(得分:0)
您需要转义'
字符串中的所有cdAlbum.getTitle(), cdAlbum.getGenre(), cdAlbum.getArtist(), cdAlbum.getTracks()
字符。
更好的是,使用prepared statement它会为你处理这个问题,作为奖励你不会受到SQL注入的攻击。