I'm currently having a very strange problem with GWT and SQL.
I'm trying to get my GWT program to communicate with my SQL server. I took several examples from the web and they would all terminate with the following error:
SEVERE: No suitable driver found for jdbc:mysql://localhost:3306/table
java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/table
After racking my brain for hours and hours, I finally came up with the following code which DOES work. Running the following will happily output the MySQL version to the console:
public static void printVersion() {
Connection con = null;
Statement st = null;
ResultSet rs = null;
String url = "jdbc:mysql://localhost:3306/table";
String user = "username";
String password = "password";
try {
con = DriverManager.getConnection(url, user, password);
st = con.createStatement();
rs = st.executeQuery("SELECT VERSION()");
if (rs.next()) {
System.out.println(rs.getString(1));
}
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(Version.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
} finally {
try {
if (rs != null) {
rs.close();
}
if (st != null) {
st.close();
}
if (con != null) {
con.close();
}
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(Version.class.getName());
lgr.log(Level.WARNING, ex.getMessage(), ex);
}
}
}
However, as soon as I changed the method slightly from outputting the string to the console to returning the string to a calling function, I started getting the "No suitable driver found" error again.
The change I made was extremely subtle; Here is the diff:
1c1
< public static String getVersion() {
---
> public static void printVersion() {
10d9
< String rtn = null;
18c17
< rtn = rs.getString(1);
---
> System.out.println(rs.getString(1));
42d40
< return rtn;
The calling function simply changed from an Version.printVersion() to String str = Version.getVersion().
I'm fairly experienced in PHP and am just making the jump to GWT/Java. I searched all over and haven't been able to find out why this isn't working like it should. Numerous tutorials and pre-existing code have failed me, so I'm asking here.
I do have the MySQL JDBC driver in my classpath, and I have tried several permutations loading it with Class.forName("com.mysql.jdbc.Driver").newInstance();, but to no avail
I'm sure I'm missing something really stupid, but I'm too inexperienced to have any clue what.
I honestly don't know why the Class.forName("com.mysql.jdbc.Driver").newInstance(); wasn't working before. I tried several methods with that and none of them worked. (I have since deleted my non-working work, so I can't compare why it didn't work) I did try it in this example just now though and it does appear to work when added. Here is the diff:
1c1
< public static String getVersion() {
---
> public static void printVersion() {
10d9
< String rtn = null;
13d11
< Class.forName("com.mysql.jdbc.Driver").newInstance();
19c17
< rtn = rs.getString(1);
---
> System.out.println(rs.getString(1));
43d40
< return rtn;
Basically just add the Class.forName("com.mysql.jdbc.Driver").newInstance(); right before you initialize the connection.
I have absolutely ZERO idea why it would work without that statement if I'm just printing the output but wouldn't work if I was returning the output. Mega bonus-points to whoever can describe that to me.
Edit:
Borked the diff - you need to add exception handlers for InstantiationException, IllegalAccessException and ClassNotFoundException as well. Your IDE should prompt you of this though.
Related
I'm facing an issue where I have a java application running on a server, and it starts growing in memory until eventually the server cannot handle it anymore.
This is some sort of memory leak / resource leak problem, which I thought was extremely rare in Java due to the garbage collection. I guess something is being referenced and never used, so the garbage collector does not collect it.
The problem is that the size in memory grows so slowly that I'm not able to debug it properly (it may take two weeks to make the server unusable).
I'm using java + mysql-connector, and I'm sure the memory leak is caused by something related to the database connection.
Here is how I connect to the database:
private static Connection connect(){
try {
Connection conn = null;
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/database","client","password");
return conn;
}catch(SQLException ex){
System.out.println("SQLException: " + ex.getMessage());
System.out.println("SQLState: " + ex.getSQLState());
System.out.println("VendorError: " + ex.getErrorCode());
return null;
}
}
public static Connection getConnection(){
try {
if (connection == null || connection.isClosed()) connection = connect();
return connection;
}catch (SQLException exception){
System.out.println("exception trying to connect to the database");
return null;
}
}
I can't find any possible problem here, but who knows!
Here's how I retrieve information from the database:
public void addPoints(long userId,int cantidad){
try {
if(DatabaseConnector.getConnection()!=null) {
PreparedStatement stm = DatabaseConnector.getConnection().prepareStatement("UPDATE users SET points = points + ? WHERE id = ? ");
stm.setLong(2, userId);
stm.setInt(1, cantidad);
if(stm.executeUpdate()==0){ //user doesn't have any point records in the database yet
PreparedStatement stm2 = DatabaseConnector.getConnection().prepareStatement("INSERT INTO users (id,points) VALUES (?,?)");
stm2.setLong(1, userId);
stm2.setInt(2, cantidad);
stm2.executeUpdate();
}
}
}catch (SQLException exception){
System.out.println("error recording points");
}
}
public ArrayList<CustomCommand> getCommands(long chatId) throws SQLException{
ArrayList<CustomCommand> commands = new ArrayList<>();
if(DatabaseConnector.getConnection() != null) {
PreparedStatement stm = DatabaseConnector.getConnection().prepareStatement("SELECT text,fileID,commandText,type,probability FROM customcommands WHERE chatid = ?");
stm.setLong(1, chatId);
ResultSet results = stm.executeQuery();
if(!results.isBeforeFirst()) return null;
while (results.next()){
commands.add(new CustomCommand(results.getString(1),results.getString(2),results.getString(3), CustomCommand.Type.valueOf(results.getString(4)),results.getInt(5)));
}
return commands;
}
return null;
}
Maybe the problem is something related to exception catching and statements not being correctly executed? Maybe something related to result sets?
It's driving me crazy. Thanks for helping me!
You do nothing to clean up ResultSet and Statement before you return. That's a bad idea. You should be closing each one in individual try/catch blocks in a finally block.
A ResultSet is an object that represents a database cursor on the database. You should close it so you don't run out of cursors.
I wouldn't have a single static Connection. I'd expect a thread-safe, managed pool of connections.
I wouldn't return a null. You don't make clear what the user is supposed to do with that. Better to throw an exception.
I have no idea what wrong is with my sample code, I've followed all instructions on multiple YouTube videos and other online sources. I just can't fix it. Could someone explain what is the problem and how to solve it? All the required lib's are already added.
I have made sure all the libraries are correctly installed, Yet it still does not find the driver.
This is my code
public boolean checkLogin(String username, String password) {
try {
Connection myconObj;
Class.forName("net.ucanaccess.jdbc.UcanaccessDriver");
URL databaseLocation = this.getClass().getResource("/com/vanstryp/database/MainUserData.accdb");
myconObj = DriverManager.getConnection("jdbc:ucanaccess:/" + databaseLocation);
ResultSet result;
Statement stmt = conn.createStatement();
String query = "select * from MainUserData";
result = stmt.executeQuery(query);
while (result.next()) {
String dbUsername = result.getString("Username");
String dbPassword = result.getString("Password");
System.out.println();
if (username.equalsIgnoreCase(dbUsername) && password.equals(dbPassword)) {
PrintWriter activeUser = new PrintWriter(new FileWriter("activeUser.db"));
activeUser.println(dbUsername);
activeUser.close();
return true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
This is the error message:
java.sql.SQLException: No suitable driver found for jdbc:ucanaccess:/file:/C:/Users/Jaco%20van%20Stryp/Dropbox/Fitness%20Perfect/build/classes/com/vanstryp/database/MainUserData.accdb
java.sql.SQLException: No suitable driver found for jdbc:ucanaccess:/file:/C:/Users/Jaco%20van%20Stryp/Dropbox/Fitness%20Perfect/build/classes/com/vanstryp/database/MainUserData.accdb
A UCanAccess connection URL must begin with jdbc:ucanaccess:// followed by the path to the database file. Your connection URL begins with jdbc:ucanaccess:/ (only one slash) and it also includes the spurious file: designator. It should look more like this:
jdbc:ucanaccess://C:/path/to/database/file.accdb
I'm struggling with a Tomcat connection pool error.The below error is thrown at runtime after running a simple stored procedure that generates a String value.
WARNING: Connection has been abandoned PooledConnection[ConnectionID:45 ClientConnectionId: 7817280c-3f7e-4239-a009-3aedd0a855e8]:java.lang.Exception
at org.apache.tomcat.jdbc.pool.ConnectionPool.getThreadDump(ConnectionPool.java:1096)
at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:799)
at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:648)
at org.apache.tomcat.jdbc.pool.ConnectionPool.getConnection(ConnectionPool.java:200)
at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:128)
at util.ThreadLocalUtil.getConnection(ThreadLocalUtil.java:55)
at webapp.dao.WebApplicationDAO.getConnection(WebApplicationDAO.java:30)
at webapp.dao.AccountDAO.generateAccountId(AccountDAO.java:827)
at webapp.bo.Account.generateUserAccountId(Account.java:285)
at webapp.actions.AddUserAccountUNZAction.execute(AddUserAccountUNZAction.java:79)
at org.apache.struts.chain.commands.servlet.ExecuteAction.execute(ExecuteAction.java:58)
at org.apache.struts.chain.commands.AbstractExecuteAction.execute(AbstractExecuteAction.java:67)
at org.apache.struts.chain.commands.ActionCommandBase.execute(ActionCommandBase.java:51)
My knowledge of that error is that a connection was opened and not closed. The connection is opened when running the stored proc in the account dao. Below is the block of code which calls the stored procedure.
Connection conn = null;
CallableStatement stmt = null;
ResultSet rs = null;
try {
conn = getConnection();
stmt = conn.prepareCall(sqlWebAppGenerateUserId);
stmt.setString(1, base);
rs = stmt.executeQuery();
String res = null;
if (rs.next()) {
res = rs.getString(1);
}
if (res == null) {
throw new RuntimeException("Failed to generate user id.");
}
return res;
} catch (SQLException e) {
LOG.error("{}", e);
throw new RuntimeException(e);
}finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
LOG.error(e.getMessage(), e);
}
}
if (rs != null) {
try {
rs.close();
conn.close();
} catch (SQLException e) {
LOG.error(e.getMessage(), e);
}
}
}
As you can see, I'm using a finally block to close the connection etc.
I'm at a loss to explain the reason why the error is being thrown still and as to how I can debug and solve this issue. Any help would be greatly appreciated
You close conn only if rs != null, meaning that every time a query fails the connection won't be closed.
I also recommend switching to try-with-resources instead of writing clumsy finally blocks which may cause bugs.
What #Kayaman said. Also if the statement execution takes longer than removeAbandonedTimeout this can happen.
#Kayaman and #Gorazd thank you for the advice. The issue with down to missing jar files in the tomcat lib folder. More specifically mail-1.4.jar.
As this jar file was missing, a function that sends emails failed. Previous to the call to send the mail, connection.autocommit is set to true. After the mail sends it will set autocommit back to false. This to me looks like where the abandoned error was occurring from.
When looking through logs file I found the mail sending error. This was in actual fact the true error whereas the abandoned error can be looked at as a red herring.
I have the code that successfully establishes a connection to a mySQL database.
String email, password; //assume these are already loaded with user-entered data.
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
return false;
}
Connection conn = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/main", "root", "password123");
} catch (SQLException e) {
return false;
}
//perform my database actions here///////////////
///////////////////////////////////////////////////
try {
conn.close();
} catch (SQLException e) {
return false;
}
I have a couple of strings in the scope of the code above that already have the email and password entered by a user on a login page. I need to look through the database for a matching email address and then verify that the password matches what the user entered in the form.
My table has 3 columns: id, email, and password.
I have pushed two rows into the table using the sql workbench
1 | email#gmail.com | password1
2 | email2#gmail.com | password2
I'm assuming in pure SQL I have to do something like
SELECT * FROM users WHERE email LIKE 'email#gmail.com' AND password LIKE 'password1';
But I'm not quite sure how to actually send these SQL commands to the database and receive info back using JSP. Also, I'm not entirely sure my SQL logic is the ideal way to verify a password. My thinking with the SQL command above was that if the database finds any row that meets the conditions, then the email/password combination are verified. Not sure if this is a great way to do it though. I'm not looking for the most secure and complicated way, I'm just looking for the simplest way that makes sense at the moment. Every tutorial I find seems to do it differently and I'm a bit confused.
Here's an example you can use from something I've worked on (I'm assuming that the connection "conn" is obvious):
PreparedStatement st = null;
ResultSet rec = null;
SprayJobItem item = null;
try {
st = conn.prepareStatement("select * from sprayjob where headerref=? and jobname=?");
st.setString(1, request.getParameter("joblistref"));
st.setString(2, request.getParameter("jobname"));
rec = st.executeQuery();
if (rec.next()) {
item = new SprayJobItem(rec);
}
} catch (SQLException ex) {
// handle any errors
ReportError.errorReport("SQLException: " + ex.getMessage());
ReportError.errorReport("SQLState: " + ex.getSQLState());
ReportError.errorReport("VendorError: " + ex.getErrorCode());
} catch (Exception ex) {
ReportError.errorReport("Error: " + ex.getMessage());
} finally {
// Always make sure result sets and statements are closed,
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
;
}
ps = null;
}
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
;
}
rs = null;
}
}
In your case instead of item = new SprayJobItem(rec);
you would have code that notes that the user is valid as the record has been found.
I have a web service method to compare templates, however it does not perform the code in the if else statement found in the try catch block instead it returns the last return statment which says "error". Any idea what am doing wrong? It was supposed to return "finger was verified" or "finger was NOT verified".
#WebMethod(operationName = "verify")
public String verify(#WebParam(name = "name") String name, #WebParam(name = "ftset") String ftset) {
Connection con = null;
String dbTemplate = null;
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/biodb", "root", "1234");
PreparedStatement st;
st = con.prepareStatement("select template from info where name = ? ");
st.setString(1, name);
ResultSet result = st.executeQuery();
if (result.next()) { //.next() returns true if there is a next row returned by the query.
dbTemplate = result.getString("template");
byte[] byteArray = new byte[1];
byteArray = hexStringToByteArray(dbTemplate);
DPFPTemplate template = DPFPGlobal.getTemplateFactory().createTemplate();
template.deserialize(byteArray);
byte[] fsArray = new byte[1];
fsArray = hexStringToByteArray(ftset);
DPFPFeatureSet features = null;
features.deserialize(fsArray);
DPFPVerification matcher = DPFPGlobal.getVerificationFactory().createVerification();
DPFPVerificationResult fresult = matcher.verify(features, template);
if (fresult.isVerified()) {
return "The fingerprint was VERIFIED.";
} else {
return "The fingerprint was NOT VERIFIED.";
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
if (con != null) {
try {
con.close();
} catch (SQLException e) {
}
}
}
return "error";
}
Any idea what am doing wrong?
Well, the behaviour you've described is what will happen if an exception is thrown, due to this:
catch (Exception e) {
System.out.println(e.getMessage());
}
If anything goes wrong, you write something to System.out (which presumably you're not looking at, otherwise you'd have seen what's happened) and continue by returning "error".
To start with, I'd recommend catching specific exceptions - and change how you're logging the exception so that it's more obvious in your diagnostics.
Additionally, you'll get this behaviour if result.next() returns false. This isn't clear from the code you've posted, due to the lack of consistent indentation. You should definitely fix the indentation - readability is absolutely crucial.
Next, work out what you want to happen if result.next() returns false. Is that an error? Should it actually just return the "not verified" case?