How to make SQL delete method validate the data properly - java

I got a method that deletes a record in the database when inserting a tag value. when a record is deleted, a message in the console screen pops up saying "this record has been deleted ". It works fine when inserting a valid tag value. However, when I insert an invalid tag value that doesn't exist in my database it acts like it has deleted it and displays that previous message. Although within my method says if the outcome is not equal 1 (which is not true) return false, but it's apparently not validating the inserted data. Can anyone tell me what's the problem
public boolean DeleteWallet(String Tag) throws SQLException {
System.out.println("Deleting wallet");
Connection dbConnection = null;
Statement statement = null;
int result = 0;
String query = "DELETE FROM wallets WHERE Tag = '" + Tag + "';";
try {
dbConnection = getDBConnection();
statement = dbConnection.createStatement();
System.out.println("The record has been deleted successfully");
// execute SQL query
result = statement.executeUpdate(query);
} finally {
if (statement != null) {
statement.close();
}
if (dbConnection != null) {
dbConnection.close();
}
}
if (result == 1) {
return true;
} else {
return false;
}
}

The statement
System.out.println("The record has been deleted successfully");
is being printed before you actually perform any database operations statement.executeUpdate(query);
Instead, you should perform your database operation within your try statement, then print your success output. If the statement fails (IE an exception is thrown) the success statement will be skipped.
Additionally, instead of relying on the output the the executeUpdate(query) to determine if your query was successful, I would always assume your query or some operation before the query fails, and only return true if all database processing was successful.
Finally, the use of prepared statements will help make your query easier to read, use, and is better secured against SQLInjection attacks.
Example:
public class DatabaseOperations {
public boolean DeleteWallet(String Tag) {
//Query used for prepared statement
static final String DELETE_QUERY = "DELETE FROM wallets WHERE Tag=?";
System.out.println("Attempting to delete wallet using query:" + DELETE_QUERY);
//assume DELETE operation fails due to exection at any stage
Boolean result = false;
try (
//Objects that can automatically be closed at the end of the TRY block
//This is known as AutoCloseable
Connection dbConnection = getDBConnection();
PreparedStatement statment = dbConnection.preparedStatement(DELETE_QUERY))
{
//replace ? with Tag
statement.setString(1, Tag);
int row = preparedStatement.executeUpdate();
//If statement fails skip to catch block
result = true;
System.out.println("The record in row " + row + " has been deleted successfully");
} catch (SQLException sqle) {
//likely thrown due to "Record Not Found"
//TODO investigate further for the specific exception thrown from the database implementation you are using.
//TODO print helpful message to help user of this method resolve this issue
} catch (Exception) {
//TODO handle any other exceptions that may happen
}
return result;
}
}

Related

How to perform a select query on the ResultSet of another select query in java

