Connection.rollback() doesn't work in Java - java

I wrote this function to easily populate my database(mySQL) :
public boolean addItems(Connection con) throws SQLException {
try {
con.setAutoCommit(false);
String[] brands = { "Honda", "BMW", "Mercedes Benz" };
String[] optional = { "acciaio", "alluminio", "carbonio", "titanio" };
Statement statement = con.createStatement();
for (int i = 0; i < brands.length; i++) {
for (int j = 0; j < optional.length; j++) {
statement.executeUpdate("INSERT INTO chassis (idUnit, brand, material, availableItems) VALUES (1, '" + brands[i] + "', '" + optional[j] + "', 20)");
statement = Condb.replaceStatement(statement);
ResultSet rs = statement.executeQuery("SELECT * FROM chassis WHERE brand = '" + brands[i] + "' AND material = '" + optional[j] + "'");
while (rs.next()) {
statement = Condb.replaceStatement(statement);
statement.executeUpdate("INSERT INTO product_code (unitName, productCode, brand, optional) VALUES ('chassis', " + rs.getInt("productCode") + ", '" + brands[i] + "', '" + optional[j] + "')");
con.commit();
}
}
}
return true;
} catch (Exception exception) {
exception.printStackTrace();
con.rollback();
return false;
}
}
But it adds one record in 'chassis' table (first update), then it doesn't enter in the while loop ('productCode' field is an auto increment field, so I need to take it from chassis table in order to add a record in 'product_code' table).
After this, it increase the j variable, executes the update in the chassis table, enters in the while loop and at the update (in the loop) it throws a SQLException
Operation not allowed after ResultSet closed
But it never executes the rollback. So I have records in my chassis table, but product_code table is empty.
This is my replaceStatement function :
public static Statement replaceStatement(Statement stmt) {
try {
stmt.close();
Statement statement = Condb.initializeDatabase().createStatement();
return statement;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Anyone can help me solve this issue?

You can't commit and then request a rollback. For a connection that you use with plain JDBC either make a single commit in the end or trigger a rollback if some statements fails.
So con.commit(); should be placed just before return true
Otherwise you can handle manualy multiple transactions inside your loops following this answer https://stackoverflow.com/a/47482143/7237884

Related

How to only execute database updates at the end of a while cycle

How can I only make my application execute the changes to a database at the end of the while cycle?
I have this rollback method but I only the changes to be made to the database at the end of it because of inconsistent data handling
I have tried to set auto commit to false but even though the exception was thrown at the second iteration of the while cycle, the changes were still in the database(until the point before the interruption, the tables after that didn't suffer changes).
Am I doing something wrong?
#Override
public void rollback(Database database) throws CustomChangeException {
JdbcConnection connection = (JdbcConnection) database.getConnection();
try {
connection.setAutoCommit(false);
ResultSet rs = getTables(connection);
//if the user chose to use a suffix
if (this.getSuffix() != null) {
while (rs.next()) {
String tableName = rs.getString(3);
if (tableName.endsWith(this.getSuffix())) {
if (!checkColumnsExists(connection, tableName, newName)) {
throw new CustomChangeException("The column " + newName + " doesn't exist in the table " + tableName + " anymore.Please fix this");
}
PreparedStatement s = connection.prepareStatement(getRollbackQuery(tableName));
s.executeUpdate();
logger.info("Column name reversed to " + this.getColumnName() + " in table" + tableName);
}
}
}
//if the user chose to use a regex
if (this.getRegex() != null) {
Pattern pattern = Pattern.compile(this.getRegex());
while (rs.next()) {
String tableName = rs.getString(3);
Matcher matcher = pattern.matcher(tableName);
boolean matches = matcher.matches();
if (matches) {
if (!checkColumnsExists(connection, tableName, newName)) {
logger.error("The column " + newName + " doesn't exist in the table " + tableName + " anymore.Please fix this");
throw new CustomChangeException();
}
PreparedStatement s = connection.prepareStatement(getRollbackQuery(tableName));
s.executeUpdate();
logger.info("Column name reversed to " + this.getColumnName() + " in table" + tableName);
}
}
}
connection.commit();
} catch (SQLException | DatabaseException | DifferentDataTypeException e) {
logger.error(e.getMessage());
throw new CustomChangeException();
}
}

Getting java.lang.reflect.InvocationTargetException while fetching the row count from each table in the database

I am working on a Java-Jdbc program which will take the row count of all the tables present in the database. To do that, I came up with the following code:
// Get the source(gp) count
public Map<String,Long> getGpTableCount() throws SQLException {
Map<String, String> gpTableMap = getScopeTableList(); // Key: Sourceschema.tablename, value: Destschema.tablename:sourcesystem1,sourcesystem2...sourcesystemn
Set<String> gpTableSet = gpTableMap.keySet(); // Gets the Source Table names - Schema.Tablename
gpCountMap = new HashMap<String, Long>();
Iterator<String> keySetIterator_gpTables = gpTableSet.iterator();
Connection gpAnalyticsCon = (Connection) DbManager.getGpConnection();
while(keySetIterator_gpTables.hasNext()) {
//getting source system names
String gpTabSchemakey = keySetIterator_gpTables.next();
String tablesnSSNs = gpTableMap.get(gpTabSchemakey);
String[] ssnArray = tablesnSSNs.split(":");
String sourceSystems = ssnArray[1];
System.out.println(sourceSystems);
if(sourceSystems.equals("No_SSNs_available") || sourceSystems == "No_SSNs_available") {
System.out.println("In the if condition");
gptableCountWithoutSsn = tblCountWithoutSsn(gpTabSchemakey, gpAnalyticsCon);
gpTabMapWoSsn.put(gpTabSchemakey, gptableCountWithoutSsn);
} else {
System.out.println("In the else condition");
//get the source system names
String inSourceSystems = "('" + sourceSystems.replace(",", "','") + "')";
String gpSchemaTableName = gpTabSchemakey;
String[] gpparts = gpSchemaTableName.split("\\."); // schema, tablename
String gpTable = gpparts[1];
String gpCountQuery = "select '" + gpTable + "' as TableName, count(*) as Count, source_system_name from " + gpSchemaTableName + " where source_system_name in " + inSourceSystems +" group by source_system_name order by source_system_name";
// resultSet(1): TableName, resultSet(2): count, resultSet(3): source_system_name
try {
PreparedStatement gp_pstmnt = gpAnalyticsCon.prepareStatement(gpCountQuery);
ResultSet gpCountRs = gp_pstmnt.executeQuery();
while(gpCountRs.next()) {
System.out.println("Tablename: " + gpCountRs.getString(1) + " Source System Name: " + gpCountRs.getString(3) + ", Count: " + gpCountRs.getLong(2));
System.out.println(" ");
ssn = getSsn(gpCountRs.getString(3));
gpCountMap.put(gpTable + ": " + gpCountRs.getString(3), gpCountRs.getLong(2));
}
} catch(org.postgresql.util.PSQLException e) {
System.out.println("Table: " + gpTable + " not found for the source system: " + ssn);
} catch(SQLException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
}
gpAnalyticsCon.close();
return gpCountMap;
}
There are two kinds of tables in the code.
Tables that have source systems
Tables without any source systems
There is an if-else condition where tables without sourcesystem names go to 'if' and those have source systems, go to 'else' condition.
In the 'if', I am calling another method: tblCountWithoutSsn which is written as:
// Method that returns the row count of tables without any source system name
private Long tblCountWithoutSsn(String tableWithoutSsn, Connection con) throws SQLException {
String[] woSsn = tableWithoutSsn.split("\\.");
long count=0;
String tablename = woSsn[1];
String query = "select '" + tablename + "' as TableName, count(*) as count from " + tableWithoutSsn;
System.out.println("Executing table: " + tablename + " which doesn't have any source system name");
System.out.println("Query for tables with no source_systems: " + query);
PreparedStatement gpwoSsn_pstmnt = con.prepareStatement(query);
ResultSet rs = gpwoSsn_pstmnt.executeQuery();
while(rs.next()) {
count = rs.getLong(2);
}
System.out.println("TableName: " + tablename + ", count: " + count);
return count;
}
There are 41 tables without any source systems. When I execute the jar file, I could see the count such of tables:
In the if condition
Executing table: table1withoutSSN which doesn't have any source system name
Query for tables with no source_systems: select 'table1withoutSSN' as TableName, count(*) as count from analytics_view.table1withoutSSN
TableName: table1withoutSSN, count: 1764
In the if condition
Executing table: table2withoutSSN which doesn't have any source system name
Query for tables with no source_systems: select 'table2withoutSSN' as TableName, count(*) as count from ge_hr3.table2withoutSSN
TableName: table2withoutSSN, count: 473376
But as soon as it reaches the table: table3WithoutSSN the code give exception and connection closes. The exception can be seen below:
In the if condition
Executing table: table3WithoutSSN which doesn't have any source system name
Query for tables with no source_systems: select 'table3WithoutSSN' as TableName, count(*) as count from custSchema.table3WithoutSSN
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused by: org.postgresql.util.PSQLException: This connection has been closed.
at org.postgresql.jdbc.PgConnection.checkClosed(PgConnection.java:803)
at org.postgresql.jdbc.PgConnection.prepareStatement(PgConnection.java:1621)
at org.postgresql.jdbc.PgConnection.prepareStatement(PgConnection.java:415)
at com.recordcount.dao.GpHiveRecords.tblCountWithoutSsn(GpHiveRecords.java:156)
at com.recordcount.dao.GpHiveRecords.getGpTableCount(GpHiveRecords.java:72)
at com.recordcount.entry.StartCount.main(StartCount.java:12)
... 5 more
The line 156 in the exception is:
PreparedStatement gpwoSsn_pstmnt = con.prepareStatement(query); from the method: `tblCountWithoutSsn`
Connection method in DBManager Class:
private static Connection gpAnalyticsConnection = null; // Creating gp connection
public static Connection getGpConnection() {
try {
Class.forName("org.postgresql.Driver");
if(gpAnalyticsConnection == null) {
gpAnalyticsConnection = DriverManager.getConnection("hostname", "username", "password");
return gpAnalyticsConnection;
} else {
return gpAnalyticsConnection;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
Could anyone let me know what is the mistake I am doing here and how can I rectify that.

SQL injections (java)

I am trying to figure out a way to see if the sql injection is correct based on the user input and if so, delete that row.
For instance the user enters 123 for an idNumber, if that number exits, the the sql statement "select * from student where idNumber = " + idNumber + ";" would be correct.
When it is verified that it is correct, I would then use another statement to delete the query.
My main issue is figuring out how to verify it is correct.
Thanks!
public static void CheckStudent(Connection con, String idNumber) throws SQLException {
Statement stmt = null;
String query = "select * from student where idNumber = " + idNumber + ";"
try {
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(query);
if (!rs.isBeforeFirst() ) {
//Here is where you do the check
System.out.println("No data");
}
} catch (SQLException e ) {
JDBCTutorialUtilities.printSQLException(e);
} finally {
if (stmt != null) { stmt.close(); }
}
}

How to update null cells of specific column with mode of that column ? (Sql using Java)

I used the following code to calculate mode of a column:
public void CalcCatValMean(String colName , String tableName){
Statement st = null;
String sql = null;
String mode = null;
try{
setConnection();
st = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
sql = "SELECT " + colName + " , Count(colName) AS Frequency FROM " + tableName + " GROUP BY " + colName + " HAVING Count(colName) >= ALL (SELECT Count(colName) FROM " + tableName + " GROUP BY " + colName + " )";
System.out.println("sql :" + sql);
ResultSet rset = st.executeQuery(sql);
CachedRowSet rowset = new CachedRowSetImpl();
rowset.populate(rset);
int i = 1;
while(rowset.next()) { // check if a result was returned
mode = rowset.getString(i); // get your result
System.out.println("mode is : " + mode);
i++;
}
//Clean-up environment
st.close();
closeConnection();
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
But the weird thing is that its' also calculating "null" as a value & giving output of following column as "null".
null
abc
null
null
xyz
What I want to do is to calculate mode of all values of that column except null and then update null cells of that column with calculated mode.

MySQL command SELECT values in column - JDBC

I'm using MySQL commands via JDBC (Java) to make changes to my database. I have implemented the following method to return the values of a column. The goal is to have the location in the column (row) correspond with their location in the array (index). This works with String columns, but with numerical columns, the ResultSet seems to place them in ascending order, thus making their positioning in the returned String array not reflect their positioning in the column. 'rs' is a ResultSet reference variable.
public String[] getColumnContents(String tableName, String columnName) {
String sql = "SELECT " + columnName + " FROM " + tableName;
String[] results = new String[SQLManager.getColumnLength(tableName, columnName)];
try {
rs = statement.executeQuery(sql);
for (int counter = 0; rs.next(); counter++) {
results[counter] = rs.getString(columnName);
}
} catch (SQLException e) {
e.printStackTrace();
}
return results;
}
It's as simple as adding an ORDER BY clause to the SQL command. Here's my working method:
public String[] getColumnContents(String tableName, String columnName) {
String sql = "SELECT " + columnName + " FROM " + tableName + " ORDER BY " + columnName1 + " ASC, " + columnName2 + " ASC";
String[] results = new String[SQLManager.getColumnLength(tableName, columnName)];
try {
rs = statement.executeQuery(sql);
for (int counter = 0; rs.next(); counter++) {
results[counter] = rs.getString(columnName);
}
} catch (SQLException e) {
e.printStackTrace();
}
return results;
}

Categories