I'm working on an application that records do my MySql database on my server. Every time I want to use the database, get the existing connection, if not, I think for the first time. When I do an insert or select, works very well, but followed that consultation, when it ends, I can never regain the connection and do not return to consultations.
My class of Database
public class Database {
/**
* Gets just one instance of the class
* Connects on construct
* #returns connection
*/
private Connection _conn = null;
private long timer;
//singleton code
private static Database DatabaseObject;
private Database() {}
public static Database connect() {
if (DatabaseObject == null)
DatabaseObject = new Database();
return DatabaseObject._connect();
}
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
//end singleton code
/**
* Connects with the defined parameters on Config
* Prevents re-connection if object was already connected
* #throws SQLException
*/
private Database _connect() {
try {
if (this._conn == null || !this._conn.isValid(0)) {
try {
Class.forName("com.mysql.jdbc.Driver");
Properties connProps = new Properties();
connProps.put("user", Config.Config.DB_USER);
connProps.put("password", Config.Config.DB_PASS);
this._conn = DriverManager.
getConnection("jdbc:" + Config.Config.DB_DBMS + "://" + Config.Config.DB_HOST + ":"
+ Config.Config.DB_PORT + "/" + Config.Config.DB_NAME, Config.Config.DB_USER, Config.Config.DB_PASS);
timer = System.currentTimeMillis();
} catch (ClassNotFoundException e) {
System.out.println("Where is your MySQL JDBC Driver?");
e.printStackTrace();
} catch (Exception e) {
System.out.println("Could not connect to DB");
e.printStackTrace();
}
} else {
try {
long tmp = System.currentTimeMillis() - timer;
if (tmp > 1200000) { //3600000 one hour ; 1200000 twenty minutes
System.out.println("Forcing reconnection ("+tmp+" milliseconds passed since last connection)");
this.close();
this._connect();
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("Forcing reconnection");
this._conn = null;
this._connect();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return this;
}
/**
* Closes connections
* This has to be invoked when database connection is no longer needed
* #throws SQLException
*/
public void close() throws SQLException {
if (this._conn != null) {
this._conn.close();
this._conn = null;
}
}
/**
* Getter for connection
* #return
*/
public Connection get() {
return this._conn;
}
}
The following function I make a query:
private Statement sment = null;
private PreparedStatement psment = null;
private ResultSet rset = null;
public boolean existsByNameAndUserId(String md5, int userId, int eventId) {
Connection conn = Database.connect().get();
try {
psment = conn.prepareStatement("SELECT * FROM files "
+ "WHERE user_id = ? AND md5 = ? AND evento_id = ?");
psment.setInt(1, userId);
psment.setString(2, md5);
psment.setInt(3, eventId);
rset = psment.executeQuery();
if (rset.next()) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
private void close() {
try { if (rset != null) rset.close(); } catch (Exception e) {System.out.println(e.getMessage());};
try { if (psment != null) psment.close(); } catch (Exception e) {System.out.println(e.getMessage());};
try { if (sment != null) sment.close(); } catch (Exception e) {System.out.println(e.getMessage());};
}
And in the next, I call the above function to find out whether or not a record with these characteristics, if not, I do an insert.
String SQL_INSERT = "INSERT INTO files (evento_id, user_id, path, thumb, preview, width, height, md5, numero_corredor, created, modified) "
+ "VALUES (?,?,?,?,?,?,?,?,?,NOW(),NOW())";
public void save(List<components.File.Schema> files) throws SQLException {
try (
Connection conn = Database.connect().get();
PreparedStatement statement = conn.prepareStatement(SQL_INSERT);
) {
int i = 0;
for (components.File.Schema file : files) {
if(!existsByNameAndUserId(file.getMd5(), file.getUserId(), file.getEventId())){
statement.setInt(1, file.getEventId());
statement.setInt(2, file.getUserId());
statement.setString(3, file.getPath());
statement.setString(4, file.getPreview());
statement.setString(5, file.getThumb());
statement.setInt(6, file.getWidth());
statement.setInt(7, file.getHeight());
statement.setString(8, file.getMd5());
statement.setString(9, null);
statement.addBatch();
i++;
if (i % 1000 == 0 || i == files.size()) {
statement.executeBatch(); // Execute every 1000 items.
}
}
}
}
}
Your issue is due to the fact that you put Connection conn = Database.connect().get() in a try-with-resources statement which is what you are supposed to do but it closes your connection and when you call it again as the method _connect() doesn't have a valid test, it doesn't create a new connection. The valid test is this._conn == null || !this._conn.isValid(0), indeed in your original test you call this._conn.isValid(0) which will returns false in our context since the connection is closed so it won't create a new connection which is not what we want here.
Response Update: The second part of the problem is the fact that in the save method you call existsByNameAndUserId which closes the current connection, you should only close the statement and let the method save close the connection.
Related
To get an idea of what the basic structure looks like, I downloaded a money system including MySQL from Spigot and looked at the code.
public static boolean playerExists(String uuid) {
try {
ResultSet rs = Simplecoinsystem.mysql.query("SELECT * FROM CoinData WHERE UUID= '" + uuid + "'");
if (rs.next())
return (rs.getString("UUID") != null);
return false;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
public static void createPlayer(String uuid) {
if (!playerExists(uuid))
Simplecoinsystem.mysql.update("INSERT INTO CoinData (UUID, COINS) VALUES ('" + uuid +
"', '" + Simplecoinsystem.getInstance().getConfig().getInt("startcoins") + "');");
}
public static Integer getCoins(String uuid) {
Integer i = Integer.valueOf(0);
if (playerExists(uuid)) {
try {
ResultSet rs = Simplecoinsystem.mysql.query("SELECT * FROM CoinData WHERE UUID= '" + uuid + "'");
if (rs.next())
Integer.valueOf(rs.getInt("COINS"));
i = Integer.valueOf(rs.getInt("COINS"));
} catch (SQLException e) {
e.printStackTrace();
}
} else {
createPlayer(uuid);
}
return i;
}
public static void setCoins(String uuid, Integer coins) {
if (playerExists(uuid)) {
Simplecoinsystem.mysql.update("UPDATE CoinData SET COINS= '" + coins + "' WHERE UUID= '" + uuid + "';");
} else {
createPlayer(uuid);
}
}
Am I correct that it is actually impractical to create a new entry with the uuid of the non-existent player after each query of the coins if the player does not exist?
Wouldn't this make it possible to flood the database with thousands of unnecessary entries by issuing, for example, a "/money (player)" command as an evil player/admin?
Couldn't I just ask when entering the server if the uuid is already stored and if not, just enter it? This way there would only be entries from players who have already been on the server before. Whether this needs great server performance, I'm not sure.
This is my first own MySQL class.
public class MySQL {
private String host, database, user, password;
private int port;
private Connection con;
public MySQL(String host, int port, String database, String user, String password) {
this.host = host;
this.port = port;
this.database = database;
this.user = user;
this.password = password;
connect();
}
public void connect() {
try {
con = DriverManager.getConnection("jdbc:mysql://" + host + ":" + port + "/" + database + "?autoReconnect=true", user, password);
System.out.println("&cDie MySQL Verbindung wurde erfolgreich aufgebaut!");
} catch (SQLException e) {
e.printStackTrace();
}
}
public void disconnect() {
try {
if(this.con != null) {
this.con.close();
System.out.println("§cDie MySQL Verbindung wurde erfolgreich beendet!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void update(String query) {
try {
Statement st = con.createStatement();
st.executeUpdate(query);
st.close();
} catch (Exception e) {
e.printStackTrace();
connect();
}
}
public ResultSet qry(String query) {
ResultSet rs = null;
try {
Statement st = con.createStatement();
rs = st.executeQuery(query);
} catch (Exception e) {
e.printStackTrace();
connect();
}
return rs;
}
public Connection getConnection() {
return this.con;
}
}
Except for this part, both MySQL classes are built relatively the same.
This is the part that is in the MySQL class of the Spigot plugin.
Your code have multiple issues.
When the connection will be closed, next time you will have an error. In your Mysql class, I suggest you to do:
public Connection getConnection() {
if(con == null || con.isClosed())
connect();
return con;
}
Then, use it in all method like getConnection().prepareStatement().
You can be attacked with SQL Injection. To fix this, try to do something like:
PreparedStatement st = con.prepareStatement("SELECT * FROM CoinData WHERE UUID = ?");
st.setString(1, uuid.toString()); // Yes it start at 1 !!
st.executeUpdate();
With this, even with all values, you can't be attacked with injections.
You will have an error while getting coins:
if (rs.next()) // go to good line
Integer.valueOf(rs.getInt("COINS")); // useless convertion
i = Integer.valueOf(rs.getInt("COINS")); // error if no line.
You can just do:
if(rs.next())
i = rs.getInt("COINS");
If the column "UUID" is unique, you will not have duplicated lines.
Finally, about performance, it's better to do it one time: at login, instead of all time. You can also create an object stored in an hashmap to easier access to it, without using SQL, like that:
public static HashMap<UUID, Integer> coinsByPlayer = new HashMap<>();
OR:
public static HashMap<UUID, MyObject> coinsByPlayer = new HashMap<>();
public class MyObject {
private int coins = 0;
public MyObject(UUID uuid) {
// make SQL request to get data
}
public int getCoins() {
return coins;
}
public void setCoins(int next){
coins = next;
// here make "UPDATE" sql query
}
}
What do you say? Is it ok with the try/catch function? #Elikill58
public Connection getConnection() {
try {
if(con == null || con.isClosed()) {
connect();
}
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
edit:
public Connection getConnection_one() throws SQLException {
if(con == null || con.isClosed()) {
connect();
return con;
} else {
return con;
}
}
So I'm trying to create a discord bot that has simple access to a database for printing out values, my code currently will print the values to the discord server but it repeats them 5 times.
Bot functionality class:
private MySQLAccess sql = new MySQLAccess();
public static void main(String[] args) throws Exception {
JDABuilder ark = new JDABuilder(AccountType.BOT);
ark.setToken("insert_discord_token_here");
ark.addEventListener(new MessageListener());
ark.buildAsync();
}
#Override
public void onMessageReceived(MessageReceivedEvent e) {
if (e.getAuthor().isBot()) return;
Message msg = e.getMessage();
String str = msg.getContentRaw();
//Ping pong
if (str.equalsIgnoreCase("!ping")) {
e.getChannel().sendMessage("Pong!").queue();
}
//Bal check
if (str.contains("!bal")) {
String user = str.substring(5);
System.out.println(user);
try {
sql.readDataBase(e.getChannel(), user);
} catch (Exception e1) {
}
}
}
Database Access Class:
private Connection connect = null;
private Statement statement = null;
private ResultSet resultSet = null;
private final String user = "pass";
private final String pass = "user";
public void readDataBase(MessageChannel msg, String username) throws Exception {
//Retrieve data and search for username
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connect = DriverManager.getConnection("jdbc:mysql://localhost/serverusers?allowPublicKeyRetrieval=true&useSSL=false", user, pass);
statement = connect.createStatement();
resultSet = statement
.executeQuery("select * from serverusers.userinfo where user=\"" + username + "\"");
writeResultSet(resultSet, msg);
} catch (Exception e) {
throw e;
} finally {
close();
}
}
private void writeResultSet(ResultSet resultSet, MessageChannel msg) throws SQLException {
// Check resultSet and print its contents
if (resultSet.next()) {
String user = resultSet.getString(2);
Double website = resultSet.getDouble(3);
msg.sendMessage("User: " + user).queue();
msg.sendMessage("Bank Amount: " + website).queue();
}
}
private void close() {
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (resultSet != null) {
resultSet.close();
}
if (connect != null) {
connect.close();
}
} catch (Exception e) {
}
}
When the program is run it finds the correct data that I'm looking for and the search function is fine, but for some odd reason the program will spit the same username and balance out 5 times.
Screenshot of Discord Bot
The common mistake here is that you run the program multiple times, each instance then responds accordingly with the same thing. You can check if that is the case by opening the task manager and looking for java processes. This often occurs with developers using the Eclipse IDE because of the console hiding other processes behind a drop-down menu on the console.
My error:
java.sql.SQLException: Listener refused the connection with the following error:
ORA-12516, TNS:listener could not find available handler with matching protocol
stack
The Connection descriptor used by the client was:
//10.2.5.21:9001/XE
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java
:112)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java
:261)
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:387)
at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:
414)
at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:165)
at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtensio
n.java:35)
at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:801)
at oracle.jdbc.pool.OracleDataSource.getPhysicalConnection(OracleDataSou
rce.java:297)
at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java
:221)
at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java
:165)
at utilityService.DB_util.setOracleConnectionActive(DB_util.java:99)
at utilityService.DB_util.getRecPreparedAuthentication(DB_util.java:124)
My common db connection class:
package utilityService;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import oracle.jdbc.pool.OracleDataSource;
public class DB_util {
String propValue = "";
ResultSet rec = null;
Statement stm = null;
PreparedStatement pre_stm = null;
CallableStatement call_stm = null;
Connection conn1 = null;
/**
* Constructure to get oracle connection
*/
public DB_util() {
Util util=new Util();
propValue=util.getFilePathToSave();
//propValue = Util.propValue;// get oracle connection
setOracleConnectionActive();
}
/**
* Close all oracle connections and result sets.
*/
public void setOracleConnectionClose() {
try {
if (conn1 != null || !conn1.isClosed()) {
if (rec != null) {
rec.close();
rec = null;
}
if (stm != null) {
stm.close();
stm = null;
}
if (pre_stm != null) {
pre_stm.close();
pre_stm = null;
}
if (call_stm != null) {
call_stm.close();
call_stm = null;
}
conn1.commit();
conn1.close();
conn1 = null;
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* return a result set according to sql sent
*
* #param SQL
* #return
*/
public ResultSet getRec(String SQL) {
try {
setOracleConnectionActive();
stm = conn1.createStatement();
rec = stm.executeQuery(SQL);
return rec;
} catch (Exception ex) {
ex.printStackTrace();
return rec;
}
}
/**
* Activate oracle connection
*/
private void setOracleConnectionActive() {
try {
if (conn1 == null || conn1.isClosed()) {
OracleDataSource ods = new OracleDataSource();
if (propValue != null) {
ods.setURL(propValue);
}
conn1 = ods.getConnection();
System.out.println("DB connection CONNECTED......");
conn1.setAutoCommit(false);
}
} catch (Exception ex) {
//setOracleConnectionActive();
ex.printStackTrace();
System.out.println("DB connection FAILED......");
}
}
/**
* send prepared result set with user authenticate
*
* #param SQL
* #param strInputUserMobile
* #param strInputUserName
* #param strInputUserPassword
* #return
*/
public ResultSet getRecPreparedAuthentication(String SQL,
String strInputUserMobile, String strInputUserName,
String strInputUserPassword) {
try {
setOracleConnectionActive();
pre_stm = conn1.prepareStatement(SQL);
pre_stm.setString(1, strInputUserMobile);
pre_stm.setString(2, strInputUserName);
pre_stm.setString(3, strInputUserPassword);
rec = pre_stm.executeQuery();
return rec;
} catch (Exception ex) {
ex.printStackTrace();
return rec;
}
}
/**
* insert sql to db which is send as a sql
*
* #param SQL
* #return
*/
public int insertSQL(String SQL) {
int output = 0;
try {
setOracleConnectionActive();
stm = conn1.createStatement();
output = stm.executeUpdate(SQL);
conn1.commit();
output = 1;
} catch (Exception ex) {
try {
conn1.rollback();
output = 0;
} catch (SQLException e) {
e.printStackTrace();
output = 0;
}
ex.printStackTrace();
}
return output;
}
/**
* Send a callable statement according to sent sql
*
* #param SQL
* #return
*/
public CallableStatement callableStatementSQL(String SQL) {
int output = 0;
try {
setOracleConnectionActive();
call_stm = conn1.prepareCall(SQL);
} catch (Exception ex) {
try {
conn1.rollback();
output = 0;
} catch (SQLException e) {
e.printStackTrace();
output = 0;
}
ex.printStackTrace();
}
return call_stm;
}
}
Every transaction I refer this class and do my fetching & CRUD operations.
Is there any issue with my code?
You opened a lot of connections and that's the issue. I think in your code, you did not close the opened connection.
A database bounce could temporarily solve, but will re-appear when you do consecutive execution.
Also, it should be verified the number of concurrent connections to the database. If maximum DB processes parameter has been reached this is a common symptom.
Courtesy of this thread: https://community.oracle.com/thread/362226?tstart=-1
I fixed this problem with sql command line:
connect system/<password>
alter system set processes=300 scope=spfile;
alter system set sessions=300 scope=spfile;
Restart database.
For me the problem was not the number of connexions, but the "matching protocol" part. Changing the ojdbc version solved the problem.
I am new to Glassfish and Java EE, and I try to develop a project using glassfish as the server. The problem I have is that sometiems glassfish takes too long to deploy the project because it is closing JDBC Connections, and that takes too long.
SEVERE: Closing JDBC Connection 0
SEVERE: Closing JDBC Connection 1
SEVERE: Closing JDBC Connection 2
SEVERE: Closing JDBC Connection 3
SEVERE: Closing JDBC Connection 4
...........
SEVERE: Closing JDBC Connection 19
I don't know if the problem is from the glassfish server or from my code.. I am closing the connections after using them..
Can you please help me with figuring out where the problem comes from and how can I solve it?
I will add some more info.
I am using GlassFish Server 4.1 and Java EE 7 Web.
For connections, I have the following classes:
public class PooledConnection {
private Connection connection = null;
private boolean inuse = false;
// Constructor that takes the passed in JDBC Connection
// and stores it in the connection attribute.
public PooledConnection(Connection value) {
if (value != null) {
this.connection = value;
}
}
// Returns a reference to the JDBC Connection
public Connection getConnection() {
// get the JDBC Connection
return this.connection;
}
// Set the status of the PooledConnection.
public void setInUse(boolean value) {
inuse = value;
}
//Returns the current status of the PooledConnection.
public boolean inUse() {
return inuse;
}
// Close the real JDBC Connection
public void close() {
try {
connection.close();
} catch (SQLException sqle) {
System.err.println(sqle.getMessage());
}
}
}
The ConnectionPool class
public class ConnectionPool {
// JDBC Driver Name
private String driver = null;
// URL of database
private String url = null;
// Initial number of connections.
private int size = 0;
// Username
private String username = null;
// Password
private String password = null;
// Vector of JDBC Connections
private ArrayList<PooledConnection> pool = null;
private ArrayList<PooledConnection> poolInUse = null;
private ArrayList<PooledConnection> poolNotInUse = null;
public ConnectionPool() {
}
// Set the value of the JDBC Driver
public void setDriver(String value) {
if (value != null) {
driver = value;
}
}
// Get the value of the JDBC Driver
public String getDriver() {
return driver;
}
// Set the URL Pointing to the Datasource
public void setURL(String value) {
if (value != null) {
url = value;
}
}
// Get the URL Pointing to the Datasource
public String getURL() {
return url;
}
// Set the initial number of connections
public void setSize(int value) {
if (value > 1) {
size = value;
}
}
// Get the initial number of connections
public int getSize() {
return size;
}
// Set the username
public void setUsername(String value) {
if (value != null) {
username = value;
}
}
// Get the username
public String getUserName() {
return username;
}
// Set the password
public void setPassword(String value) {
if (value != null) {
password = value;
}
}
// Get the password
public String getPassword() {
return password;
}
// Creates and returns a connection
private Connection createConnection() throws Exception {
Connection con = null;
// Create a Connection
con = DriverManager.getConnection(url, username, password);
return con;
}
// Initialize the pool
public synchronized void initializePool() throws Exception {
// Check our initial values
if (driver == null) {
throw new Exception("No Driver Name Specified!");
}
if (url == null) {
throw new Exception("No URL Specified!");
}
if (size < 1) {
throw new Exception("Pool size is less than 1!");
}
// Create the Connections
try {
// Load the Driver class file
Class.forName(driver);
// Create Connections based on the size member
for (int x = 0; x < size; x++) {
System.err.println("Opening JDBC Connection " + x);
Connection con = createConnection();
if (con != null) {
// Create a PooledConnection to encapsulate the real JDBC Connection
PooledConnection pcon = new PooledConnection(con);
// Add the Connection to the pool
addConnection(pcon);
}
}
} catch (SQLException sqle) {
System.err.println(sqle.getMessage());
} catch (ClassNotFoundException cnfe) {
System.err.println(cnfe.getMessage());
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
// Adds the PooledConnection to the pool
private void addConnection(PooledConnection value) {
// If the pool is null, create a new vector with the initial size of
if(pool == null)
{
pool = new ArrayList<PooledConnection>(size);
}
pool.add(value);
}
public synchronized void releaseConnection(Connection con)
{
if(con != null)
{
// find the PooledConnection Object
for (int x = 0; x < pool.size(); x++) {
PooledConnection pcon = pool.get(x);
// Check for correct Connection
if (pcon.getConnection() == con) {
System.err.println("Releasing Connection " + x);
// Set its inuse attribute to false, which
// releases it for use
pcon.setInUse(false);
break;
}
}
}
}
// Find an available connection
public synchronized Connection getConnection() throws Exception {
PooledConnection pcon = null;
// find a connection not in use
for (int x = 0; x < pool.size(); x++) {
pcon = pool.get(x);
// Check to see if the Connection is in use
if (pcon.inUse() == false) {
// Mark it as in use
pcon.setInUse(true);
// return the JDBC Connection stored in the
// PooledConnection object
return pcon.getConnection();
}
}
// Could not find a free connection, create and add a new one
try {
// Create a new JDBC Connection
Connection con = createConnection();
// Create a new PooledConnection, passing it the JDBC Connection
pcon = new PooledConnection(con);
// Mark the connection as in use
pcon.setInUse(true);
// Add the new PooledConnection object to the pool
pool.add(pcon);
} catch (Exception e) {
System.err.println(e.getMessage());
}
// return the new Connection
return pcon.getConnection();
}
// When shutting down the pool, you need to first empty it.
public synchronized void emptyPool() {
// Iterate over the entire pool closing the JDBC Connections.
for (int x = 0; x < pool.size(); x++) {
System.err.println("Closing JDBC Connection " + x);
PooledConnection pcon = pool.get(x);
// If the PooledConnection is not in use, close it
if (pcon.inUse() == false) {
pcon.close();
} else {
// If it is still in use, sleep for 30 seconds and force close.
try {
java.lang.Thread.sleep(30000);
pcon.close();
} catch (InterruptedException ie) {
System.err.println(ie.getMessage());
}
}
}
}
}
And the DBAccessController
public final class DBAccessController {
private Connection connection = null;
public DBAccessController(String url, String userId, String password, boolean typereadonly) {
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver").newInstance();
connection = DriverManager.getConnection(url, userId, password);
connection.setReadOnly(typereadonly);
} catch (java.lang.ClassNotFoundException exceptionClassNotFound) {
} catch (java.lang.InstantiationException instantException) {
} catch (java.lang.IllegalAccessException illegalAccess) {
} catch (java.sql.SQLException sqle) {
}
}
public DBAccessController(Connection con) {
if (con != null) {
this.connection = con;
}
}
public final synchronized ArrayList runSQL(String queryString, List<String> parametrii) {
try {
PreparedStatement prepStmt = connection.prepareStatement(queryString, PreparedStatement.RETURN_GENERATED_KEYS);
connection.setAutoCommit(true);
for (int i = 0; i < parametrii.size(); i++) {
prepStmt.setString((i + 1), parametrii.get(i));
}
ResultSet rs = prepStmt.executeQuery();
boolean flag = prepStmt.execute();
ArrayList<HashMap<String, String>> rezultate = new ArrayList<>();
ResultSet keyset = prepStmt.getGeneratedKeys();
while (keyset != null && keyset.next()) {
HashMap<String, String> keysHM = new HashMap<>();
// Retrieve the auto generated key(s).
int key = keyset.getInt(1);
keysHM.put("cheia", Integer.toString(key));
rezultate.add(keysHM);
}
if (flag) {
ResultSet res = prepStmt.getResultSet();
ResultSetMetaData rsmd = res.getMetaData();
int numberOfColumns = rsmd.getColumnCount();
while (res.next()) {
HashMap<String, String> hm = new HashMap<>();
Object o = res.getObject(i);
if (o != null) {
hm.put(rsmd.getColumnName(i), o.toString());
}
}
rezultate.add(hm);
}
res.close();
prepStmt.close();
return rezultate;
} else {
prepStmt.close();
if (keyset != null) {
return rezultate;
} else {
return null;
}
}
} catch (java.sql.SQLException sqle) {
return null;
}
}
public final synchronized ArrayList runSQL(String queryString) {
try {
PreparedStatement statement = connection.prepareStatement(queryString, PreparedStatement.RETURN_GENERATED_KEYS);
connection.setAutoCommit(true);
boolean flag = statement.execute();
System.out.println("Statement: " + statement + " flag: " + flag);
ArrayList<HashMap<String, String>> rezultate = new ArrayList<>();
ResultSet keyset = statement.getGeneratedKeys();
while (keyset != null && keyset.next()) {
HashMap<String, String> keysHM = new HashMap<>();
// Retrieve the auto generated key(s).
int key = keyset.getInt(1);
keysHM.put("cheia", Integer.toString(key));
rezultate.add(keysHM);
System.out.println("Cheile " + keyset.toString());
}
System.out.println("Cheile " + keyset.toString());
if (flag) {
ResultSet res = statement.getResultSet();
ResultSetMetaData rsmd = res.getMetaData();
int numberOfColumns = rsmd.getColumnCount();
System.out.println("res: " + res + " rsmd: " + rsmd + " numberOfColumns: " + numberOfColumns);
while (res.next()) {
HashMap<String, String> hm = new HashMap<>();
System.out.println("Res to string " + res.toString());
for (int i = 1; i <= numberOfColumns; i++) {
System.out.println("obiectul " + i + " res.getObject(i) " + res.getObject(i));
Object o = res.getObject(i);
System.out.println("rsmd.getColumnName(i) " + rsmd.getColumnName(i));
if (o != null) {
hm.put(rsmd.getColumnName(i), o.toString());
}
}
rezultate.add(hm);
}
res.close();
statement.close();
System.out.println("Return rezultate");
return rezultate;
} else {
System.out.println("Return null 1");
statement.close();
if (keyset != null) {
return rezultate;
} else {
return null;
}
}
} catch (java.sql.SQLException sqle) {
System.out.println("Return null 2" + sqle.getMessage());
return null;
}
}
public final void stop() {
try {
connection.close();
} catch (java.sql.SQLException e) {
}
}
}
When I need to use a connection I do the following (for example):
Connection con;
try {
con = cp.getConnection();
udao = new UtilizatorDAO(con);
con.close();
}
} catch (Exception ex) {
Logger.getLogger(RegisterController.class.getName()).log(Level.SEVERE, null, ex);
}
out.close();
So I'm quite new to Java and Derby. I'm using both with my Flex app on Tomcat 7.
When I make a call to Java from Flex the login function works fine but my getUserByUsername function does not.
public Boolean loginUser(String username, String password) throws Exception
{
Connection c = null;
String hashedPassword = new String();
try
{
c = ConnectionHelper.getConnection();
PreparedStatement ps = c.prepareStatement("SELECT password FROM users WHERE username=?");
ps.setString(1, username);
ResultSet rs = ps.executeQuery();
if(rs.next())
{
hashedPassword = rs.getString("password");
}
else
{
return false;
}
if(Password.check(password, hashedPassword))
{
return true;
}
else
{
return false;
}
}
catch (SQLException e)
{
e.printStackTrace();throw new DAOException(e);
}
finally
{
ConnectionHelper.closeConnection(c);
}
}
public User getUserByUsername(String username) throws DAOException
{
//System.out.println("Executing DAO.getUserByName:" + username);
User user = new User();
Connection c = null;
try
{
c = ConnectionHelper.getConnection();
PreparedStatement ps = c.prepareStatement("SELECT * FROM users WHERE username = ?");
ps.setString(1, username);
ResultSet rs = ps.executeQuery();
while(rs.next())
{
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
user.setTeam(rs.getString("team"));
user.setScore(rs.getInt("score"));
}
}
catch (SQLException e)
{
e.printStackTrace();
throw new DAOException(e);
}
finally
{
ConnectionHelper.closeConnection(c);
}
return user;
}
The stack I get in Flex is useless as far as I can tell:
Flex Message (flex.messaging.messages.ErrorMessage) clientId = 8EB6D37B-7E0B-01B0->AA55-457722B9036C correlationId = A39E574F-CFC6-51FE-6CBE-451AF329E2F8 destination >= service messageId = 8EB6DF4C-650B-BDD7-7802-B813A61C8DC8 timestamp = >1401318734645 timeToLive = 0 body = null code = Server.Processing message = >services.DAOException : java.sql.SQLException: Failed to start database >'/Applications/blazeds/tomcat/webapps/testdrive/WEB-INF/database/game_db', see the next >exception for details. details = null rootCause = ASObject(23393258)>>{message=java.sql.SQLException: Failed to start database >'/Applications/blazeds/tomcat/webapps/testdrive/WEB-INF/database/game_db', see the next >exception for details., suppressed=[], localizedMessage=java.sql.SQLException: Failed to >start database '/Applications/blazeds/tomcat/webapps/testdrive/WEB->INF/database/game_db', see the next exception for details., cause=java.sql.SQLException} >body = null extendedData = null
My first thought was that it was just an error in my function (maybe someone else will notice it) but I've been looking through it for a couple hours and I can't see anything.
After that I thought maybe Derby had a problem with concurrent connections. I saw somewhere that Embedded JDBC can only handle one connection so I changed the driver from Embedded to Client which once again resulted in the login function working and the other an error saying the url in the connection was null. Any thoughts? Thanks ahead of time for any ideas.
EDIT:
package services;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.net.URLDecoder;
public class ConnectionHelper
{
private String url;
private static ConnectionHelper instance;
public String getUrl()
{
return url;
}
private ConnectionHelper()
{
try
{
Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
String str = URLDecoder.decode(getClass().getClassLoader().getResource("services").toString(),"UTF-8");
str= str.substring(0, str.indexOf("classes/services"));
if ( str.startsWith("file:/C:",0)){
str=str.substring(6);
}
else{
str=str.substring(5);
}
url = "jdbc:derby:" + str + "database/game_db";
System.out.println("Database url "+url);
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static ConnectionHelper getInstance()
{
if (instance == null)
instance = new ConnectionHelper();
return instance;
}
public static Connection getConnection() throws java.sql.SQLException
{
return DriverManager.getConnection(getInstance().getUrl());
}
public static void closeConnection(Connection c)
{
try
{
if (c != null)
{
c.close();
}
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
There is NO problem with multiple connections in embedded mode. Full stop.
That said, what you may have come across, is that only one jvm process can access the Derby database files at a time. But that jvm may well have 1000s of threads each with their own connection to Derby (resources permitting, of course).