This is the code where I'm trying to execute a second query on the resultSet of my first lengthy query. I need to upload this
data somewhere.
Is it the right thing to do?
Or is there a better approach apart from querying the database again?
public String createQuery() throws SQLException {
StringBuilder Query = new StringBuilder();
try {
Query.append(" SELECT ...... ")
} catch (Exception e) {
e.printStackTrace();
}
return Query.toString();
}
private void openPreparedStatements() throws SQLException {
myQuery = createQuery();
try {
QueryStatement = dbConnection.prepareStatement(myQuery);
} catch (SQLException e) {
e.printStackTrace();
return;
}
}
public ResultSet selectData(String timestamp) throws SQLException {
openConnection();
ResultSet result = null;
ResultSet rs_new=null;
try {
result = QueryStatement.executeQuery();
while (result.next()) {
String query = "SELECT * FROM " + result + " WHERE " + "ID" + " =" + "ABC";
rs_new =QueryStatementNew.executeQuery(query);
System.out.print(rs_new);
}
} catch (SQLException e) {
LOGGER.info("Exception", e);
}
return result;
}
Instead of running two separate queries (when you don't need the intermediate one) you can combine them.
For example you can do:
SELECT *
FROM (
-- first query here
) x
WHERE ID = 'ABC'
You cannot use two statement objects within one database connection. So you can either open another database connection and execute the second statement in the 2nd connection, or iterate through the resultset from first statement and store the value you need (e.g. in an array/collection) then close that statement and run the second one, this time retrieving the value from the array/collection you saved them in. Refer to Java generating query from resultSet and executing the new query
Make Db2 keep your intermediate result set in a Global Temporary Table, if you have an ability to use it, and you application uses the same database connection session.
DECLARE GLOBAL TEMPORARY TABLE SESSION.TMP_RES AS
(
SELECT ID, ... -- Your first lengthy query text goes here
) WITH DATA WITH REPLACE ON COMMIT PRESERVE ROWS NOT LOGGED;
You may send the result of subsequent SELECT ... FROM SESSION.TMP_RES to FTP, and the result of SELECT * FROM SESSION.TMP_RES WHERE ID = 'ABC' to elastic.

Terminal condition for JDBC preparedStatement.executeBatch()

I am using java.sql library to execute updates in batches.
When preparedStatement.executeBatch() is executed, ideally it should return an array of update counts.
But in some instances, instead of update counts it returns -2, like below..
/**
* The constant indicating that a batch statement executed successfully
* but that no count of the number of rows it affected is available.
*
* #since 1.4
*/
int SUCCESS_NO_INFO = -2;
So in this case, when I am running the queries in batches, there's no way to find whether a particular batch query execution updated any records or not. So there's no way to determine a terminal condition to exit the loop of batch execution. If anyone has a workaround or suggestion. It would be helpful.
I have the below condition right now.
private static String batchUpdate() throws SQLException {
Connection dbConnection = null;
PreparedStatement preparedStatement = null;
String result = null;
String updateSQL = "update TABLE_NAME set SOME_FLAG ='T' \n" +
" where SOME_USER!='SOMEUSER' and SOME_FLAG = 'F' and rownum<=?";
try {
dbConnection = getDBConnection();
preparedStatement = dbConnection.prepareStatement(updateSQL);
dbConnection.setAutoCommit(false);
while (true) {
preparedStatement.setInt(1, 10000);
preparedStatement.addBatch();
int[] updateResults = preparedStatement.executeBatch();
if (updateResults == null || updateResults.length == 0 || updateResults[0] == -3) {
break;
}
dbConnection.commit();
}
result = "Records are updated!";
} catch (SQLException e) {
result = e.getMessage();
dbConnection.rollback();
} finally {
if (preparedStatement != null) {
preparedStatement.close();
}
if (dbConnection != null) {
dbConnection.close();
}
}
return result;
}
Oracle 11g does not return update counts for batch methods. Instead it returns SUCCESS_NO_INFO.
I looked at some examples here, and I think you'll have to catch an exception in your code.
So this means a complete redesign of your code.
Look at the tutorial link. I think it shouldn't be that hard for you.
Also, do a rollback if you get an exception!

How to check if deletion was successful in the database?

I wanted an error to popup, when the user entered a wrong id into the delete field. But even if a wrong id is entered, the query still proceeds, but no data is deleted. Here's my code:
String value = jTextField19.getText();
if (value == null || "".equals(value)) {
JOptionPane.showMessageDialog(null, "The field is blank!");
} else {
theQuery("DELETE FROM inventorydb WHERE item_id=('"+jTextField19.getText()+"') AND item_id IS NOT NULL");
}
The theQuery method:
private void theQuery(String query) {
Connection con = null;
Statement st = null;
try {
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/inventory", "root", "");
st = con.createStatement();
st.executeUpdate(query);
JOptionPane.showMessageDialog(null, "Done!");
} catch (Exception ex) {
JOptionPane.showMessageDialog(null,"Error!");
}
}
First of all: do not ever directly build SQL queries from user input, use prepared statements instead. If you don't know about SQL Injection, you should.
If you are using JDBC, you can check the result of #executeUpdate() to see how many rows were affected. If it was zero, then you can say that it was a wrong id.
This is the method definition:
public int executeUpdate(java.lang.String sql)
The return value is:
An int that indicates the number of rows affected, or 0 if using a DDL statement.
In the program at hand, you can just simply do this:
int deleted = st.executeUpdate(query);
if (deleted == 0) {
JOptionPane.showMessageDialog(null, "Nothing to delete!");
return;
}

How to get result size from an SQL query and check size

Hi I'm trying to write a piece of code for a simple verification method as part of a MVC.
At present the SQL is not written as a prepared statement so obviously it is at risk to a SQL injection so any help in regards to writing the SQL as a prepared statement would be really helpful.
The method which is in the User model.
public boolean getInfo() {
try {
DBAccess dbAccess = new DBAccess();
String sql = "SELECT username, password FROM owner WHERE username = '" + this.username
+ "'AND password = '" + this.password + "';";
dbAccess.close();dbAccess.executeQuery(sql);
dbAccess.close();
return true;
} catch (Exception e) {
return false;
}
}
I want to get the size of the result set which is generated by the SQL query and if the size of it is 1 return true else it's false.
If you need more info on the rest of the MVC just post and I'll get it up here.
Just return the result of ResultSet#next(), assuming that there's an UNIQUE constraint on the username. It returns false if there is no next record.
Here's a concrete kickoff example, slightly rewritten to fix potential SQL injection attack hole, resource leaking and threadsafety problems as shown so far in your code. Also, the altered SQL query should force you to MD5-hash the passwords before saving in DB (you don't want to store passwords plaintext in DB).
public boolean exist(String username, String password) throws SQLException {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
boolean exist = false;
try {
connection = database.getConnection();
statement = connection.prepareStatement("SELECT id FROM owner WHERE username = ? AND password = MD5(?)");
statement.setString(1, username);
statement.setString(2, password);
resultSet = statement.executeQuery();
exist = resultSet.next();
} finally {
if (resultSet != null) try { resultSet.close(); } catch (SQLException ignore) {}
if (statement != null) try { statement.close(); } catch (SQLException ignore) {}
if (connection != null) try { connection.close(); } catch (SQLException ignore) {}
}
return exist;
}
Rather select the fields username and password, you could select the count of them and then reference that value.
So your SQL query would be:
SELECT count(*) FROM owner WHERE username = '" + this.username
+ "'AND password = '" + this.password + "';
That would return the number of matched records, where if number is greater than 0, or equals one, validate them.
Without knowing the details of your DBAccess class, we can't tell you how to do this. I'm guessing it returns a List (but it's a guess, nothing more). If that's the case, you could check the size of the List via list.size() , or see if it returned at least 1 result with !list.isEmpty(). Of course, if it's not a list then this won't work.
And you definitely need to switch to prepared statements. For an example, see this SO post.
Side note: if this method is returning a boolean indicating whether a user exists, it shouldn't be called getInfo()! Something like userExists() would make more sense.
For your question about preventing sql injection, and if you want to start getting your feet wet with an "ORM like" library, you could use myibatis to create prepared statements. Myibatis is a data mapper which you can create a relatively simple ORM from. As you get more brave, you could move to hibernate or JPA.
http://www.mybatis.org/

delete sql not deleting

I'm trying to delete an event from my table. However I can't seem to get it to work.
My SQL statement is:
public void deleteEvent(String eventName){
String query = "DELETE FROM `Event` WHERE `eventName` ='"+eventName+"' LIMIT 1";
db.update(query);
System.out.println (query);
}
Using MySQL db
Try using the following :
String query = "DELETE FROM `Event` WHERE `eventName` ='"+eventName+"' LIMIT 1";
try {
Connection con = getConnection();
Statement s = con.createStatement();
s.execute(query);
} catch (Exception ex) {
ex.printStackTrace();
}
You have to code your getConnection() method to return a valid Database Connection.
I would suggest using Statement.executeUpdate method, since it returns an integer. So after performing this delete query you will also have information if you really deleted any records (in this case you would expect this method to return 1, since you are using LIMIT=1). I would also suggest closing Statement as soon as you don't need it, here is skeleton implementation:
private void performDelete(Connection conn, String deleteQuery, int expectedResult) throws SQLException {
Statement stmt = conn.createStatement();
int result = -1;
try {
result = stmt.executeUpdate(deleteQuery);
if(result != expectedResult) {
//Here you can check the result. Perhaps you don't need this part
throw new IllegalStateException("Develete query did not return expected value");
}
} catch(SQLException e) {
//Good practice if you use loggers - log it here and rethrow upper.
//Or perhaps you don't need to bother in upper layer if the operation
//was successful or not - in such case, just log it and thats it.
throw e;
} finally {
//This should be always used in conjunction with ReultSets.
//It is not 100% necessary here, but it will not hurt
stmt.close();
}
}

Categories