问题
Hi I am having trouble executing the following function without running into the following exception. I'm not sure why this is happening. I think it might have something to do with the quotes. I am using derby database if it matters.
java.sql.SQLSyntaxErrorException
This is the following code I am trying to execute:
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();
}
}
This is the exception:
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
回答1:
Two problems in your code:
SQL statements don't need semicolon
;
at the end. It will make the code fail.The code is prone to SQL Injection and is hard to maintain. Use a
PreparedStatement
instead:
This should be the working code:
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();
The big difference between plain string concatenation and this approach for your case is that PreparedStatement
parameters will escape any '
and "
and other characters for you.
回答2:
XKCD #327 (http://xkcd.com/327/)
Use a PreparedStatement
!
May I suggest:
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();
}
This prevents any possibility of weird values in the data causing the query to fail. Also note that I use a try-with-resources
construct, this will always close the resources. Your current code has a memory leak if there is an error in the query - the exception will be thrown and the close()
calls with be skipped. You have this issue in many places, when you read the file, when you open the connection, etc...
I have also changed your if...if
to an if...else if
as I suppose it's unlikely that a CDAlbum
would also be a DVDAlbum
. A naming note - acronyms in class names are best expressed as words - DvdAlbum
rather than DVDAlbum
.
Further I would suggest that you learn about method overloading as well as polymorphism. Any use if instanceof
in your code is a sure sign of code smell.
Although the whole idea of storing completely disparate data in the same table is a sure sign of design problems. Further, fields like tracks
- surely that needs to be another table?!
回答3:
It is probably "Don't cry for me, Argentina". Do you see it?
You can breach security with wrong values.
Best use a prepared statement:
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)");
}
I have added some column names as good measure for future changes to the table scheme. And updateCount should give 1 for addition.
The try-with-resources closes statement
irrespective of thrown exception / return / break.
P.S. "Don't" is probably the culprit, the apostrophe ends the quoted text, and that t appears in your error message.
回答4:
sql = "INSERT INTO MyAlbums VALUES ('DVD', '" + dvdAlbum.getTitle() + "', '" + dvdAlbum.getGenre() + "','" + dvdAlbum.getDirector() + "', '" + dvdAlbum.getPlotOutline() + "');";
I don't think two ; required. Better to debug the code and take the SQL query and test in DB.
回答5:
You need to escape any '
character in your cdAlbum.getTitle(), cdAlbum.getGenre(), cdAlbum.getArtist(), cdAlbum.getTracks()
strings.
Better yet, use prepared statement and it will handle this for you and as a bonus you won't be vulnerable to SQL injection.
来源:https://stackoverflow.com/questions/25811597/sql-syntax-error-exception-when-trying-to-insert-row-into-table