I'm developing a software in Java processing data in a MySQL database and I'm facing an issue due to a rollback call not doing what I was expecting ... My function is composed of two queries and I need to rollback if the second query is not executed (or with errors) in order to keep consistent data. Here is my code, I've been doing a syntax error on purpose for throwing an error during the second query execution. The rollback method is called but my first statement is executed and committed in my database, can you explain me why ?
#Override
public void updateIndicatorRemainingTimeAndExecuted(int id) throws ServiceException {
PreparedStatement stmt = null;
Connection con = null;
String query1 = "UPDATE "+indicatorSchedulerTable+" i "
+"JOIN adv_frequency f ON i.id_frequency = f.id_frequency "
+"SET i.ind_remainingtime = i.ind_remainingtime + f.frq_seconds WHERE id_indicator = ?";
String query2 = "UPDATE "+indicatorSchedulerTable
+" SET ind_executing = WHERE id_indicator = ?";
try {
con = mySQLManipulator.getConnection();
stmt = con.prepareStatement(query1);
stmt.setInt(1,id);
/*Updating remaining time*/
stmt.executeUpdate();
stmt.close();
/*Updating executing status*/
stmt = con.prepareStatement(query2);
stmt.setInt(1,id);
stmt.executeUpdate();
con.commit();
} catch (SQLException e) {
try {
con.rollback();
System.out.println("ROLLBACK OK");
} catch (SQLException e1) {
throw new ServiceException("Problème de rollback lors de la mise à jour dans la fonction \"updateIndicatorRemainingTimeAndExecuted\" : "+e1.getMessage()+e.getMessage());
}
throw new ServiceException("Problème lors de la mise à jour dans la fonction \"updateIndicatorRemainingTimeAndExecuted\" : "+e.getMessage());
} finally {
handleDatabaseClosure(con, stmt, null);
}
}
I'm also using a pool of connection like this maybe the error is because of this :
public class JDBCManipulator {
private static final BasicDataSource dataSource = new BasicDataSource();
private DBType type = null;
private String URI = null;
public JDBCManipulator(DBType type, String URI, String user, String password) throws Exception {
if(type == DBType.PHOENIX){
Class.forName("org.apache.phoenix.jdbc.PhoenixDriver");
} else if(type == DBType.MYSQL) {
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl(URI);
dataSource.setUsername(user);
dataSource.setPassword(password);
dataSource.setMaxActive(20);
dataSource.setDefaultAutoCommit(false);
} else {
throw new Exception("Le type fournit ("+type+") pour l'initialisation de JDBCManipulator n'est pas connu ...");
}
this.type = type;
this.URI = URI;
}
public Connection getConnection() throws SQLException {
Connection conn = null;
if(type == DBType.MYSQL){
conn = dataSource.getConnection();
} else {
conn = DriverManager.getConnection(URI);
}
return conn;
}
}
You have to set autoCommit of the connection to false.
con.setAutoCommit(false);
Otherwise, each executed update would be commited immediatelly.
In addition, use a storage engine that supports transactions like InnoDB. MyISAM does not support transactions.
I was able to get everything working by replacing ENGINE=MyISAM with ENGINE=INNODB in my CREATE statement. Thank you all for your help!
Related
I'm creating a simple app which uses JDBC to get data from MySQL. I use a dao to get data from the database. All but one are working fine (code is the same for all DAOs). Also I'm committing INSERT and UPDATE methods manually.
Workbench returns valid result even if I set isolation level read committed manually.
JDBCSessionDao create method:
public void create(Session session) throws SQLException{
try(PreparedStatement ps = conn.prepareStatement(INSERT_SESSION)){
conn.setAutoCommit(false);
LocalTime start = session.getStartTime();
LocalTime end = session.getEndTime();
System.out.println(start + ", " + end);
System.out.println(Time.valueOf(start) + ", " + Time.valueOf(end));
ps.setTime(1, Time.valueOf(start));
ps.setTime(2, Time.valueOf(end));
ps.setDate(3, Date.valueOf(session.getDate()));
ps.setLong(4, session.getMovieId());
ps.executeUpdate();
conn.commit();
conn.setAutoCommit(true);
}
catch (SQLException e){
logger.error(e.getMessage());
conn.rollback();
}
}
JDBCSessionDao findByDate method
public List<Session> findByDate(LocalDate date) {
List<Session> sessions = new ArrayList<>();
SessionMapper mapper = new SessionMapper();
try(PreparedStatement ps = conn.prepareStatement(SELECT_BY_DATE_ORDER_BY_TIME_ASC)){
ps.setDate(1, Date.valueOf(date));
ResultSet rs = ps.executeQuery();
System.out.println(rs.getFetchSize());
while(rs.next()){
Session s = mapper.extractFromResultSet(rs);
sessions.add(s);
}
}
catch (SQLException e){
logger.error(e.getMessage());
}
return sessions;
}
Query:
String SELECT_BY_DATE_ORDER_BY_TIME_ASC = "SELECT * FROM sessions WHERE session_date=? ORDER by start_time ASC";
JDBCDaoFactory getConnection() method:
private Connection getConnection(){
String url = "jdbc:mysql://localhost:3306/cinemajee?useLegacyDatetimeCode=false&serverTimezone=Europe/Kiev";
String user = "root";
String password = "root";
try{
Class.forName("com.mysql.cj.jdbc.Driver");
return DriverManager.getConnection(url, user, password);
}
catch (SQLException | ClassNotFoundException e){
e.printStackTrace();
throw new RuntimeException();
}
}
Query result in workbench:
query result
Try modifying the query in your code. Perhaps the session_date parameter isn't working. So change from this:
"SELECT * FROM sessions WHERE session_date=? ORDER by start_time ASC"'
to this:
"SELECT * FROM sessions ORDER by start_time ASC LIMIT 5"'
I've forgot to change column names in SessionMapper, they were written in camel case (e.g. sessionId) but my db columns is in snake case (e.g. session_id).
private void totaleActionPerformed(java.awt.event.ActionEvent evt) {
PreparedStatement ps;
ResultSet rst;
String query="SELECT SUM( montant_m) FROM `mnd` ";
String num_m = jTF1.getText();
try {
ps=Connecteur_db.connecterDB().prepareStatement(query);
// ps.setString(1, num_m);
rst=ps.executeQuery();
if(rst.next()){
String som_t = rst.getString("SUM(montant_m)");
jLabe_resultat.setText(""+som_t);
JOptionPane.showMessageDialog(null,""+som_t);
}
} catch (SQLException ex) { java.util.logging.Logger.getLogger(noveau_j.class.getName()).log(Level.SEVERE, null, ex);
}
}
While trying to execute this i am getting an error like "Caused by: java.sql.SQLException: Column 'SUM(montant_m)' not found.
at What is the problem here?? Please help me..
Sorry for my poor english
This is myconnecteur_db() class the connection
public static Connection connecterDB() {
Connection conx = null;
String pilot = "com.mysql.cj.jdbc.Driver";
try {
Class.forName(pilot);//chargement de driver
System.out.println("Driver ok");
String url = "jdbc:mysql://localhost:3307/tc";
String user = "root";
String pw;
pw = "root";
Connection con = DriverManager.getConnection(url, user, pw);
System.out.println("la connection est bien etablir");
return con;
} catch (Exception e) {
System.out.println("Echec connection!!");
e.printStackTrace();
return null;
}
}
I assume this is occuring at the line rst.getString("SUM(montant_m)")
SUM(montant_m) doesn't have a space before montant_m.
To make it easier, use the query:
SELECT SUM(montant_m) AS total FROM mnd
And then rst.getString("total")
i have been using this JDBC conection in all of my class that had to run query but i created a new class which i dont want the constructor with a parameter of the DConnection from JDBC Class(main Database Class).
but i keep on getting NullPointExceptions. Can anyway figur out what that problem may be.
Thanks.
public class UsersDao {
// associating the Database Connection objekt
private DConnector connector;
private final Connection myConn;
// Constructor
public UsersDao() throws CZeitExceptionHand,SQLException {
myConn = connector.getConnenction();
}
public boolean updateUsers(String mitarb, int mid) throws SQLException{
// PreparedStatement myStmt = null;
Statement stmt = myConn.createStatement();
try {
String myStmt = "SELECT Bly "
+ "" + mid + ";";
return stmt.execute(myStmt);
} finally {
close(stmt);
}
}
Example like this Method which is working but in different class
String[][] getAllTheWorkers(DConnector connector) throws CZeitExceptionHand {
try {
Connection connect = connector.getConnenction();
Statement stmt = connect.createStatement();
ResultSet result = stmt.executeQuery("SELECT ");
result.last();
int nt = result.getRow();
result.beforeFirst();
}
return results;
} catch (SQLException e) {
throw new CZeitExceptionHand("Error: " + e);
}
}
The object does not seem to be initialized.
Can you please post which method is not working and from where it is invoked ?
P.S : Unable to add a comment - that is why have answered !
I'm getting this error even though I am not trying to edit the table/column:
com.ibm.db2.jcc.am.SqlSyntaxErrorException: The operation failed because the operation is not supported with the type of the specified table. Specified table: "DASH103985.wajihs". Table type: "ORGANIZE BY COLUMN". Operation: "WITH RS".. SQLCODE=-1667, SQLSTATE=42858
#MultipartConfig
public class DemoServlet extends HttpServlet {
private static Logger logger = Logger.getLogger(DemoServlet.class.getName());
private static final long serialVersionUID = 1L;
#Resource(lookup="jdbc/db2")DataSource dataSource;
private String getDefaultText() {
TweetsCombined = new String(" ");
try {
// Connect to the Database
Connection con = null;
try {
System.out.println("Connecting to the database");
} catch (SQLException e) {
TweetsCombined = "first" +e;
}
// Try out some dynamic SQL Statements
Statement stmt = null;
try {
stmt = con.createStatement();
String tableName = "wajihs";// change table name here to one
// chosen in the first website
String columnName = "msgBody";// msgBody is where the tweets
// are stored
String query = "SELECT * FROM \"" + tableName + "\"";
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
content = rs.getString(columnName) + ". ";
if (content.toLowerCase().contains("RT".toLowerCase())
|| content.toLowerCase().contains("Repost: ".toLowerCase())) {
// do nothing
}
else {
TweetsCombined.concat(content);
}
}
// Close everything off
// Close the Statement
stmt.close();
// close
con.commit();
// Close the connection
con.close();
} catch (Exception e) {
TweetsCombined = "second" +e;
System.out.println(e.getMessage());
}
} catch (Exception e) {
TweetsCombined = "third" + e;
System.out.println(e);
}
return TweetsCombined;
}
As I explained here, dashDB, with its BLU Acceleration features, has certain limitations compared to DB2 without BLU Acceleration. In your case it is that you can only run queries with the CS isolation level against column-organized tables.
Either change your connection configuration to use CS isolation level or create your table(s) while explicitly specifying ORGANIZE BY ROW.
I have this class in my NetBeans project:
public class ConexionBD
{
private Connection conexion;
private Statement consulta;
private final String ruta;
private final String claseDriver;
private final String driver;
public ConexionBD(String ruta)
{
this.ruta = ruta;
this.claseDriver = "org.sqlite.JDBC";
this.driver = "jdbc:sqlite:";
}
public void conectar() throws SQLException, ClassNotFoundException
{
Class.forName(this.claseDriver);
this.conexion = DriverManager.getConnection(this.driver + this.ruta);
System.out.println("Opened database successfully");
this.consulta = this.conexion.createStatement();
System.out.println("Statement created successfully");
}
public ResultSet consultar(String sql) throws SQLException
{
ResultSet resultado = this.consulta.executeQuery(sql);
System.out.println(this.consulta.getConnection());
return resultado;
}
}
And this method which use it:
private void buildTableView()
{
ConexionBD c = new ConexionBD(System.getProperty("user.dir") + "bbdd");
ObservableList<ObservableList> data FXCollections.observableArrayList();
System.out.println(System.getProperty("user.dir") + "\\bbdd");
try
{
c.conectar(); //WORKS FINE
}
catch(ClassNotFoundException | SQLException e)
{
Constantes.showAlert(AlertType.ERROR, "Error", "Error de base de datos", "Error de conexión");
}
try
{
String sql = "select name from controller";
ResultSet rs = c.consultar(sql); //THROWS SQLException
while(rs.next())
{
ObservableList<String> row = FXCollections.observableArrayList();
row.add(rs.getString(1));
data.add(row);
}
reguladores.setItems(data);
}
catch(SQLException e)
{
Constantes.showAlert(AlertType.ERROR, "Error", "Error de base de datos", "Error al obtener los datos");
}
try
{
c.cerrar();
}
catch (SQLException ex)
{
Constantes.showAlert(AlertType.ERROR, "Error", "Error de base de datos", "Error al cerrar la conexión");
}
The connection method seems to work fine, but when it executes the method which calls the "executeQuery(sql)" method, it throws the SQLException.
I think I configured the jdbc driver, ojdbc library and database fine, but I can't find why the method doesn't do its job. Any clue?
The stack trace:
java.sql.SQLException: no such table: controller
at org.sqlite.DB.throwex(DB.java:288)
at org.sqlite.NestedDB.prepare(NestedDB.java:115)
at org.sqlite.DB.prepare(DB.java:114)
at org.sqlite.Stmt.executeQuery(Stmt.java:89)
at app.ConexionBD.consultar(ConexionBD.java:37)
at app.controllers.InicioController.buildTableView(InicioController.java:145)
The table does exist in database
Try to fully qualify your table name like OWNER.TABLE_NAME
Make sure the account you connect with has SELECT privilege granted to it from the table owner
Those are my two obvious suggestions
Brute force is to examine all tables like so:
DatabaseMetaData md = connection.getMetaData();
ResultSet rs = md.getTables(null, null, "%", null);
while (rs.next()) {
System.out.println(rs.getString(3));
}