Rollback is working on a transaction but crashes anyway by SQLNonTransientConnectionException - java

I'm working on a cinema ticketing java application.
There is a grid of chairs, the user selects all chairs to book, then press ok to book it (insert rows in a mysql database). If any of the bookings pretended to do fails due to duplicate entries, all of them are rollbacked.
To do it, listening button "buy" I do:
case "buy":
try {
boolean success = true;
for(Booking b : bookingsToDo) {
if(DbConnect.getConnection().getAutoCommit())
DbConnect.getConnection().setAutoCommit(false);
success = controllerBooking.insertBooking(b);
if(!success) {
JOptionPane.showMessageDialog(frameMain, "Error occurred, booking failed");
DbConnect.getConnection().rollback();
}
}
if(success) {
JOptionPane.showMessageDialog(frameMain, "Booking done");
DbConnect.getConnection().commit();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
This is working, because actually all the bookings are being reversed.
But anyway is throwing: java.sql.SQLNonTransientConnectionException:
Can't call rollback when autocommit=true
so the program fails then.
How is it possible that rollback is working and at the same time throwing a "Can't rollback" message? And how could it be when I'm doing setAutoCommit(false) in every loop?

DbConnect.getConnection() is getting a new connection each time its called.
Autocommit is set on a per connection basis. Therefore you are rolling back on a different connection. The controllerBooking also needs a connection reference to use the same connection.
So:
con = DbConnect.getConnection();
con.setAutoCommit(false);
for(Booking b : bookingsToDo) {
success = controllerBooking.insertBooking(con, b);
if(!success) {
JOptionPane.showMessageDialog(frameMain, "Error occurred, booking failed");
con.rollback();
break;
}
}
con.commit();

Related

Why JPA/Hibernate transaction is active even when I did not start one explicitly

My problem is that JPA/Hibernate returns true for a call of entityManager.getTransaction().isActive() even when I did not explicitly start a transaction (see code below).
The problem here is that I want to read something from the database and a SerializationException is ok in this scenario, because this just indicates that the persisted object does not fit to the actual code any more and needs to be recalculated. Instead of just returning null the code below throws the following exception:
Transaction rollback failed.
org.hibernate.TransactionException: Unable to rollback against JDBC Connection
This shows me, there must have been a transaction somewhere which I did not start in my code. The finally block in the code above is
final EntityManager entityManager = Persistence.createEntityManagerFactory("test").createEntityManager();
try {
final TypedQuery<Test> query = entityManager.createQuery("SELECT t FROM test t", Test.class);
return query.getResultList();
} catch (final PersistenceException e) {
if (e.getCause() instanceof SerializationException) {
LOG.debug("Implementation changed meanwhile. That's ok - we return null.");
return null;
}
throw e;
} finally {
EntityManagerCloser.closeEntityManager(entityManager);
}
And the EntityManagerCloser looks like this:
public final class EntityManagerCloser {
private static final Logger LOG = LoggerFactory.getLogger(EntityManagerCloser.class);
public static void closeEntityManager(EntityManager entityManager) {
if (entityManager.getTransaction().isActive()) {
try {
entityManager.getTransaction().rollback();
} catch (PersistenceException | IllegalStateException e) {
LOG.error("Transaction rollback failed.", e);
}
}
if (entityManager.isOpen()) {
try {
entityManager.close();
} catch (IllegalStateException e) {
LOG.error("Closing entity manager failed.", e);
}
}
}
}
Hibernate docs says "Always use clear transaction boundaries, even for read-only operations". So do I really need to insert a
entityManager.getTransaction().begin();
....
<do read here>
....
entityManager.getTransaction().commit();
around every read operation I perform on the database?
I could implement another closeEntityManager method for read-only operations without the rollback transaction block but I want to understand why there IS a transaction at all. Thanks for any help!
The problem is that when you call entityManager.getTransaction(); a new transaction object will be created. So it is better to save the transaction reference to a variable as shown below.
Transaction txn = entityManager.getTransaction();
if (txn.isActive()) {
try {
txn.rollback();
} catch (PersistenceException | IllegalStateException e) {
LOG.error("Transaction rollback failed.", e);
}
}
Thanks to Jobin I quickly found the solution to my problem:
I think I need to call entityManager.isJoinedToTransaction() in my closeEntityManager method before calling entityManager.getTransaction().isActive().
This will prevent the EntityManagerCloser to start its own transaction which I can not rollback later because I did not explicitly call transaction.begin() on it.

Postgres Query to know the db is up and running

(EDITED)
I am using the following code to check if my Postgres db is up and running. However if the machine running the db is slow (Not enough RAM for example) it sometimes pass but when i tried to get some real data from the db (a few millisec after) i fail. I guess because not all tables were loaded.
Here is my code:
public static boolean testDBConnection(boolean refreshFactory) throws Exception
Session session = null;
try {
if(refreshFactory){
ConnectionUtil.refreshSessionFactory();
}
session = ConnectionUtil.getSessionFactory().openSession();
String sql = "select 1";
session.createSQLQuery(sql).list();
return true;
}
catch (HibernateException e) {
String error = "Failed to connect db.";
throw ExceptionFactory.create(error);
}
finally{
if(session!=null){
session.close();
}
}
}
Is there a better way then "select 1"?
Thanks

How to handle reversal with JPA?

I am using Spring and JPA for a financial data handling project. I have to handle scheduling transactions for future dates. In a daily run quartz cron job and execute all schedule transaction and persist to real table.
My problem is, when going to execute trigger for a given time, one record failed due to some reason, then all other records were not executed.
I need to execute all other transactions and failed transactions should rollback.
Is there a way to handle these things?
following code block get all the schedule job
public void bankingPaymentSchedullerRun(){
// get all pending job
List<BankScheduler> bankSchedulers = bankSchedulerDao.findByStatus(ScheduleStatus.PENDING);
Calendar currentDate = DateUtil.getFormatedCalenderDate(DateUtil.currentDate(), "yyyy-MM-dd");
if (bankSchedulers != null) {
for (BankScheduler bankScheduler : bankSchedulers) {
LOGGER.info("bankingPaymentSchedullerRun " + bankScheduler.toString());
//compare from date and to date
if ((bankScheduler.getFromDate().compareTo(currentDate) <= 0)
&& (bankScheduler.getToDate().compareTo(currentDate)) >= 0) {
if (bankScheduler.getSchedulerType().equals(SchedulerType.FUND_TRANSFER.toString())) {
scheduleFundTransfer(bankScheduler);
}else {
scheduleUtilityPayment(bankScheduler);
}
}
}
}
}
Fund transfer execution code block
public PaymentResponse scheduleFundTransfer(final BankScheduler bankScheduler){
FundTransfer fundTransfer = new FundTransfer();
fundTransfer.setBranchName(bankScheduler.getBankSchedulerFundTransfer().getBeneficiaryBranchName());
fundTransfer.setBeneficiaryBankName(bankScheduler.getBankSchedulerFundTransfer().getBeneficiaryBankName());
fundTransfer.setBeneficiaryType(bankScheduler.getBankSchedulerFundTransfer().getBeneficiaryType());
fundTransfer.setBeneficiaryName(bankScheduler.getBankSchedulerFundTransfer().getBeneficiaryName());
fundTransfer.setCurrency(bankScheduler.getBankSchedulerFundTransfer().getCurrency());
fundTransfer.setNarration(bankScheduler.getDetail());
fundTransfer.setThirdPartyType(bankScheduler.getBankSchedulerFundTransfer().getThirdPartyType());
fundTransfer.setTransferedAmount(bankScheduler.getBankSchedulerFundTransfer().getAmount());
fundTransfer.setUserAccountNumber(bankScheduler.getBankSchedulerFundTransfer().getAccountNumber());
fundTransfer.setUserName(bankScheduler.getBankSchedulerFundTransfer().getUserName());
FundTransfer fundTransferUpdate = null;
//commit to fundtransfer real table
try {
fundTransferUpdate = fundTransferDao.create(fundTransfer);
} catch (Exception e) {
LOGGER.error("Exception occur when call update fund transfer in fundTransfer()", e);
}
// getting from currecy Decimals
BankCurrecyInfor currecyInfo =
bankCurrecyInforDao.getDecimalpointsByCurrecy(fundTransfer.getUserAccount().getCurrencyCode());
fundTransferUpdate.setDecimalAmt(String.valueOf(currecyInfo.getNoOfDecimal()));
//call to bank back-end to update
PaymentResponse response = accountServiceInvoker.fundTransfer(fundTransferUpdate);
//for sending sms
SmsCriteria smsCriteria = new SmsCriteria();
smsCriteria.setBank_name("ABC");
messageServiceInvoker.sentIbSms(smsCriteria);
return response;
}
Yes there is, use proper exception handling so when single transaction fails, other will still (try to) execute.
Pseudocode
for(scheduled task from all scheduled tasks) {
try{
begin transaction
do your stuff with jpa
commit transaction
}catch(Exception e){
rollback transaction, log error and stuff
}finally{
release resources
}
}

ldap transaction protocol error

I’m writing in order to get some help.
To be short, I’m trying to use com.unboundid.ldap.sdk (but it is not necessary - the same problem i get if i use oracle's javax.naming.ldap.*) to handle with ldap transactions, and I get the following error:
Exception in thread "Main Thread" java.lang.AssertionError: Result EndTransactionExtendedResult(resultCode=2 (protocol error), diagnosticMessage='protocol error') did not have the expected result code of '0 (success)'.
at com.unboundid.util.LDAPTestUtils.assertResultCodeEquals(LDAPTestUtils.java:1484)
at pkg.Main.main(Main.java:116)
My program is the following ( I’m using simple example from https://www.unboundid.com/products/ldap-sdk/docs/javadoc/com/unboundid/ldap/sdk/extensions/StartTransactionExtendedRequest.html ) :
public class Main {
public static void main( String[] args ) throws LDAPException {
LDAPConnection connection = null;
try {
connection = new LDAPConnection("***", ***, "***", "***");
} catch (LDAPException e1) {
e1.printStackTrace();
}
// Use the start transaction extended operation to begin a transaction.
StartTransactionExtendedResult startTxnResult;
try
{
startTxnResult = (StartTransactionExtendedResult)
connection.processExtendedOperation(
new StartTransactionExtendedRequest());
// This doesn't necessarily mean that the operation was successful, since
// some kinds of extended operations return non-success results under
// normal conditions.
}
catch (LDAPException le)
{
// For an extended operation, this generally means that a problem was
// encountered while trying to send the request or read the result.
startTxnResult = new StartTransactionExtendedResult(
new ExtendedResult(le));
}
LDAPTestUtils.assertResultCodeEquals(startTxnResult, ResultCode.SUCCESS);
ASN1OctetString txnID = startTxnResult.getTransactionID();
// At this point, we have a transaction available for use. If any problem
// arises, we want to ensure that the transaction is aborted, so create a
// try block to process the operations and a finally block to commit or
// abort the transaction.
boolean commit = false;
try
{
// do nothing
}
finally
{
// Commit or abort the transaction.
EndTransactionExtendedResult endTxnResult;
try
{
endTxnResult = (EndTransactionExtendedResult)
connection.processExtendedOperation(
new EndTransactionExtendedRequest(txnID, commit));
}
catch (LDAPException le)
{
endTxnResult = new EndTransactionExtendedResult(new ExtendedResult(le));
}
LDAPTestUtils.assertResultCodeEquals(endTxnResult, ResultCode.SUCCESS);
}
}
}
As you can see, I do nothing with the transaction: just start and rolling back, but it still not working.
Connection is ok, and I receive transaction id = F10285501E20C32AE040A8C0070F7502 BUT IT ALWAYS THE SAME - is it all wrigth???
If “// do nothing” replace with some action exception: unwilling to perform.
I’m starting to think that it is OID problem, but I just can’t figure out what is wrong…
OID is on a WebLogic server and it’s version is :
Version Information
ODSM 11.1.1.6.0
OID 11.1.1.6.0
DB 11.2.0.2.0
All ideas will be appreciated.

Storm Crashing after 23 hours

Hello all I have a basic Storm application set up where it receives a stream of tweets and stores them in a MySQL database. The application works great for the first ~23 hours or so then it starts giving the following error:
SQL Exception
SQL State: 08003
After it does this a few times it dies. I'm using the standard JBDC connector to connect to the database from Java. The code for the functions for storing and setting up the DB connection are as follows:
private String _db="";
private Connection conn = null;
private PreparedStatement pst = null;
public ArchiveBolt(String db){
_db = db;
}
private void setupConnection() {
//Connect to the database
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:8889/twitter_recording", "root", "root");
} catch (Exception e){
e.printStackTrace();
}
}
public void execute(Tuple tuple, BasicOutputCollector collector) {
Status s = (Status) tuple.getValue(0);
//setup the connection on the first run through or if the connection got closed down
try {
setupConnection();
} catch (Exception e) {
// TODO: handle exception
System.out.println(e.toString());
}
try {
pst = conn.prepareStatement("INSERT INTO " + _db + " (tweet)" +
"VALUES (?);");
pst.setString(1, s.toString());
//execute the SQL
pst.executeUpdate();
} catch (SQLException ex) {
// handle any errors
System.out.println("SQLException: " + ex.getMessage());
System.out.println("SQLState: " + ex.getSQLState());
System.out.println("VendorError: " + ex.getErrorCode());
if(ex.getSQLState().equals("08003")){
setupConnection();
}
} finally {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
After it became apparent that it was crashing because of a 08003 error I decided that if it threw that error it should retry the set up of the connection, however that didn't help either. Could anyone point me in the right direction for solving this issue?
After it became apparent that it was crashing because of a 08003 error I decided that if it threw that error it should retry the set up of the connection, however that didn't help either. Could anyone point me in the right direction for solving this issue?
There are basically two problems here that need to be solved:
Why are the connections getting lost in the first place?
Why isn't your attempt to reconnect succeeding?
For the first problem, you should take a look at the MySQL logs to see if there are any indications there. And also, check for SQL exceptions immediately prior to the (repeated) "state 080003" exceptions. The latter are simply telling you that the connection has died previously.
My guess is that the problem is one of the following:
The MySQL server has timed out the connection due to inactivity. You can change the connection timeout in the MySQL configs if this is the problem.
Your application may be slowly leaking JDBC connections.
For the second problem, the general approach is correct, but your code doesn't match the description. In fact, it looks like it is always trying to establish a new database connection each time your execute method is called. This renders the reconnection call in your exception handler pointless. (OTOH, the code show signs that someone has been "beating on it" to try to get it to work ... and that could well be part of the problem.)
I would check that setupConnection is being called when it needs to be, and look for any exception that might be thrown. In addition, you should make sure that you explicitly close() the dead connection object ... and rethink / recode your connection management so that it doesn't leak.
For the record, there is a connection URL parameter called "autoReconnect" that in the distant past used to "deal" with lost connections. Unfortunately, the original implementation was unsafe, so they effectively disabled it; see this Question for details: Why does autoReconnect=true not seem to work?

Categories