I am trying to run an alter system command through JDBC which is required for me to run a query optimally.
I`m not sure if I am doing it right as I am not able to see the effect of the alter session statement. How do we persist the same session in JDBC what I mean is if I use the same connection and not close it does it mean I am using the same session?
The connection and database class are just helper classes to get a connection.
MyConnection mainDatabaseConnection = new MyConnection("jdbc:oracle:thin:#aas:111:"+tm.databaseName, "sys as sysdba", "xxx");
Database mainDatabase = new Database(mainDatabaseConnection.getConnection());
/* Fill in with data got for the main database */
//String auditQuery = mainDatabase.generateAuditQuery(tm.schemaName, tm.tableName);
String auditQuery = "select id, name, school, start, end from user where start>'11-11-11' and start<'12-12-12'";
System.out.println(auditQuery);
ResultSet rs = mainDatabase.runQuery("ALTER SESSION set optimizer_use_invisible_indexes = true");
// ResultSetMetaData md = rs.getMetaData();
// System.out.println(md.getColumnCount());
rs.close();
mainDatabase.close();
mainDatabaseConnection.close();
I am not sure if the alter session command ran successfully.
Question 2: When I run a Select query using Statement I get a resultSet. WHen I close the statement does the resultSet get closed too? So, as soon as I close the statment or connection does all the fetched data go away?
A java.sql.Connection object represents a session in Oracle. As long as you keep using the same object, you're in the same session.
With regard to closing Statements, as Mark Rotteveel commented - closing a Statement will indeed close a ResultSet that was opened by it. It would, however, be recommended to close the RestulSet once you're done with it, even (or, actually - especially) if you intend to reuse the Statement object.
Related
Hello there and thanks for reading.
I'm trying to retrieve the ID of the newly inserted data, but I always get an empty ResultSet.
Connection con = main.getCon();
String sqlCommand = "Insert Into Relations(name,explanation) values(?,?)";
PreparedStatement state =
con.prepareStatement(sqlCommand,Statement.RETURN_GENERATED_KEYS);
state.setString(1,name.getText());
state.setString(2,explanation.getText());
int affectedRows = state.executeUpdate();
assert (affectedRows>0);
ResultSet rs = state.getGeneratedKeys();
assert rs.next();
int instertedID= rs.getInt("ID");
Not sure what's wrong with it. Checked different samples online, but couldn't figure out what's my mistake.
I also tried it with Statement, but no luck with that either.
Point 1: the code runs smoothly and my data in inserted into the database.
Point 2: there are examples online for this very case, you can check it here:
https://www.baeldung.com/jdbc-returning-generated-keys
I just realized that my ResultSet wasn't empty, I had problem with using my debugger and that's why I thought it was empty.
As Mark Rotteveel mentioned in a comment, the problem was with "assert" statement.
The problem is your use of assert rs.next(). Assertions in Java are intended for checking invariants (eg during testing), but when you normally run Java, assert statements are not executed, they are only executed when explicitly enabling this with the -ea commandline option.
As a result, rs.next() is not called, so your result set is still positioned before the first row when you call rs.getInt(1). Instead use if (rs.next()) { ... }.
This is DB engine dependent. Some tips:
JDBC is low-level and not appropriate to program with
It's a complicated API. Use something that makes it easier: JDBI, or JOOQ. They may have abstractions over insertion that takes care of this stuff for you.
Some DB engines require that you list the column name
Try:
con.prepareStatement(sqlCommand, new String[] {"UNID"});
Some DB engines will only return generated values as direct resultset
Don't call .executeUpdate(); instead, call .executeQuery() which returns a ResultSet; check that one.
Something else
Post the exact table structure and DB engine you're working with if the above doesn't help.
Your code is broken
You can't create resource objects (once that must be closed) unless you do so safely, and you're not doing so safely. Use try-with-resources:
String sql = "INSERT INTO relations(name, explanation) VALUES (?, ?)";
try (Connection con = main.getCon();
PreparedStatement ps = con.prepareStatement(sql, new String[] {"unid"})) {
state.setString(1, name.getText());
state.setString(2, explanation.getText());
try (ResultSet rs = state.executeQuery()) {
if (!rs.next()) throw new SQLException("insert didn't return autogen?");
System.out.println(rs.getInt(1));
}
}
ResultSets, Statements, PreparedStatements, and Connections are all resources (must be closed!) - if you want to store one of those things in a field, you can do that, but only if the class that contains this field is itself a resource: It must have a close() method, it must implement AutoClosable, and you can then only make instances of this class with try-with-resources as above.
Failure to adhere to these rules means your app seems to work, but is leaking resources as it runs, thus, if you let it run long enough, it will start crashing. Also, your DB engine will grind to a halt as more and more connections are left open, stuck forever.
change the last line of code to this because the DBMS you are using may not support the getting value by column name so pass the index of that column:
int instertedID = rs.getInt(1);
String sqlCommand = "Insert Into Relations (name, explanation) values(?, ?)";
PreparedStatement state = con.prepareStatement(sqlCommand, Statement.RETURN_GENERATED_KEYS);
state.setString(1,name.getText());
state.setString(2,explanation.getText());
state.executeUpdate();
ResultSet resultSet = state.getGeneratedKeys();
if(resultSet.next()) {
System.out.println(resultSet.getInt(1)); //Indicate the corresponding column index value.
}
I am currently trying to code a java program for a school project that has a mysql database of sportsclub members. I want to use the id of the members in order to change the number of classes that someone skipped. However my Java code always fails to run and outputs the exception message. My database is called demo1 and the field im trying to update is Consecutiveskips. The id field is called (id)
Simplest way to update record is through statement
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection oCon = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
String query="Update Demo1 SET Consecutiveskips=? where id=?";
PreparedStatement preparedStatement = oCon.prepareStatement(query);
preparedStatement.setInt(1, 233);
preparedStatement.setInt(2, 4);
In your code you are using setInt(6,1) but there is no 6th index present.
You should use
preparestaement.setInt(1,"yourconsicutiveskipvalue");
preparestaement.setInt(2,"idvalue");
Moreover, make sure to have mysql-connector.jar in classpath
I have been making a program that is using HSQL to connect to a database that I created. For some reason some methods in my class can call on the database and perform commands, while other parts cannot. I keep getting this error,
java.sql.SQLFeatureNotSupportedException: feature not supported
and here is the method,
public List<CustomerInfo> DBgetInfo(String Customer)
throws ClassNotFoundException, SQLException {
Class.forName("org.hsqldb.jdbcDriver");
Connection con = DriverManager.getConnection(urlConnection, userId,
password);
Statement stmt= con.createStatement();
String query = "SELECT * FROM PUBLIC.CUSTOMER";
ResultSet rs = stmt.executeQuery(query);
rs.first(); //The error happens on this line
rs.close();
stmt.close();
con.close();
}
I have ran the debugger multiple times and there error is in this method on the rs.first line. I have tried remaking the DB, reimporting all the files, checking to make sure the command is correct, and ect... The weird thing is that earlier in this class I have a method very similar to this, but it has no issues. I really can't figure out what the problem is.
According to the documentation this error occurs:
Throws:
SQLException - if a database access error occurs, this method is called on a closed result set or the result set type is TYPE_FORWARD_ONLY
SQLFeatureNotSupportedException - if the JDBC driver does not support this method
Earlier on the same page, there is a section on HSQL specific details for result sets. To call first you need to modify your statement creation:
ResultSet object generated by HSQLDB is by default of ResultSet.TYPE_FORWARD_ONLY (as is standard JDBC behavior) and does not allow the use of absolute and relative positioning methods. If a statement is created with:
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
then the ResultSet objects it produces support using all of the absolute and relative positioning methods of JDBC2 to set the position of the current row...
But you might want to think about why you need to call first.
In JDBC, can I use single Statement object to call executeQuery("") multiple times? Is it safe? Or should I close the statement object after each query, and create new object for executing another query.
E.G:
Connection con;
Statement s;
ResultSet rs;
ResultSet rs2;
try
{
con = getConnection();
// Initially I was creating the Statement object in an
// incorrect way. It was just intended to be a pseudocode.
// But too many answerers misinterpretted it wrongly. Sorry
// for that. I corrected the question now. Following is the
// wrong way, commented out now.
// s = con.prepareStatement();
// Following is the way which is correct and fits for my question.
s = con.createStatement();
try
{
rs = s.executeQuery(".......................");
// process the result set rs
}
finally
{
close(rs);
}
// I know what to do to rs here
// But I am asking, should I close the Statement s here? Or can I use it again for the next query?
try
{
rs2 = s.executeQuery(".......................");
// process the result set rs2
}
finally
{
close(rs2);
}
}
finally
{
close(s);
close(con);
}
Yes you can re-use a Statement(specifically a PreparedStatement) and should do so in general with JDBC. It would be inefficient & bad style if you didn't re-use your statement and immediately created another identical Statement object. As far as closing it, it would be appropriate to close it in a finally block, just as you are in this snippet.
For an example of what you're asking check out this link: jOOq Docs
I am not sure why you are asking. The API design and documentation show it is perfectly fine (and even intended) to reuse a Statement object for multiple execute, executeUpdate and executeQuery calls. If it wouldn't be allowed that would be explicitly documented in the Java doc (and likely the API would be different).
Furthermore the apidoc of Statement says:
All execution methods in the Statement interface implicitly close a statment's [sic] current ResultSet object if an open one exists.
This is an indication that you can use it multiple times.
TL;DR: Yes, you can call execute on single Statement object multiple times, as long as you realize that any previously opened ResultSet will be closed.
Your example incorrectly uses PreparedStatement, and you cannot (or: should not) be able to call any of the execute... methods accepting a String on a PreparedStatement:
SQLException - if [...] the method is called on a PreparedStatement or CallableStatement
But to answer for PreparedStatement as well: the whole purpose of a PreparedStatement is to precompile a statement with parameter placeholders and reuse it for multiple executions with different parameter values.
I can't find anything in the API docs that would state, that you shouldn't call executeQuery() on a given PreparedStatement instance more than once.
However your code does not close the PreparedStatement - a call to executeQuery() would throw a SQLException in that case - but the ResultSet that is returned by executeQuery(). A ResultSet is automatically closed, when you reexecute a PreparedStatement. Depending on your circumstances you should close it, when you don't need it anymore. I would close it, because i think it's bad style not to do so.
UPDATE Upps, I missed your comment between the two try blocks. If you close your PreparedStatement at this point, you shouldn't be able to call executeQuery() again without getting a SQLException.
A Prepared Statement tells the database to remember your query and to be prepared to accept parameterized variables to execute in that query. It's a lot like a stored procedure.
Prepared Statement accomplishes two main things:
It automatically escapes your query variables to help guard against SQL Injection.
It tells the database to remember the query and be ready to take variables.
Number 2 is important because it means the database only has to interpret your query once, and then it has the procedure ready to go. So it improves performance.
You should not close a prepared statement and/or the database connection in between execute calls. Doing so is incredibly in-efficient and it will cause more overhead than using a plain old Statement since you instruct the database each time to create a procedure and remember it. Even if the database is configured for "hot spots" and remembers your query anyways even if you close the PreparedStatement, you still incur network overhead as well as small processing time.
In short, keep the Connection and PreparedStatement open until you are done with them.
Edit: To comment on not returning a ResultSet from the execution, this is fine. executeQuery will return the ResultSet for whatever query just executed.
Firstly I am confused about your code
s = con.prepareStatement();
Is it work well?I can't find such function in JAVA API,at least one parameter is needed.Maybe you want to invoke this function
s = con.createStatement();
I just ran my code to access DB2 for twice with one single Statement instance without close it between two operation.It's work well.I think you can try it yourself too.
String sql = "";
String sql2 = "";
String driver = "com.ibm.db2.jcc.DB2Driver";
String url = "jdbc:db2://ip:port/DBNAME";
String user = "user";
String password = "password";
Class.forName(driver).newInstance();
Connection conn = DriverManager.getConnection(url, user, password);
Statement statement = conn.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
int count = 0;
while (resultSet.next()) {
count++;
}
System.out.println("Result row count of query number one is: " + count);
count = 0;
resultSet = statement.executeQuery(sql2);
while (resultSet.next()) {
count++;
}
System.out.println("Result row count of query number two is: " + count);
We are trying to fetch data from Oracle DB using a PreparedStatement. It keeps fetching zero records while the same runs and fetches data when run from PL/SQL developer.
We found the root cause while trying to debug. While debugging the code fetched the two records properly.
We did a temporary fix by placing this piece of code.
ResultSet rs = ps.executeQuery();
while(!rs.hasNext()){
ps.executeQuery();}
This works. But this is not the best solution since it results in an unwanted DB hit.It clearly looks like a time issue. We also explicitly committed earlier transactions since they can affect the result of this query.
What could be causing this. What's the best way to solve this?
The method is quite big: I'll just post some parts here:
private static boolean loadCommission(Member member){
Connection conn = getConnection("schema1"); //obtained through connection pool
//insertion into table
conn.close();
Conn conn2 = getConnection("schema2"); //obtained through connection pool
PreparedStatement ps = conn2.prepareStatement(sql);
//this sql combines data from schema1
// and 2 with DB links
ResultSet rs = ps.executeQuery();
//business logic
conn2.close();
return true;
}
Thanks
We tried a few more things yesterday. We replaced the second connection code with direct jdbc connection like so
Connection conn = DriverManager.getConnection(URL, USER, PASS);
This too works. Now we are not sure if the delay is in getting connection from pool or in completing previous transaction like we thought earlier.
If your query selects from a materialized view, then there may be some elapsed time before it will yield results (as materialized views do not necessarily refresh instantly after a commit, depending upon how they've been created).
If this is the case, then you can resolve the problem by either selecting directly from the base table (or equivalent non-materialized views), or forcing the materialized view to refresh.