I have written the following java code to connect the Oracle Express Edition database.....I have read a lot about closing the connection, statement and result but there are some questions about this issue...
1- I usually test my code several time so If I Don not close the connection and etc. will I face with any problem?!!(because the connection is made on the same variable or object in my code!!!!)
2-how can I understand how many connections exist now?(after testing the code for several time)
3- Should I place CLOSE methods in finally block with a new TRY CATCH block or add THROWS SQLException after main method?!!!! what is the difference between these to implementation?!!!
package mainAssignment;
import java.sql.*;
import java.text.MessageFormat;
import java.math.*;
import java.util.*;
//import java.text.MessageFormat;
public class Conn {
/**
* #param args
*/
public static void main(String[] args)throws SQLException{
// TODO Auto-generated method stub
String jdbcURL = "jdbc:oracle:thin:#localhost:1521:xe";
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
String user = "hr";
String passwd = "hr";
Scanner input = new Scanner(System.in);
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection(jdbcURL, user, passwd);
System.out.println("ok");
System.out.println("Please enter the desired employee ID: ");
Object[] arg={new String(input.nextLine())};
String query = MessageFormat.format(
"select * from EMPLOYEES where employee_id={0}", arg);
//System.out.println(query);
stmt = conn.createStatement();
stmt.executeQuery(query);
rs = stmt.getResultSet();
while (rs.next()) {
BigDecimal empid = rs.getBigDecimal(1);
String firstname = rs.getString("FIRST_NAME");
System.out.println("employee ID " + empid
+ " first name is " + firstname);
}
} catch (SQLException e) {
e.printStackTrace();
// TODO
} catch (ClassNotFoundException e) {
// TODO
e.printStackTrace();
} finally {
conn.close();
rs.close();
if (conn.isClosed())
System.out.println("no connection any more");
else
System.out.println("connection exists");
}
}
}
1) You'll be left with many idle (hanging) connections after you finish the execution. To prevent that check whether the connection is null. If it is - establish a new one, if it's not null - use existing.
2) You can check it on the sql server. Example for ms sql server: How to determine total number of open/active connections in ms sql server 2005
3) Putting close methods in finally block is a good practice. Don't change that. Sometimes finally block also requires its own inner try-catch-finally block.
Side note: if you create methods that throw exceptions you're not solving any issues. it's just pushing the need to maintain the exception to the person who'll use your methods. Sometimes it's a good approach but more often it is not.
In real life applications you should also check whether the database is available, the connection was established and the query result is not null.
Appendix 1: How to check the number of active connections in oracle express:
How to list active / open connections in Oracle?
http://dbalink.wordpress.com/2008/06/08/find-active-sessions-in-oracle-database/
You may want to use a connection pool. Take a look at C3P0 or DBCP. You still need to close your result set, and statement, but when you call close on the connection it just returns it back to the pool. Update: we'be been using Hikari for connection pooling for a few years, and have been really happy with it.
Related
I started learning databases in java with postgres. I created database and now need to add there some data. I can add data succesfully only one time, then i get SQLException and can't add anything to database, so i need to launch my project again. Where did i go wrong?
Here is method for adding: (if its not enough, i can add what is needed)
public final Connection CONNECTION = DriverManager.getConnection
(url, login, pass);
public void sqlAddData(Algorithm codec, String input, String translated) throws SQLException {
try (CONNECTION) {
java.sql.Timestamp date = new java.sql.Timestamp(new java.util.Date().getTime());
String add = " insert into db.public.history ( codec, input, translated, date) values(?,?,?,?)";
PreparedStatement prepared = CONNECTION.prepareStatement(add);
prepared.setString(1, String.valueOf(codec));
prepared.setString(2, input);
prepared.setString(3, translated);
prepared.setTimestamp(4, date);
prepared.executeUpdate();
} catch (SQLException e) {
logger.warning("Error with database");
}
CONNECTION.close();
}
Thanks for help and i'm sorry, if it is noob question, i'm just learning.
Its because you close the connection after one call.
CONNECTION.close(); is the last thing you do and that closes the connection, if u wanna add data again you need to open the connection once again, or wait to close when you dont wanna add anything more.
In your code you instantiate your connection before your method with :
public final Connection CONNECTION = DriverManager.getConnection(url, login, pass);
Which means, if you close it inside your method you will not be able to reuse this connection unless you create a new one (instantiate a new one).
To fix your problem here is what you can do :
public final Connection CONNECTION;
public void sqlAddData(Algorithm codec, String input, String translated) throws SQLException {
CONNECTION = DriverManager.getConnection(url, login, pass);
try (CONNECTION) {
java.sql.Timestamp date = new java.sql.Timestamp(new java.util.Date().getTime());
String add = " insert into db.public.history ( codec, input, translated, date) values(?,?,?,?)";
PreparedStatement prepared = CONNECTION.prepareStatement(add);
prepared.setString(1, String.valueOf(codec));
prepared.setString(2, input);
prepared.setString(3, translated);
prepared.setTimestamp(4, date);
prepared.executeUpdate();
} catch (SQLException e) {
// Handle your exception correctly or throw it.
}
}
Note you can also use try-catch-finally to safely close your connection. I didn't show you how to catch your exception I will let you do some digging yourself ;)
Also note that you are using try-with-resources which remove the finally block and still close your connection safely.
Hope this helps.
The reason you can only connect to the database one time is because you're closing the open connection by wrapping the Connection object in a try-with-resources statement. Also, you're calling close on Connection after that statement which is redundant.
A solution to this problem would be to use connection pooling. Some good options are Hikari and C3P0.
I try to create a connection between JDBC and MS Access.
I follow the instruction as per this link. I am using IntelliJ Idea. Here I am sharing some snaps to describe my problem.
This is the code that I write down to make a connection with Database Database2. But as you can see there is no error neither any output. Now I am sharing the table structure and content on the table.
2nd picture is
My code is:
import java.sql.*;
public class Connection_sample {
public static void main(String[] args) {
try {
Class.forName("net.ucanaccess.jdbc.UcanaccessDriver");
Connection conn= DriverManager.getConnection("jdbc:ucanaccess://D://tutorial/Database2.accdb");
Statement s = conn.createStatement();
s.executeQuery("select * from Student");
ResultSet rset = s.getResultSet();
while (rset.next()) {
System.out.println(rset.getInt(1)+""+rset.getInt(2));
}
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Can anyone help me to find the error?
Your problem is the result of using getResultSet() instead of using the result set returned by executeQuery(). You should only use getResultSet() in combination with execute().
A result set should only be obtained once, and it was already returned from executeQuery (which you ignored). When you called getResultSet, you - apparently - got an empty one (which technically violates the contract).
I know this probably is a similar question from the rest, (well originally, before I tried something new, it was a bit unique but it never solved the main problem), but I probably need to discuss this with someone who can help because I could never get what's causing this despite already reading various posts from this site. Bottom line is I need to keep on making plenty of sequential queries but I ended up making too many connections.
What my program does is that it displays data about each member and that it's sort of a tree or network where, in order to get the data you need for each member, you have to scout through every other member that points to that current member (or child's data) , and the data of the member that points to the member that points to the current member (or grandchild's data) and so on. Hence, why I need to keep making queries cause I need to get the data off of each child. Each node has I think a minimum children of 5 and on my 34th member, it gave off that "Too Many Connections" error.
I have read how to open and close the Connections and all but am I still doing it incorrectly? I've tried changing the max connections but that's not really a long term solution for me. Here's how I do it:
public class SQLConnect {
private Connection con;
private Statement st;
private ResultSet rs;
public SQLConnect() {
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbname?zeroDateTimeBehavior=convertToNull", "root", "");
st = con.createStatement();
} catch (ClassNotFoundException | SQLException ex) {
System.out.println("Error in constructor: " + ex);
}
}
//this method gets called before I make another query
public void reconnect() {
try {
st.close();
con.close();
if (con.isClosed()) {
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbname", "root", "");
st = con.createStatement();
}
} catch (SQLException ex) {
Logger.getLogger(SQLConnect.class.getName()).log(Level.SEVERE, null, ex);
}
}
//sample method on how I do queries
public ResultSet getMemberViaMemberId(String mID) {
try {
String query = "CALL getMemberViaMemberId(" + mID + ");"; //procedure call
rs = st.executeQuery(query);
} catch (Exception ex) {
System.out.println("Error: " + ex);
}
return rs;
}
}//end of class
The way I call it in my JForm is this..
SQLConnect connect;
public Class(){
connect = new SQLConnect();
}
public void methodThatGetsCalledALot(String current_id){
connect.reconnect(); //refer to SQLConnectClass displayed above
ResultSet member = connect.getMemberViaMemberId(current_id);
try{
if (member.next()) {
lastName = member.getString("last_name");
firstName = member.getString("first_name");
}
//display data...
} catch (SQLException ex){
}
}
The code:
connect.reconnect();
ResultSet rs = connect.callSQLMethod();
is the most essential bit and is called by every class, and by every method that needs to fetch data. I have to acknowledge that I never bother closing ResultSet because often times it's inside a loop and gets replaced with new data anyway.
Again, my problem is: I cant continue fetching data anymore because of too many connections. Am I really closing things properly or am I missing something? Any suggestions on how to fix this? If my question is too confusing, I'd add more details if required. Thank you. If anyone's to keen on freely helping me out, I'd go for some emailing. Thank you! And Happy New Year btw.
You seem to be creating a lot of connections and recursing with the ResultSet open. Don't create new connections all the time, all you need is one connection and don't reconnect all the time. You actually don't need the reconnect method at all (unless you connection closes automatically, in which case you can check if it is closed before executing query). And you need to close the ResultSet once you are done retrieving values.
All you need is the data and not the resultset. So take the data and release the resource ie ResultSet. So do this -
In your getMemberViaMemberId don't return ResultSet, in that method itself, iterate through the resultset and create the object for the row and store it into a collection and return that collection after closing the ResultSet. And dont call reconnect method at all.
Close the single connection that you have when exiting the program.
I'm building a webcrawler and I'm looking for the best way to handle my requests and connection between my threads and the database (MySql).
I've 2 types of threads :
Fetchers : They crawl websites. They produce url and add they into 2 tables : table_url and table_file. They select from table_url
to continue the crawl. And update table_url to set visited=1 when they
have read a url. Or visited=-1 when they are reading it. They can
delete row.
Downloaders : They download files. They select from table_file. They update table_file to change the Downloaded column. They never
insert anything.
Right now I'm working with this :
I've a pool of connection based on c3p0.
Every target (website) have thoses variables :
private Connection connection_downloader;
private Connection connection_fetcher;
I create both connection only once when I instanciate a website. Then every thread will use thoses connections based on their target.
Every thread have thoses variables :
private Statement statement;
private ResultSet resultSet;
Before every Query I open a SqlStatement :
public static Statement openSqlStatement(Connection connection){
try {
return connection.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
And after every Query I close sql statement and resultSet with :
public static void closeSqlStatement(ResultSet resultSet, Statement statement){
if (resultSet != null) try { resultSet.close(); } catch (SQLException e) {e.printStackTrace();}
if (statement != null) try { statement.close(); } catch (SQLException e) {e.printStackTrace();}
}
Right now my Select queries only work with one select (I never have to select more than one for now but this will change soon) and is defined like this :
public static String sqlSelect(String Query, Connection connection, Statement statement, ResultSet resultSet){
String result = null;
try {
resultSet = statement.executeQuery(Query);
resultSet.next();
result = resultSet.toString();
} catch (SQLException e) {
e.printStackTrace();
}
closeSqlStatement(resultSet, statement);
return result;
}
And Insert, Delete and Update queries use this function :
public static int sqlExec(String Query, Connection connection, Statement statement){
int ResultSet = -1;
try {
ResultSet = statement.executeUpdate(Query);
} catch (SQLException e) {
e.printStackTrace();
}
closeSqlStatement(resultSet, statement);
return ResultSet;
}
My question is simple : can this be improved to be faster ? And I'm concerned about mutual exclusion to prevent a thread to update a link while another is doing it.
I believe your design is flawed. Having one connection assigned full-time for one website will severly limit your overall workload.
As you already have setup a connection pool, it's perfectly okay to fetch before you use (and return afterwards).
Just the same, try-with-catch for closing all your ResultSets and Statements after will make code more readable - and using PreparedStatement instead of Statement would not hurt as well.
One Example (using a static dataSource() call to access your pool):
public static String sqlSelect(String id) throws SQLException {
try(Connection con = dataSource().getConnection();
PreparedStatement ps = con.prepareStatement("SELECT row FROM table WHERE key = ?")) {
ps.setString(1, id);
try(ResultSet resultSet = ps.executeQuery()) {
if(rs.next()) {
return rs.getString(1);
} else {
throw new SQLException("Nothing found");
}
}
} catch (SQLException e) {
e.printStackTrace();
throw e;
}
}
Following the same pattern I suggest you create methods for all the different Insert/Update/Selects your application uses as well - all using the connection only for the short time inside the DB logic.
I can not see a real advantage to have all the Database stuff in your webcrawler threads.
Why don't you use a static class with the sqlSelect and sqlExec method, but without the Connection and ResultSet parameters. Both connection objects are static as well. Make sure the connection objects are valid befor using them.
I am working on my first Java Project with MySQL. I have one function that gets called every time I get data back from my data source. This function should save a new line to my MySQL database. See the code here:
import java.sql.*;
import java.util.Properties;
/**
*
* #author jeffery
*/
public class SaveToMysql {
// The JDBC Connector Class.
private static final String dbClassName = "com.mysql.jdbc.Driver";
private static final String CONNECTION = "jdbc:mysql://localhost/test";
static public String test(int reqId, String date, double open, double high, double low,
double close, int volume, int count, double WAP, boolean hasGaps){
if (date.contains("finished")){
return "finished";
}
// Class.forName(xxx) loads the jdbc classes and
// creates a drivermanager class factory
try{
Class.forName(dbClassName);
}catch ( ClassNotFoundException e ) {
System.out.println(e);
}
// Properties for user and password. Here the user and password are both 'paulr'
Properties p = new Properties();
p.put("user","XXXXXXXX");
p.put("password","XXXXXXXXXXXx");
// Now try to connect
Connection conn;
try{
conn = DriverManager.getConnection(CONNECTION,p);
}catch(SQLException e){
return e.toString();
}
PreparedStatement stmt;
try{
stmt = conn.prepareStatement("insert into dj_minute_data set symbol = (select ticker from dow_jones_constituents where id = ?), "
+ "date = str_to_date(?,'%Y%m%d %H:%i:%s')" +
", open = ?" +
", high = ?" +
", low = ?" +
", close = ?" +
", volume = ?" +
", adj_close = ?");
stmt.setInt(1, reqId);
stmt.setString(2, date);
stmt.setDouble(3, open);
stmt.setDouble(4, high);
stmt.setDouble(5, low);
stmt.setDouble(6, close);
stmt.setDouble(7, volume);
stmt.setDouble(8, WAP);
}catch (SQLException e){
return e.toString();
}
try{
stmt.executeUpdate();
}catch (SQLException e){
return e.toString();
}
return stmt.toString();
}
}
As you all can see this function test is in its own class, called SaveToMysql. To call this function, I import the class into a different class, and use this syntax:
msg = SaveToMysql.test(reqId, date, open, high, low, close, volume, count, WAP, hasGaps);
The msg then get output to the screen. Showing either error message or success.
This function may be called many times rapidly in a short time period. I know I should not have to re-open my connection with the MySQL server every time the function gets called. How would I change this so that the 1 MySQL connection stays open for every call to the function.
Thanks!!
JDBC URL: jdbc:mysql://:/? connectTimeout=0&socketTimeout=0&autoReconnect=true
I know I should not have to re-open my connection with the MySQL server every time the function gets called.
No, it's fine to do so - as long as you have a connection pool under the hood to manage the real connections. There are various connection pool projects around, such as c3p0 and DBCP. That way you can make each of your calls isolated from the others:
Fetch a connection from the pool
Use it
Release it back to the pool
See the documentation for whichever pool you choose for the details. Often connection pools allow you to just request a connection from JDBC as normal and then close it as normal, effectively making the whole thing transparent.
Also note that you should definitely start using prepared statements with parameters rather than including your values directly in your SQL statement. Your current code is a SQL injection attack waiting to happen.
you need to manage one static class or method.
like
public class ConnectionClass
{
public static Connection connection = null;
public Connection getCurrentConnection()
{
if(connection != null)
{
return connection;
}
else
{
create new connection...
and return that new connection after giving it to global connection..
}
}
}
by this every time you will get current connection. and if there is some issue and connection is not available then you can create new connection. when you need connection object you just need to call getCurrentConnection method.
so you just need to following things in ur code.
Connection conn;
try{
//conn = DriverManager.getConnection(CONNECTION,p);
conn = getCurrentConnection();
}catch(SQLException e){
return e.toString();
}
If you want use 1 connection when call SaveToMysql.test method many times, you can add your connection in method parameter, or create a global connection variable out side SaveToMysql.test method. but, if you use 1 connection, please attention about transaction. I hope it will help you.