Related
I am trying to print out all the columns that has the same path as the one that i get from an Image. The main problem is that path='path' is read as a string with the value "path" instead of the value that i have in my path-variable. path = path without the '' is not accepted as a value, and therefore i can't print the columns. if i directly insert path='C:\Users....\' here, it prints out the right columns.
public void getImageInfoFromDatabase(Image image) {
String path = image.getFile().getAbsolutePath();
path = path.replace("\\", "\\\\");
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connect = DriverManager.getConnection(url, user, pass);
Statement statement = connect.createStatement();
resultSet = statement.executeQuery("SELECT * FROM image_table WHERE path='path'");
while (resultSet.next()) {
int id = resultSet.getInt(1);
String title = resultSet.getString(2);
String path = resultSet.getString(3);
String tags = resultSet.getString(4);
String latitude = resultSet.getString(5);
String longitude = resultSet.getString(6);
java.util.Date timestamp = resultSet.getTimestamp(7);
System.out.println(id + " " + title + " " + path + " " + tags + " " + latitude + " " + longitude + " " + timestamp);
}
} catch (SQLException | ClassNotFoundException e) {
System.out.println("Error. ");
e.printStackTrace();
}
}
I found out that i had to use the setString method from PreparedStatement to input a value at a specific index. The complete functioning code looks like this:
public boolean getImageInfoFromDatabase(Image image) {
boolean success = true;
String string = image.getFile().getAbsolutePath();
string = string.replace("\\", "\\\\");
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connect = DriverManager.getConnection(url, user, pass);
PreparedStatement stmt = connect.prepareStatement("SELECT * FROM image_table WHERE path = ?");
stmt.setString(1, string);
resultSet = stmt.executeQuery();
while (resultSet.next()) {
int id = resultSet.getInt(1);
String title = resultSet.getString(2);
String path = resultSet.getString(3);
String tags = resultSet.getString(4);
String latitude = resultSet.getString(5);
String longitude = resultSet.getString(6);
java.util.Date timestamp = resultSet.getTimestamp(7);
System.out.println(id + " " + title + " " + path + " " + tags + " " + latitude + " " + longitude + " " + timestamp);
success = true;
}
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
success = false;
}
return success;
}
SELECT * FROM image_table WHERE path='path'
I want to create a java source object in oracle database via JDBC, PreparedStatement. However, in the java source file, there are several question marks. Once I executed it, I faced an error message like below..
java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).
I changed my code to be more understandable.
private void installOS_COMMAND() {
Connection targetDBconn = null;
PreparedStatement pstmt = null;
Statement stmt = null;
try {
String SQL = "create or replace java source named \"FILE_TYPE_JAVA\" as\n"
+ "public class FileType {\n"
+ " public static String getFileTypeOwner(Connection con) throws Exception {\n"
+ " String sFileTypeOwner = null;\n"
+ " CallableStatement stmt = con.prepareCall(\"begin dbms_utility.name_resolve(?,?,?,?,?,?,?,?); end;\");\n"
+ " stmt.setString(1, \"FILE_TYPE\");\n"
+ " stmt.setInt(2, 7);\n"
+ " stmt.registerOutParameter(3, java.sql.Types.VARCHAR);\n"
+ " stmt.registerOutParameter(4, java.sql.Types.VARCHAR);\n"
+ " stmt.registerOutParameter(5, java.sql.Types.VARCHAR);\n"
+ " stmt.registerOutParameter(6, java.sql.Types.VARCHAR);\n"
+ " stmt.registerOutParameter(7, oracle.jdbc.OracleTypes.NUMBER);\n"
+ " stmt.registerOutParameter(8, oracle.jdbc.OracleTypes.NUMBER);\n"
+ " stmt.execute();\n"
+ " sFileTypeOwner = stmt.getString(3);\n"
+ " stmt.close();\n"
+ " return sFileTypeOwner;\n"
+ " }\n"
+ "}";
targetDBconn = globalTargetConn.connect();
pstmt = targetDBconn.prepareStatement(SQL);
pstmt.executeUpdate();
} catch (SQLException ex) { logWriter.writeLogs(logTextArea, LogWriter.ERROR, ex.getMessage());
} finally {
if (pstmt != null ) try {pstmt.close();} catch(SQLException ex) {}
if (targetDBconn != null ) try {targetDBconn.close();} catch(SQLException ex) {}
}
}
Is there someone who can fix this problem?
Don't use prepared statements:
private void installOS_COMMAND() {
Connection targetDBconn = null;
Statement stmt = null;
try {
String SQL = "create or replace java source named \"FILE_TYPE_JAVA\" as\n"
+ "public class FileType {\n"
+ " public static String getFileTypeOwner(Connection con) throws Exception {\n"
+ " String sFileTypeOwner = null;\n"
+ " CallableStatement stmt = con.prepareCall(\"begin dbms_utility.name_resolve(?,?,?,?,?,?,?,?); end;\");\n"
+ " stmt.setString(1, \"FILE_TYPE\");\n"
+ " stmt.setInt(2, 7);\n"
+ " stmt.registerOutParameter(3, java.sql.Types.VARCHAR);\n"
+ " stmt.registerOutParameter(4, java.sql.Types.VARCHAR);\n"
+ " stmt.registerOutParameter(5, java.sql.Types.VARCHAR);\n"
+ " stmt.registerOutParameter(6, java.sql.Types.VARCHAR);\n"
+ " stmt.registerOutParameter(7, oracle.jdbc.OracleTypes.NUMBER);\n"
+ " stmt.registerOutParameter(8, oracle.jdbc.OracleTypes.NUMBER);\n"
+ " stmt.execute();\n"
+ " sFileTypeOwner = stmt.getString(3);\n"
+ " stmt.close();\n"
+ " return sFileTypeOwner;\n"
+ " }\n"
+ "}";
targetDBconn = globalTargetConn.connect();
stmt = targetDBconn.createStatement();
stmt.setEscapeProcessing(false);
stmt.executeUpdate(SQL);
} catch (SQLException ex) { logWriter.writeLogs(logTextArea, LogWriter.ERROR, ex.getMessage());
} finally {
if (targetDBconn != null ) try {targetDBconn.close();} catch(SQLException ex) {}
}
}
public boolean saveHighScore(Client c) throws SQLException {
long totallvlexp = (long) (c.playerXP[0]) + (c.playerXP[1]) + (c.playerXP[2]) + (c.playerXP[3]) + (c.playerXP[4]) + (c.playerXP[5]) + (c.playerXP[6]) + (c.playerXP[7]) + (c.playerXP[8]) + (c.playerXP[9]) + (c.playerXP[10]) + (c.playerXP[11]) + (c.playerXP[12]) + (c.playerXP[13]) + (c.playerXP[14]) + (c.playerXP[15]) + (c.playerXP[16]) + (c.playerXP[17]) + (c.playerXP[18]) + (c.playerXP[19]) + (c.playerXP[20]);
int totallevell = (int) (c.getLevelForXP(c.playerXP[0]) + c.getLevelForXP(c.playerXP[1]) + c.getLevelForXP(c.playerXP[2]) + c.getLevelForXP(c.playerXP[3]) + c.getLevelForXP(c.playerXP[4]) + c.getLevelForXP(c.playerXP[5]) + c.getLevelForXP(c.playerXP[6]) + c.getLevelForXP(c.playerXP[7]) + c.getLevelForXP(c.playerXP[8]) + c.getLevelForXP(c.playerXP[9]) + c.getLevelForXP(c.playerXP[10]) + c.getLevelForXP(c.playerXP[11]) + c.getLevelForXP(c.playerXP[12]) + c.getLevelForXP(c.playerXP[13]) + c.getLevelForXP(c.playerXP[14]) + c.getLevelForXP(c.playerXP[15]) + c.getLevelForXP(c.playerXP[16]) + c.getLevelForXP(c.playerXP[17]) + c.getLevelForXP(c.playerXP[18]) + c.getLevelForXP(c.playerXP[19]) + c.getLevelForXP(c.playerXP[20]));
String delQuery1 = "DELETE FROM `skills` WHERE playerName = '"+c.playerName+"';";
String delQuery2 = "DELETE FROM `skillsoverall` WHERE playerName = '"+c.playerName+"';";
String delQuery3 = "DELETE FROM `playerrights` WHERE playerName = '"+c.playerName+"';";
String insQuery1 = "INSERT INTO `skills` (`playerName`,`Attacklvl`,`Attackxp`,`Defencelvl`,`Defencexp`,`Strengthlvl`,`Strengthxp`,`Hitpointslvl`,`Hitpointsxp`,`Rangelvl`,`Rangexp`,`Prayerlvl`,`Prayerxp`,`Magiclvl`,`Magicxp`,`Cookinglvl`,`Cookingxp`,`Woodcuttinglvl`,`Woodcuttingxp`,`Fletchinglvl`,`Fletchingxp`,`Fishinglvl`,`Fishingxp`,`Firemakinglvl`,`Firemakingxp`,`Craftinglvl`,`Craftingxp`,`Smithinglvl`,`Smithingxp`,`Mininglvl`,`Miningxp`,`Herblorelvl`,`Herblorexp`,`Agilitylvl`,`Agilityxp`,`Thievinglvl`,`Thievingxp`,`Slayerlvl`,`Slayerxp`,`Farminglvl`,`Farmingxp`,`Runecraftlvl`,`Runecraftxp`) VALUES ('"+c.playerName+"',"+c.playerLevel[0]+","+c.playerXP[0]+","+c.playerLevel[1]+","+c.playerXP[1]+","+c.playerLevel[2]+","+c.playerXP[2]+","+c.playerLevel[3]+","+c.playerXP[3]+","+c.playerLevel[4]+","+c.playerXP[4]+","+c.playerLevel[5]+","+c.playerXP[5]+","+c.playerLevel[6]+","+c.playerXP[6]+","+c.playerLevel[7]+","+c.playerXP[7]+","+c.playerLevel[8]+","+c.playerXP[8]+","+c.playerLevel[9]+","+c.playerXP[9]+","+c.playerLevel[10]+","+c.playerXP[10]+","+c.playerLevel[11]+","+c.playerXP[11]+","+c.playerLevel[12]+","+c.playerXP[12]+","+c.playerLevel[13]+","+c.playerXP[13]+","+c.playerLevel[14]+","+c.playerXP[14]+","+c.playerLevel[15]+","+c.playerXP[15]+","+c.playerLevel[16]+","+c.playerXP[16]+","+c.playerLevel[17]+","+c.playerXP[17]+","+c.playerLevel[18]+","+c.playerXP[18]+","+c.playerLevel[19]+","+c.playerXP[19]+","+c.playerLevel[20]+","+c.playerXP[20]+");";
String insQuery2 = "INSERT INTO `skillsoverall` (`playerName`,`lvl`,`xp`) VALUES ('"+c.playerName+"',"+totallevell+","+totallvlexp+");";
String insQuery3 = "INSERT INTO `playerrights` (`playerName`,`rank`) VALUES ('"+c.playerName+"',"+c.playerRights+");";
String[] delQueries = {delQuery1, delQuery2, delQuery3};
String[] insQueries = {insQuery1, insQuery2, insQuery3};
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
try(Connection conX = DriverManager.getConnection("jdbc:mysql://localhost/highscores","root","root")) {
try(Statement stmtX = conX.createStatement()) {
for(int i = 0; i < delQueries.length; i++)
{
stmtX.executeUpdate(delQueries[i]);
stmtX.executeUpdate(insQueries[i]);
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
}
Using this code how could I make it faster? If I used UPDATE instead would it make it faster? If it would please show me how to do that with the code I provided. I'm not very good with SQL, again just helping out a friend.
Some ways to improve this:
Use UPDATE statement and use the value of the primary key in the WHERE clause. This is in case you know the id. If you don't know it, then
Use UPDATE statement properly. Add a proper index on the columns you will use for the WHERE clause, in case is a single column and it's not the primary key and this statement may be executed several times.
Update the relevant columns, not all the columns (unless you are updating all the values for that row, which is something odd but not impossible).
Since you want/need to update everything or nothing, then you should use a transaction. You can start a transaction by using Connection#setAutoCommit(false); and close it by using Connection#commit. In case of errors, use Connection#rollback() and none of the operations will affect the database.
Stop using Statement so naively. If your queries need to be parameterized, then use PreparedStatement instead.
In your database, do this:
ALTER TABLE skills ADD INDEX idx_playerName (playerName);
Here's part of your Java code updated using the statements above:
public boolean saveHighScore(Client c) throws SQLException {
long totallvlexp = (long) (c.playerXP[0]) + (c.playerXP[1]) + (c.playerXP[2]) + (c.playerXP[3]) + (c.playerXP[4]) + (c.playerXP[5]) + (c.playerXP[6]) + (c.playerXP[7]) + (c.playerXP[8]) + (c.playerXP[9]) + (c.playerXP[10]) + (c.playerXP[11]) + (c.playerXP[12]) + (c.playerXP[13]) + (c.playerXP[14]) + (c.playerXP[15]) + (c.playerXP[16]) + (c.playerXP[17]) + (c.playerXP[18]) + (c.playerXP[19]) + (c.playerXP[20]);
int totallevell = (int) (c.getLevelForXP(c.playerXP[0]) + c.getLevelForXP(c.playerXP[1]) + c.getLevelForXP(c.playerXP[2]) + c.getLevelForXP(c.playerXP[3]) + c.getLevelForXP(c.playerXP[4]) + c.getLevelForXP(c.playerXP[5]) + c.getLevelForXP(c.playerXP[6]) + c.getLevelForXP(c.playerXP[7]) + c.getLevelForXP(c.playerXP[8]) + c.getLevelForXP(c.playerXP[9]) + c.getLevelForXP(c.playerXP[10]) + c.getLevelForXP(c.playerXP[11]) + c.getLevelForXP(c.playerXP[12]) + c.getLevelForXP(c.playerXP[13]) + c.getLevelForXP(c.playerXP[14]) + c.getLevelForXP(c.playerXP[15]) + c.getLevelForXP(c.playerXP[16]) + c.getLevelForXP(c.playerXP[17]) + c.getLevelForXP(c.playerXP[18]) + c.getLevelForXP(c.playerXP[19]) + c.getLevelForXP(c.playerXP[20]));
boolean result = true;
String updateSkillsSql = "UPDATE skills"
+ " SET `Attacklvl`=?,"
+ " `Attackxp`=?,"
+ " `Defencelvl`=?,"
+ " `Defencexp`=?,"
+ " `Strengthlvl`=?,"
+ " `Strengthxp`=?,"
+ " `Hitpointslvl`=?,"
+ " `Hitpointsxp`=?,"
+ " `Rangelvl`=?,"
+ " `Rangexp`=?,"
+ " `Prayerlvl`=?,"
+ " `Prayerxp`=?,"
+ " `Magiclvl`=?,"
+ " `Magicxp`=?,"
+ " `Cookinglvl`=?,"
+ " `Cookingxp`=?,"
+ " `Woodcuttinglvl`=?,"
+ " `Woodcuttingxp`=?,"
+ " `Fletchinglvl`=?,"
+ " `Fletchingxp`=?,"
+ " `Fishinglvl`=?,"
+ " `Fishingxp`=?,"
+ " `Firemakinglvl`=?,"
+ " `Firemakingxp`=?,"
+ " `Craftinglvl`=?,"
+ " `Craftingxp`=?,"
+ " `Smithinglvl`=?,"
+ " `Smithingxp`=?,"
+ " `Mininglvl`=?,"
+ " `Miningxp`=?,"
+ " `Herblorelvl`=?,"
+ " `Herblorexp`=?,"
+ " `Agilitylvl`=?,"
+ " `Agilityxp`=?,"
+ " `Thievinglvl`=?,"
+ " `Thievingxp`=?,"
+ " `Slayerlvl`=?,"
+ " `Slayerxp`=?,"
+ " `Farminglvl`=?,"
+ " `Farmingxp`=?,"
+ " `Runecraftlvl`=?,"
+ " `Runecraftxp`=?"
+ " WHERE playerName = ?";
//do similar for the other queries...
//not needed since JDBC 4, noted since you're using Java 7
//Class.forName("com.mysql.jdbc.Driver").newInstance();
try(Connection con = DriverManager.getConnection("jdbc:mysql://localhost/highscores","root","root")) {
//when storing multiple data, it's better to use a transaction
con.setAutoCommit(false);
try(PreparedStatement pstmt = con.prepareStatement(updateSkillsSql);
//declare the other PreparedStatements for each update sql statement here...
) {
//do something like this for every PreparedStatement
setParameters(pstmt,
c.playerLevel[0], c.playerXP[0],
c.playerLevel[1], c.playerXP[1],
c.playerLevel[2], c.playerXP[2],
c.playerLevel[3], c.playerXP[3],
c.playerLevel[4], c.playerXP[4],
c.playerLevel[5], c.playerXP[5],
c.playerLevel[6], c.playerXP[6],
c.playerLevel[7], c.playerXP[7],
c.playerLevel[8], c.playerXP[8],
c.playerLevel[9], c.playerXP[9],
c.playerLevel[10], c.playerXP[10],
c.playerLevel[11], c.playerXP[11],
c.playerLevel[12], c.playerXP[12],
c.playerLevel[13], c.playerXP[13],
c.playerLevel[14], c.playerXP[14],
c.playerLevel[15], c.playerXP[15],
c.playerLevel[16], c.playerXP[16],
c.playerLevel[17], c.playerXP[17],
c.playerLevel[18], c.playerXP[18],
c.playerLevel[19], c.playerXP[19],
c.playerLevel[20], c.playerXP[20],
c.playerName);
pstmt.executeUpdate();
} catch (Exception e) {
System.out.println(String.format("There's a problem when saving the data of player %s.", c.playerName));
e.printStackTrace(System.out);
con.rollback();
result = false;
}
if (result) {
con.commit();
con.setAutoCommit(true);
}
} catch (Exception e) {
System.out.println(String.format("There's a problem when saving the data of player %s.", c.playerName));
e.printStackTrace(System.out);
result = false;
}
return result;
}
//created method to add parameters despite its type
private void setParameters(PreparedStatement pstmt, Object ... args) {
int i = 1;
for (Object arg : args) {
pstmt.setObject(i++, arg);
}
}
The biggest cost in either your DELETE / INSERT approach or an UPDATE approach is probably your WHERE clause.
Doing the UPDATE or DELETE with a WHERE pointing at playerName = 'FriendlyNameOfPlayer' is brutal. You could make it a little better if you created an index on that field.
You'd create the index with something along the lines of...
CREATE INDEX playerName_ix ON skills (playerName)
CREATE INDEX playerName_ix ON skillsoverall (playerName)
Read more on some additional options that may be relevant on a case by case basis here.
A better practice would be to target the rows by their PK (maybe an auto-incrementing integer?). Ideally, the schema behind this would be a table called Player_Master with an autoincrementing integer as the PK, then the friendly name of the player stored in another column. Tables like those referenced in your code snippit should be storing the PK values from Player_Master (instead of the friendly name), which would be FK's. Your DELETE statement would instead look like...
DELETE FROM `skills` WHERE skills.playerID = 37
Redoing the schema would be the "correct" way to do it, but I get that every project may not have the time or resources required for a total teardown / redo. If your buddy is saying "can you make this faster?", you could do the index and walk away. If the question were "how do I do this right?", I'd start the clock on billable hours, because from the small glimpse into the code and schema provided, it's not a quick fix.
I'll also wristslap you for calling raw executes of cobbled together TSQL statements. There are better ways to do this.
I was wondering if someone here could help me, I can't find a solution for my problem and I have tried everything.
What I am trying to do is read and parse lines in a csv file into java objects and I have succeeded in doing that but after it reads all the lines it should insert the lines into the database but it only inserts the 1st line the entire time and I don't no why. When I do a print it shows that it is reading all the lines and placing them in the objects but as soon as I do the insert it wants to insert only the 1st line.
Please see my code below:
public boolean lineReader(File file){
BufferedReader br = null;
String line= "";
String splitBy = ",";
storeList = new ArrayList<StoreFile>();
try {
br = new BufferedReader(new FileReader(file));
while((line = br.readLine())!=null){
line = line.replace('|', ',');
//split on pipe ( | )
String[] array = line.split(splitBy, 14);
//Add values from csv to store object
//Add values from csv to storeF objects
StoreFile StoreF = new StoreFile();
if (array[0].equals("H") || array[0].equals("T")) {
return false;
} else {
StoreF.setRetailID(array[1].replaceAll("/", ""));
StoreF.setChain(array[2].replaceAll("/",""));
StoreF.setStoreID(array[3].replaceAll("/", ""));
StoreF.setStoreName(array[4].replaceAll("/", ""));
StoreF.setAddress1(array[5].replaceAll("/", ""));
StoreF.setAddress2(array[6].replaceAll("/", ""));
StoreF.setAddress3(array[7].replaceAll("/", ""));
StoreF.setProvince(array[8].replaceAll("/", ""));
StoreF.setAddress4(array[9].replaceAll("/", ""));
StoreF.setCountry(array[10].replaceAll("/", ""));
StoreF.setCurrency(array[11].replaceAll("/", ""));
StoreF.setAddress5(array[12].replaceAll("/", ""));
StoreF.setTelNo(array[13].replaceAll("/", ""));
//Add stores to list
storeList.add(StoreF);
}
} //print list stores in file
printStoreList(storeList);
executeStoredPro(storeList);
} catch (Exception ex) {
nmtbatchservice.NMTBatchService2.LOG.error("An exception accoured: " + ex.getMessage(), ex);
//copy to error folder
//email
}
return false;
}
public void printStoreList(List<StoreFile> storeListToPrint) {
for(int i = 0; i <storeListToPrint.size();i++){
System.out.println( storeListToPrint.get(i).getRetailID()
+ storeListToPrint.get(i).getChain()
+ storeListToPrint.get(i).getStoreID()
+ storeListToPrint.get(i).getStoreName()
+ storeListToPrint.get(i).getAddress1()
+ storeListToPrint.get(i).getAddress2()
+ storeListToPrint.get(i).getAddress3()
+ storeListToPrint.get(i).getProvince()
+ storeListToPrint.get(i).getAddress4()
+ storeListToPrint.get(i).getCountry()
+ storeListToPrint.get(i).getCurrency()
+ storeListToPrint.get(i).getAddress5()
+ storeListToPrint.get(i).getTelNo());
}
}
public void unzip(String source, String destination) {
try {
ZipFile zipFile = new ZipFile(source);
zipFile.extractAll(destination);
deleteStoreFile(source);
} catch (ZipException ex) {
nmtbatchservice.NMTBatchService2.LOG.error("Error unzipping file : " + ex.getMessage(), ex);
}
}
public void deleteStoreFile(String directory) {
try {
File file = new File(directory);
file.delete();
} catch (Exception ex) {
nmtbatchservice.NMTBatchService2.LOG.error("An exception accoured when trying to delete file " + directory + " : " + ex.getMessage(), ex);
}
}
public void executeStoredPro(List<StoreFile> storeListToInsert) {
Connection con = null;
CallableStatement st = null;
try {
String connectionURL = MSSQLConnectionURL;
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver").newInstance();
con = DriverManager.getConnection(connectionURL, MSSQLUsername, MSSQLPassword);
for(int i = 0; i <storeListToInsert.size();i++){
st = con.prepareCall( "IF EXISTS (SELECT * FROM tblPay#RetailStores WHERE StoreID = " + storeListToInsert.get(i).getStoreID() + " AND RetailID = "+ storeListToInsert.get(i).getRetailID() + ")"
+ " UPDATE tblPay#RetailStores "
+ " SET RetailID = '" + storeListToInsert.get(i).getRetailID() + "',"
+ " StoreID = '" + storeListToInsert.get(i).getStoreID() + "',"
+ " StoreName = '" + storeListToInsert.get(i).getStoreName() + "',"
+ " TestStore = 0,"
+ " Address1 = '" + storeListToInsert.get(i).getAddress1() + "',"
+ " Address2 = '" + storeListToInsert.get(i).getAddress2() + "',"
+ " Address3 = '" + storeListToInsert.get(i).getAddress3() + "',"
+ " Address4 = '" + storeListToInsert.get(i).getAddress4() + "',"
+ " Address5 = '" + storeListToInsert.get(i).getAddress5() + "',"
+ " Province = '" + storeListToInsert.get(i).getProvince() + "',"
+ " TelNo = '" + storeListToInsert.get(i).getTelNo() + "',"
+ " Enabled = 1"
+ " ELSE "
+ " INSERT INTO tblPay#RetailStores ( [RetailID], [StoreID], [StoreName], [TestStore], [Address1], [Address2], [Address3], [Address4], [Address5], [Province], [TelNo] , [Enabled] ) "
+ " VALUES "
+ "('" + storeListToInsert.get(i).getRetailID() + "',"
+ "'" + storeListToInsert.get(i).getStoreID() + "',"
+ "'" + storeListToInsert.get(i).getStoreName() + "',"
+ "0,"
+ "'" + storeListToInsert.get(i).getAddress1() + "',"
+ "'" + storeListToInsert.get(i).getAddress2() + "',"
+ "'" + storeListToInsert.get(i).getAddress3() + "',"
+ "'" + storeListToInsert.get(i).getAddress4() + "',"
+ "'" + storeListToInsert.get(i).getAddress5() + "',"
+ "'" + storeListToInsert.get(i).getProvince() + "',"
+ "'" + storeListToInsert.get(i).getTelNo() + "',"
+ "1)");
st.executeUpdate();
}
con.close();
} catch (Exception ex) {
nmtbatchservice.NMTBatchService2.LOG.error("Error executing Stored proc with error : " + ex.getMessage(), ex);
nmtbatchservice.NMTBatchService2.mailingQueue.addToQueue(new Mail("support#nmt-it.co.za", "Service Email Error", "An error occurred during Store Import failed with error : " + ex.getMessage()));
}
}
Any advise would be appreciated.
Thanks
Formatting aside, your code is wrong (I truncated the part of the query):
for(int i = 0; i <storeListToInsert.size();i++){
st = con.prepareCall( "IF EXISTS (SELECT * FROM tblPay#RetailStores ...
+ "'" + storeListToInsert.get(i).getTelNo() + "',"
+ "1)");
st.executeUpdate();
}
Don't do a classical for loop while foreach exists and can be better to use, and even if you do a classical for loop, use local variables, eg:
for(int i = 0; i <storeListToInsert.size();i++){
StoreFile item = storeListToInsert.get(i);
st = con.prepareCall( "IF EXISTS (SELECT * FROM tblPay#RetailStores ...
+ "'" + item.getTelNo() + "',"
+ "1)");
st.executeUpdate();
}
Which could translate as:
for (StoreFile item : storeListToInsert) {
st = con.prepareCall( "IF EXISTS (SELECT * FROM tblPay#RetailStores ...
+ "'" + item.getTelNo() + "',"
+ "1)");
st.executeUpdate();
}
Now, the second problem is your PreparedStatement. A PreparedStatement allow reusing, which means you don't need to create PreparedStatement per item which is what you are doing.
Also, you need to close the statement otherwise, you will exhaust resources..
You must not create it in the for loop, but before, like this:
PreparedStatement st = null;
try {
st = con.prepareCall( "IF EXISTS (SELECT * FROM tblPay#RetailStores ...
+ "SET RetailID = :RetailID ,"
+ "1)");
for (StoreFile item : storeListToInsert) {
st.setString(":RetailID", item.getRetailID());
st.executeUpdate();
}
} finally {
if (null != st) {st.close();}
}
In brief:
You need to close the PreparedStatement after usage, because it is a memory leak otherwise.
You need to rewrite your query using either named parameters, either positional parameter (like: ? or ?1 for first parameter, and so on). I favor named parameters, but they are not always available. The example I linked all use positional parameters.
You need to set the value for each parameters in the for loop, and care about the type. I expected here that getRetailID() is a String, but it might be a Long in that case that would be st.setLong.
Your query is reusable, avoiding the need to reparse it/resend it to the SQL Server. You just send the parameter's values. Beside, you can also batch update.
A PreparedStatement for a statement that you generate (like you are doing) is overkill, and beside, it is missing SQL escapement to protect the String you inject to your query to avoid it being badly interpreted (aka SQL errors) or worst, to do what it was not intended for (like, even if it is far fetched, dropping the whole database, etc).
The executeUpdate() return the number of updated rows. You can check it to see if there was updates.
You can also use Batch statement, which can help performances.
And finally, you can use opencsv to parse common CSV files.
I have a java web application that I removed a function from the code and yet the database entries that this function writes are still being written to the database.
Inside the IssueWarrant function there is a call to insertWarrantFee that has been commented out.
private void issueWarrant(String CasePrefix, String CaseNumber, String HearingType, String Suspend)
{
int i = 0, intDivision = 0, pos = 0;
String SummSeq = getSummSeq(CasePrefix, CaseNumber);
String Charges = getCharges(CasePrefix, CaseNumber, HearingType);
boolean isVacated = false, isHearingFound = false;
NextBWNumber warrNbr = new NextBWNumber();
String WarrantNumber = warrNbr.getNextBWNumber();
String warrStatus = warrNbr.getNextBWNStatus();
String HearingDesc = "", Division = "";
isVacated = getVacatedStatus(CasePrefix, CaseNumber, HearingType);
isHearingFound = getHearingStatus (CasePrefix, CaseNumber, HearingType);
HearingDesc = getFormatToday() + " " + getHearingDesc(HearingType);
if (HearingDesc.length() > 30)
{
HearingDesc = HearingDesc.substring(0,30);
}
Division = getHearingJudge(CasePrefix,CaseNumber,HearingType);
intDivision = Integer.parseInt(Division);
if (intDivision < 10)
{ Division = "0" + Division; }
Statement localstmt = null;
String localqueryString;
localqueryString = "INSERT INTO " + library7 + "CMPBWPND" +
" (CASPRE, CASNUM, DEFSEQ, CHGSEQ, SUMSEQ, STSCOD, STSDAT," +
" STATUT, CHGABV, BWNBR, JUDCOD, PRVFLG, CT2FLG, DIVISN, BNDAMT," +
" BTYPE, CMNT, CUSER, TUSER, LUPDAT, SCRDAT, STATSDAT, SUMCRDAT, LUPDATE )" +
" VALUES ('" + CasePrefix + "', " + CaseNumber + ", 1, " + Charges.substring(i, i + 1) +
", " + SummSeq + ", 9, " + getShortDate() + ", 'RCP 12-A TA', 'WARRANT', '" +
WarrantNumber + "', " + intDivision + ", 'N', 1, '" + Division + "', " +
BondAmt + ", '" + BondType + "', '" + HearingDesc + "', 'TAAD', 'TAAD', " +
getShortDate() + ", " + getShortDate() + ", " + getLongDate() + ", " + getLongDate() +
", " + getLongDate() + ")";
try
{
if (!isVacated && isHearingFound)
{
localstmt = conn.createStatement();
localstmt.executeUpdate(localqueryString);
localstmt.close();
StatusMsg = "Client No Show-WI";
}
if (isVacated)
{
StatusMsg = "Client Vacated Case";
}
if (!isHearingFound)
{
StatusMsg = "Client Hearing Missing";
}
} catch (SQLException e)
{
System.out.println("IssueWarr - Error in IssueWarrant");
e.printStackTrace();
ReturnInfo = "Issuing Warrants Failed.";
success = false;
}finally
{
try
{
if (!localstmt.isClosed())
{
localstmt.close();
}
} catch (SQLException sql2)
{
System.out.println("Error trying to close connections. Exception: " + sql2.getMessage());
}
}
**//insertWarrantFee(CasePrefix, CaseNumber, SummSeq, WarrantNumber);**
updateHearingRecord(CasePrefix, CaseNumber, HearingType, Charges.substring(i, i + 1), Suspend);
for ( i = 1; i < Charges.length(); i++ )
{
insertBWPTFRecord(CasePrefix, CaseNumber, SummSeq, Charges.substring(i, i + 1));
}
if (!success)
{
StatusMsg = "Client Iss. Warrant Failure";
}
}
Here is the code that the insertWarrantFee called before it was commented out:
private void insertWarrantFee(String CasePrefix, String CaseNumber, String SummSeq, String WarrantNumber)
{
Statement localstmt = null;
String localqueryString;
ResultSet localrSet = null;
String feeAmt = null;
localqueryString = "SELECT AUTO$$ FROM " + library3 + "CMPDKTTP WHERE DKTTYP = 'W'";
try
{
localstmt = conn.createStatement();
localrSet = localstmt.executeQuery(localqueryString);
while (localrSet.next())
{
feeAmt = localrSet.getString("AUTO$$");
}
localstmt.close();
localrSet.close();
} catch (SQLException e)
{
System.out.println("IssueWarr - Error in Insert Warrant Fee SQL1");
e.printStackTrace();
ReturnInfo = "Issuing Warrants Failed.";
success = false;
}finally
{
try
{
if (!localstmt.isClosed())
{
localstmt.close();
}
} catch (SQLException sql2)
{
System.out.println("Error trying to close connections. Exception: " + sql2.getMessage());
}
}
localqueryString = "INSERT INTO " + library7 + "CMPBWTRN"
+ " (CASPRE, CASNUM, DEFSEQ, SUMSEQ, BWNBR, FEEAMT, DKTTYP, TUSER, LUPDAT)"
+ " VALUES ('" + CasePrefix + "', " + CaseNumber + ", 1, " + SummSeq + ", '" + WarrantNumber
+ "', " + feeAmt + ", 'W', 'TAAD', " + getShortDate() + ")";
try
{
localstmt = conn.createStatement();
localstmt.executeUpdate(localqueryString);
localstmt.close();
} catch (SQLException e)
{
System.out.println("IssueWarr - Insert Warrant Fee SQL2");
e.printStackTrace();
ReturnInfo = "Issuing Warrants Failed.";
success = false;
}finally
{
try
{
if (!localstmt.isClosed())
{
localstmt.close();
}
} catch (SQLException sql2)
{
System.out.println("Error trying to close connections. Exception: " + sql2.getMessage());
}
}
}
So even though the line that called insertWarrantFee is commented out a record is still being inserted into CMPBWTRN.
Any ideas how this could happen? The developer is indicating it could be a tomcat connection cache issue? Any other suggestion beside magical code?
Thanks!
Leslie
A couple of things to try:
Make sure you've redeployed the application and have restarted Tomcat. Check the timestamp of the deployed class in question.
Clean Tomcat's tmp and work directories
Open the deployed Java class using a decompiler to see whether the removed code is still in there.
Add a logging (or System.out.println) statement to the method that's commented out, and to the method calling it. See whether one or both are printed after redeploying the changes.