I am trying to launch a class only if a select query returned at least a row.
My call to thequery function noted below:
results=thequery("SELECT `username`,`numberpoints` FROM `highscores` WHERE `username` = '"+name+"'");//send query that checks if username exist
if(!results.next()) {
BallTrial trial = new BallTrial();
}
thequery function:
public ResultSet thequery(String query){
PreparedStatement statement = null;
ResultSet rs = null;
Connection con=null;
Statement st=null;
try {
con=DriverManager.getConnection("jdbc:mysql://localhost/scores","root","");
statement = con.prepareStatement(query);
rs= statement.executeQuery();
while(rs.next()){
System.out.println(rs.getString(1)+" "+rs.getString(2));
return rs;
}}
catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("you have not accessed the data base");
}
return null;
}
I am getting a null pointer exception at if(!results.next()) {, can anyone clarify what is my mistake here?
You should add the null check condition before calling next, the condition needs to be tweaked something around the lines: results != null && !results.next()
You need to make a couple of changes:
From thequery method, return ResultSet (i.e. rs) instead of returning null. Returning null will cause NPE. Also, remove while(...) as it needs to be done by the caller, e.g.
public ResultSet thequery(String query){
PreparedStatement statement = null;
ResultSet rs = null;
Connection con=null;
Statement st=null;
try {
con=DriverManager.getConnection("jdbc:mysql://localhost/scores","root","");
statement = con.prepareStatement(query);
rs= statement.executeQuery();
return rs;
catch (SQLException e) {
e.printStackTrace();
System.out.println("you have not accessed the data base");
throw e;
}
}
In the caller method, check whether ResultSet contains any records by calling rs.next(), e.g.:
results = thequery(..)
if(!results.next()){
BallTrial trial = new BallTrial();
}
while(true) {
if (!results.next()){
System.out.prinln("result has no data");
}else{
System.out.prinln("result has some data");
}
}
Related
I am currently making a programme that communicates with an SQL database, after I make a query I obviously have to close the connections, I can close the connection fine, but I cannot close the actual statement itself. Is this necessary to close or does it close because it is a function of the connection itself? The code works perfectly fine I was just curious if this statement was needed. Here is the code, there error is highlighted towards the end of the returnEmployeeSalary function:
public class GroundControlToMajorTom {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
System.out.println(returnEmployeeSalary("ivy"));
}
public static String returnEmployeeSalary(String name) throws ClassNotFoundException, SQLException {
HashMap<String, String> infoHR = connectionInfoHR();
String query = "SELECT salary FROM employees WHERE first_name = '" + name + "'";
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection(infoHR.get("url"), infoHR.get("uname"), infoHR.get("pass"));
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(query);
rs.next();
String id = rs.getString("salary");
return id;
st.close(); /////////// ERROR IS HERE /////////////
con.close();
}
public static HashMap<String, String> connectionInfoHR() {
HashMap<String, String> infoHR = new HashMap();
infoHR.put("url", "jdbc:mysql://localhost:3306/sql_hr");
infoHR.put("uname", "root");
infoHR.put("pass", "");
return infoHR;
}
}
The problem is that you have statements after the return statement. Given return ends the normal flow of a method, the subsequent close methods aren't executed.
However, your code doesn't take into account abrupt exits of a method through an exception. In such situation, you won't properly close resources like statements and connections.
The appropriate solution is to use try-with-resources. Your code would then look like:
try (Connection con = DriverManager.getConnection(infoHR.get("url"), infoHR.get("uname"), infoHR.get("pass"));
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(query);) {
rs.next();
return rs.getString("salary");
}
At the end of the try-with-resources block, the result set, statement and connection will be closed, in the right order, even if closing of one of these fails.
You need to close your resultSet ,statement then your database connection to release all resources from the database.
try this :
Connection connection = DriverManager.getConnection(infoHR.get("url"), infoHR.get("uname"), infoHR.get("pass"));
try {
Statement statement = connection.createStatement();
try {
ResultSet resultSet = statement.executeQuery(query);
try {
rs.next();
return rs.getString("salary");
} finally {
resultSet.close();
}
} finally {
statement.close();
}
} finally {
connection.close();
}
You could follow this article for more information :
How to Close JDBC Resources Properly – Every Time
Update :
Since Java 7 you could use this :
try (Connection connection = DriverManager.getConnection(infoHR.get("url"), infoHR.get("uname"), infoHR.get("pass"));
Statement statement = connection.createStatement()) {
try (ResultSet resultSet = statement.executeQuery(query)) {
rs.next();
return rs.getString("salary");
}
}
This is a method to add a new planet to an observablelist of customers.
I am wondering if I am using the try with resources correctly and if the auto-close is working.
public static Customer addPlanet(Customer customer) {
String query1 = "Select * from planet where planet=? AND universeID=?";
String query2 = "INSERT INTO planet (planet,universeID) VALUES(?,?)";
try (PreparedStatement statement = (PreparedStatement) Database.connection.prepareStatement(query1);
PreparedStatement statement2 = (PreparedStatement) Database.connection.prepareStatement(query2)) {
statement.setString(1, customer.getPlanet());
statement.setString(2, Integer.toString(customer.getUniverseID()));
try (ResultSet rs = statement.executeQuery()) {
if (rs.next()) {
int planetId = rs.getInt(1);
customer.setPlanetID(planetId);
return customer;
} else {
statement2.setString(1, customer.getPlanet());
statement2.setInt(2, customer.getUniverseID());
statement2.executeUpdate();
return addPlanet(customer);
}
} catch (SQLException e) {
e.printStackTrace();
return null;
}
} catch (SQLException e) {
e.printStackTrace();
}
return customer;
}
My question is, does this part need to be enclosed in a try-catch block or does it get closed automatically.
statement2.executeUpdate();
It gets closed. Anything in the try gets closed at the end if they are AutoCloseable.
I have DAO class with methods getting and sending data.
I'm catching Exceptions inside SQL requests, so I need to declare connection variables outside of try parenthesis.
every method looks lookes like this:
public Role getRole(int roleId) {
Connection connection = null;
ResultSet rs = null;
PreparedStatement statement = null;
Role role = null;
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement("select ROLE_ID, ROLE_TEXT from ROLES WHERE ROLE_ID = :1");
statement.setInt(1, roleId);
rs = statement.executeQuery();
rs.next();
role = roleMapper.mapRow(rs, 1);
} catch (SQLException e) {
} finally {
JdbcUtils.closeResultSet(rs);
JdbcUtils.closeStatement(statement);
JdbcUtils.closeConnection(connection);
return role;
}
}
But there's problem. Finbugs giving me an error, saying:
Load of known null value in DAO.getRole
and
may fail to clean up java.sql.Statement
So what should I do to avoid that?
The getRole can return null.
Furthermore:
if (rs.next()) {
role = roleMapper.mapRow(rs, 1);
}
I prefer another notation. And the error solution unfortunately consists of either letting getRole throw an exception (best) or letting return an Optional<Role>
//public Role getRole(int roleId) throws SQLException {
public Optional<Role> getRole(int roleId) {
try (Connection connection = dataSource.getConnection();
PreparedStatement statement =
connection.prepareStatement(
"select ROLE_ID, ROLE_TEXT from ROLES WHERE ROLE_ID = :1")) {
statement.setInt(1, roleId);
try (ResultSet rs = statement.executeQuery()) {
if (rs.next()) {
return roleMapper.mapRow(rs, 1);
}
}
} catch (SQLException e) { //
Logger.getLogger(getClass().getName()).log(Level.SEVERE, "ID: " + roleId, e); //
}
return Optional.empty(); //
}
I need help with the code below and getting it to return a true or false value. Any and all help would be appreciated.
public synchronized static boolean checkCompanyName(String companyName,
Statement statement) {
try {
ResultSet res = statement
.executeQuery("SELECT `companyName` FROM `companys` WHERE companyName = '"
+ companyName + "';");
boolean containsCompany = res.next();
res.close();
return containsCompany;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
Try to make your query like this:
ResultSet res = statement.executeQuery("SELECT companyName FROM companys WHERE companyName = " + companyName);
Or you can either you PreparedStatement which is better then you did before
You should be using a PreparedStatement (for that end pass the Connection in to the method). Also, you should retrieve the value from the ResultSet and validate it matches your companyName. Something like
static final String query = "SELECT `companyName` FROM "
+ "`companys` WHERE companyName = ?";
public synchronized static boolean checkCompanyName(String companyName,
Connection conn) {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(query);
ps.setString(1, companyName);
rs = ps.executeQuery();
if (rs.next()) {
String v = rs.getString(1);
return v.equals(companyName);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
}
}
}
return false;
}
Two comments:
You only need to check if there's at least one row matching your criteria, so you can use .first()
Your code is vulnerable to SQL Injection attacks. Please read this to learn more about it.
The easiest way to avoid SQL injection attacs is to use prepared statements. So let me strike two birds with a single stone and give you a solution using them:
/*
Check if the company exists.
Parameters:
conn - The connection to your database
company - The name of the company
Returns:
true if the company exists, false otherwise
*/
public static boolean checkCompanyName(Connection conn, String company) {
boolean ans = false;
try(PreparedStatement ps = conn.prepareStatement(
"select companyName from companies where companyName = ?"
) // The question mark is a place holder
) {
ps.setString(1, company); // You set the value for each place holder
// using setXXX() methods
try(ResultSet rs = ps.executeQuery()) {
ans = rs.first();
} catch(SQLException e) {
// Handle the exception here
}
} catch(SQLException e) {
// Handle the exception here
}
return ans;
}
Suggested reads:
Bobby Tables: A guide to preventing SQL injection
The Java Tutorials - JDBC: Using prepared statements
In the following code, I execute a query on a SQLite JDBC connection via the executeRestitutionalQuery(String query) method:
public static ArrayList<Metadata> findMetadata(String name, String text, String after, String before, String repPath)
throws SQLException, ClassNotFoundException {
ArrayList<Metadata> data = new ArrayList<Metadata>();
boolean needADD = false;
String query = "SELECT * from " + TABLE_NAME_METADATA;
...
query += " ORDER BY timestamp DESC;";
ResultBundle bundle = executeRestitutionalQuery(query);
ResultSet result = bundle.getResultSet();
while(result.next()){
Metadata metadata = new Metadata(result.getLong("id"), result.getString("name"), Timestamp.valueOf(result.getString("timestamp")),
result.getInt("filesNo"), result.getLong("size"), result.getString("description"), -1);
data.add(metadata);
}
closeStatementAndResultSet(bundle.getStatement(), bundle.getResultSet());
return data;
}
private static ResultBundle executeRestitutionalQuery(String query) throws SQLException, ClassNotFoundException{
Connection connection = null;
Statement statement = null;
ResultSet result = null;
ResultBundle bundle = null;
try{
connection = getConnection();
statement = connection.createStatement();
statement.executeUpdate(query);
connection.commit();
result = statement.executeQuery(query);
bundle = new ResultBundle(statement, result);
}finally{
if(connection != null){
try{
connection.close();
}catch (Exception e){
/* ignored */
}
}
}
return bundle;
}
private static void closeStatementAndResultSet(Statement statement, ResultSet result){
if(result != null){
try{
result.close();
}catch (Exception e){
// ignored
}
}
if(statement != null){
try{
statement.close();
}catch (Exception e){
// ignored
}
}
}
The ResultBundle class is just used to summarize the resultset and the statement. It looks like this:
public class ResultBundle {
private final Statement statement;
private final ResultSet result;
public ResultBundle(Statement statement, ResultSet result){
this.result = result;
this.statement = statement;
}
public Statement getStatement(){
return statement;
}
public ResultSet getResultSet(){
return result;
}
}
The problem is, that every call to result.getLong(), result.getString() etc. returns null resp. 0. I can't understand why. The queries should all be okay, as the code was running fine before I had to do some refactoring. Could the problem arise from the ResultBundle-class? What am I not seeing here?
Statements and ResultSets are "live" objects, living only as long as their connection. The executeRestitutionalQuery returns a ResultBundle, whose result and statement members are implicitly closed on return when the connection is closed in the finally block.
try {
...
}finally{
if(connection != null){
try{
connection.close(); // <---- here's the problem
}catch (Exception e){
/* ignored */
}
}
}
By the time, the caller of executeRestitutionalQuery can lay its hand on the resource bundle, the connection has been closed, and the result set is "dead".
I would say this is a bad design.
A better one would keep the SQL objects in tight scope, map results into a collection or object and immediately close all those scarce resources. Not only will the data be available to clients, but you'll avoid nasty problems with connection and cursors exhausted. It'll scale better, too.