Below is my Java program. I am calling a PLSQL procedure to update the Employee name. I turned off the commit in the PLSQL code so that I can do the commit and rollback from Java code. But even after I turned off the auto commit and doing explicit rollback, still the details are updated in the table.
How? I have no idea, please help.
Here's my Java code. In PLSQL, it just read the value and does an update statement . No commits.
public class TestCommit {
public static void main(String[] args) throws SQLException, IOException {
CallableStatement callableStatement = null;
Connection conn = null;
try {
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
conn = DriverManager
.getConnection("jdbc:oracle:thin:testuser/testpwd#//testdb:1521/testbx");
conn.setAutoCommit(false);
String sql = "{call testpkg.saveemployee(?,?)}";
callableStatement = conn.prepareCall(sql);
callableStatement.setString("name", "spider");
callableStatement.setString("id", "A101");
callableStatement.executeQuery();
conn.rollback();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
// Close the statement
callableStatement.close();
// Close the connection
conn.close();
}
}
}
edit: PLSQL
CREATE OR REPLACE PROCEDURE saveemployee(
name IN employee.ename%TYPE,
id IN employee.eid%TYPE)
IS
BEGIN
UPDATE employee SET ename = name WHERE eid = id;
END;
My bad, I was calling a wrong procedure, there were two versions of the same procedure in two different packages,
one has the commit , the other one doesn't have the commit. I was calling the one that had the commit.
Now that the commit is removed from both procedures, my code seems to work now.
Related
ConnectionClass:
Here I used stm.execute but I'm not getting an error. I also used executeUpdate but I'm also getting an error.
package com.company;
import java.sql.*;
class ConnectionClass {
private static Connection con = null;
private static Statement stm = null;
private static ConnectionClass connectionClass;
public void createConnection() {
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql", "root", "root");
}
catch (Exception e) {
e.printStackTrace();
}
}
public void createTable() {
String Table_Name = "BOOK";
try {
stm = con.createStatement();
DatabaseMetaData dbm = con.getMetaData();
ResultSet rs = dbm.getTables(null, null, Table_Name, null);
if (rs.next()) {
System.out.println("Table" + Table_Name + "Already created");
} else {
String sql = "CREATE TABLE" + Table_Name + "(ID VARCHAR(200), title VARCHAR(200),author varchar(100),publisher varchar(100)";
stm.executeLargeUpdate(sql);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public ConnectionClass() {
createConnection();
createTable();
}
}
MainClass:
Here I think the main class is working properly.
package com.company;
public class Main {
public static void main(String[] args) throws Exception {
ConnectionClass connectionClass = new ConnectionClass();
}
}
ERROR:
The method executeLargeUpdate was added in Java 8 / JDBC 4.2 and judging by the error it has not been implemented in the MySQL Connector/J version you are using.
The solution is simple: don't use any of the Large methods in the API, and instead use executeUpdate, or - better in the case of DML - execute. Alternatively, update to a newer version of MySQL Connector/J, as executeLargeUpdate is implemented in newer versions of MySQL Connector/J (eg 5.1.46, but at least 5.1.37 (the version that added support)).
You will also need to address the syntax error pointed out by Adil.
You have a syntax error in your query. You current SQL Query:
String sql = "CREATE TABLE" + Table_Name + "(ID VARCHAR(200), title VARCHAR(200),author varchar(100),publisher(100)";
Corrected SQL Query:
String sql = "CREATE TABLE" + Table_Name + "(ID VARCHAR(200), title VARCHAR(200),author varchar(100),publisher varchar(100)";
(You are asking mysql to create a column publisher, but where's the datatype? Simply specify the datatype and it will work.)
EDIT:
So, finally wrapping up this question, let's have a look at what Ora Docs have to say about this:
executeLargeUpdate:
default long executeLargeUpdate(String sql) throws SQLException
Executes the given SQL statement, which may be an INSERT, UPDATE, or DELETE statement or an SQL statement that returns nothing, such as an SQL DDL statement.
This method should be used when the returned row count may exceed Integer.MAX_VALUE - A constant holding the maximum value an int can have, 2^31-1.
Note:This method cannot be called on a PreparedStatement or CallableStatement.
The default implementation will throw UnsupportedOperationException. This method is introduced since JDK 1.8
Also note the above point as stated in the docs. The default implementation is to throw an UnsupportedOperationException. This means that different JDBC drivers can have different implementations of Statement class. They can either implement it or leave it unimplemented, and if you invoke the method in 2nd case, the method will throw an UnsupportedOperationException, as stated in the docs.
By checking the oracle docs for this method, you can get more information about it. So the possibility could be that the driver version you are using is not supporting this method, so please update tot eh latest version of this driver and try it out.
First let me describe the problem I am facing.
We are developing a web service using Jersey and MySQL at back-end. It's simple that user can view or edit data via Restful API, and the service will load/save data to or from MySQL database.
I created several stored procedure at MySQL server, like SelectAnswer and UpdateAnswer. In the program, we use standard JDBC and MySQL connector to connect to the database.
Firstly I created stored procedure per connection. Like each time the program start a new connection to the database, it creates a bunch of Stored Procedure.
public enum JDBCDataSource {
INSTANCE;
private BasicDataSource dataSource = new BasicDataSource();
private Connection conn;
private CallableStatement answerUpsert;
private JDBCDataSource(){
initConnection();
try{
conn = dataSource.getConnection();
answerUpsert = prepareSP(answerUpsert,"{call upsert_answer(?, ?, ?)}");
} catch (SQLException e) {
e.printStackTrace();
}
}
And the program reuse the stored procedure for each time calling:
private void executeUpsert(String app, String id, String content)
throws SQLException{
try {
CallableStatement callableStatement = JDBCDataSource.INSTANCE.getUpsert();
callableStatement.setString(1,app);
callableStatement.setInt(2,Integer.valueOf(id));
callableStatement.setString(3,content);
callableStatement.execute();
} catch (NumberFormatException e) {
e.printStackTrace();
} finally {
callableStatement.clearParameters();
}
}
So each time calling the procedure, the function set its own parameters, and execute the SP, and finally clear the parameters.
But it is not thread safe, if the user post two request and one request is trying to set parameters, and another to clear parameters, it will cause an exception.
So for stored procedure in MySQL, should I create it per transaction or per connection in order to keep it thread safe? Maybe my understanding of SP and MySQL is not correct, or maybe it is design problem. Please share your though for my question.
I'm writing a small program with a mysql connection. I have to insert data into the database. The connection is ok but when I try to execute a query it doesn't work. all statements after executeQuery() statement doesn't work.
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException, SQLException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
Connection connect=null;
PreparedStatement preparedStatement;
String JDBC_DRIVER="com.mysql.jdbc.Driver";
String DB_URL="jdbc:mysql//localhost/jarvis";
String USER = "test";
String PASS = "test";
try{
Class.forName(JDBC_DRIVER);
connect = DriverManager.getConnection(DB_URL, USER, PASS);
}
catch(ClassNotFoundException e){
out.println("Errore: "+e);
} catch (SQLException ex) {
Logger.getLogger(Prova.class.getName()).log(Level.SEVERE, null, ex);
}
out.println();
out.println("qui");
String query = "INSERT INTO users(Nome, Cognome, Username, Password) values(?, ?, ?, ?)";
try (PreparedStatement insert = connect.prepareStatement(query)) {
insert.setString(1, "name");
insert.setString(2, "sur");
insert.setString(3, "gvhgv");
insert.setString(4, "qfwe");
insert.executeUpdate();
}
catch(Exception e){
out.println("Errore "+e);
}
out.println("Fine");
}
on executeQuery it stop working and doesn't insert the values into the database.
P.S.: sorry for my English
foto
Firstly your JDBC Connection URL is wrong, it should be this
String DB_URL = jdbc:mysql://localhost/jarvis
instead of this:
String DB_URL = jdbc:mysql//localhost/jarvis
You can follow the MySQL documentation whenever you are in doubt about anything.
Please note that mentioning port is not necessary if it is skipped it would default to MySQL's default port 3306.
Secondly, use executeUpdate() method instead of executeQuery method. It is best suggested to test your code in chunks, like DB Connection is successful, able to retrieve data from the underlying DB and then inserting into the DB.
Or even a better way is to debug your code and at least provide where you find the NullPointerException as you say you're getting now!
Edit:
You must have your JDBC Connector/J jar available for your code to access it if you use an IDE (then in its build path) and in the CLASSPATH global variable (for references when we don't use an IDE). It is better to have it on your CLASSPATH if you are not going to change these dependencies any often.
Hope this helps!
I want to test a method where the following lines appear:
try (Connection connection = dataSource.getConnection()) {
((org.postgresql.PGConnection) connection).addDataType("geometry", Class.forName("org.postgis.PGgeometry"));
((org.postgresql.PGConnection) connection).addDataType("box3d", Class.forName("org.postgis.PGbox3d"));
try (Statement statement = connection.createStatement()) {
/*
* 4326 is the ID of a format in which the longitude and latitude values should be
* retreived.
*/
String sqlQuery = "SELECT ST_Transform(way, 4326) FROM planet_osm_line WHERE (highway='footway' OR highway='steps');";
ResultSet resultSet = statement.executeQuery(sqlQuery);
while (resultSet.next()) {
PGgeometry geom = (PGgeometry) resultSet.getObject(1);
LineString line = (LineString) geom.getGeometry();
Point[] wayPoints = line.getPoints();
pointList.add(wayPoints);
}
}
} catch (SQLException | ClassNotFoundException e) {
throw new OpenStreetMapDAOException(e.getMessage(), e);
}
those lines force me to catch a ClassNotFoundException, i.e. the call of Class.forName("name") does so.
The catch case for the ClassNotFoundException is never reached in my tests since these classes are always present. Is there a way to test my catch block?
As org.postgresql.PGConnection seems to be an interface, you could try to mock it via Mockito or a similar mocking framework.
org.postgresql.PGConnection connection = Mockito.mock(org.postgresql.PGConnection.class)
Mockito.doThrow( ...your exception here...).when( connection ).addDataType("geometry", Class.forName("org.postgis.PGgeometry"));
With these two lines you are creating a mock object for your connection which you can then use in your method. This mock object will throw the given exception when that method is called with these parameters.
I refactored the code from my question till I ended up with the following method for the critical part, i.e those Class.forName("some.class.name") calls:
Statement createStatement() throws SQLException, ClassNotFoundException {
Connection connection = dataSource.getConnection();
((org.postgresql.PGConnection) connection).addDataType("geometry", Class.forName("org.postgis.PGgeometry"));
((org.postgresql.PGConnection) connection).addDataType("box3d", Class.forName("org.postgis.PGbox3d"));
return connection.createStatement();
}
In my unit tests I then used
when(dao.createStatement()).thenThrow(ClassNotFoundException.class);
which finally solved my problem.
This is how I implement each jooq query that i want.
UtilClass{
//one per table more or less
static void methodA(){
//my method
Connection con = MySQLConnection.getConexion(); //open
DSLContext create = DSL.using(con, SQLDialect.MYSQL); //open
/* my logic and jooq querys */ //The code !!!!!!!
try {
if ( con != null )
con.close(); //close
} catch (SQLException e) {
} //close
con=null; //close
create=null; //close
}
}
Am I overworking here? / Is it safe to leave the Context and Connection Open?
In case it is safe to leave it open I would rather work with 1 static field DSLContext per UtilClass (and only the commented section would be on my methods). I would be opening a connection for each UtilClass since I am encapsulating the methods per table (more or less).
DSLContext is usually not a resource, so you can leave it "open", i.e. you can let the garbage collector collect it for you.
A JDBC Connection, however, is a resource, and as all resources, you should always close it explicitly. The correct way to close resources in Java 7+ is by using the try-with-resources statement:
static void methodA() {
try (Connection con = MySQLConnection.getConexion()) {
DSLContext ctx = DSL.using(con, SQLDialect.MYSQL); //open
/* my logic and jooq queries */
// "ctx" goes out of scope here, and can be garbage-collected
} // "con" will be closed here by the try-with-resources statement
}
More information about the try-with-resources statement can be seen here. Please also notice that the jOOQ tutorial uses the try-with-resources statement when using standalone JDBC connections.
When is DSLContext a resource?
An exception to the above is when you let your DSLContext instance manage the Connection itself, e.g. by passing a connection URL as follows:
try (DSLContext ctx = DSL.using("jdbc:url:something", "username", "password")) {
}
In this case, you will need to close() the DSLContext as shown above