0

I am using the following code to begin and commit a transaction.

final static Object lock = new Object();
@Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public String addRequest(String actionCode) throws Exception {
    synchronized (this.getClass()) {

        Session session = dao.getCurrentSession();
        try {
            System.out.println("start");

            Transaction tr = session.getTransaction();
            tr.begin();

            certRequest
                    .setRequestNbr(generateRequestNumber(certInsuranceRequestAddRq
                            .getAccountInfo().getAccountNumberId()));
            reqId = Utils.getUniqueId();
            certRequest.setRequestId(reqId);

            ItemIdInfo itemIdInfo = new ItemIdInfo();

            itemIdInfo.setInsurerId(certRequest.getRequestId());

            certRequest.setItemIdInfo(itemIdInfo);

            Serializable it = session.save(certRequest);
            if (it != null) {
                addAccountRel();

                System.out.println("\n \n Transaction value is as " + it);
                if (!tr.wasCommitted())
                    tr.commit();
                System.out.println("\n \n Refresh value is "
                        + generateRequestNumber(certInsuranceRequestAddRq
                                .getAccountInfo().getAccountNumberId()));


    }
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }
        System.out.println("end1");
    }
    return reqId;
}

However I get the following exception.

org.springframework.transaction.TransactionSystemException: Could not commit Hibernate transaction; nested exception is org.hibernate.TransactionException: Transaction not successfully started
    at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:660)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
    at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$afterReturning$org_springframework_transaction_aspectj_AbstractTransactionAspect$3$2a73e96c(AbstractTransactionAspect.aj:82)
    at com.csc.exceed.uow.RequestAddUOW.addRequest(RequestAddUOW.java:405)
    at com.csc.exceed.uow.RequestAddUOW.invokeService(RequestAddUOW.java:82)
    at resources.rules.uow.Rule_Add_Request_0.defaultConsequence(Rule_Add_Request_0.java:7)
    at resources.rules.uow.Rule_Add_Request_0DefaultConsequenceInvoker.evaluate(Rule_Add_Request_0DefaultConsequenceInvoker.java:29)
    at org.drools.common.DefaultAgenda.fireActivation(DefaultAgenda.java:917)
    at org.drools.common.DefaultAgenda.fireNextItem(DefaultAgenda.java:856)
    at org.drools.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1071)
    at org.drools.common.AbstractWorkingMemory.fireAllRules(AbstractWorkingMemory.java:785)
    at org.drools.common.AbstractWorkingMemory.fireAllRules(AbstractWorkingMemory.java:761)
    at org.drools.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:226)
    at com.csc.exceed.infrastructure.BusinessProcessManager.executeRules(BusinessProcessManager.java:35)
    at com.csc.exceed.infrastructure.BusinessProcessManager.executeUOWSequence(BusinessProcessManager.java:72)
    at com.csc.exceed.controller.RequestHandler.service(RequestHandler.java:169)
    at com.csc.exceed.controller.ControllerServlet.doPost(ControllerServlet.java:54)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    at java.lang.Thread.run(Thread.java:619)
Caused by: org.hibernate.TransactionException: Transaction not successfully started
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:131)
    at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
    ... 32 more


 error msz is Could not commit Hibernate transaction; nested exception is org.hibernate.TransactionException: Transaction not successfully started

I have also tried Transaction tr = session.beginTransaction();

in place of "Transaction tr = session.getTransaction(); tr.begin();" but that also is not working. Please suggest!

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
pkn1230
  • 103
  • 1
  • 3
  • 15
  • Don't... Spring is managing the transaction, remove all transaction en session management logic from your code. Just do `sessionFactory.getCurrentSession` do your thing and be done. That is the whole point of `@Transactional`. – M. Deinum Sep 15 '15 at 06:59
  • hi @M.Deinum, I am trying to work on the following issue http://stackoverflow.com/questions/32522850/data-commit-issue-in-multithreading. That's why I'v applied the transaction logic. Could you please suggest some alternate solution in case I remove Transaction logic from my code? – pkn1230 Sep 15 '15 at 07:02
  • @pkn1230 You have to add a roleback in the else case of `if (it != null) {` – Jens Sep 15 '15 at 07:07
  • Use `@Transactional(isolation=SERIALIZABLE)`. Don't try to fix this in code as that will always fail, you might be able to fix it for a single node, but as soon as you deploy it on multiple machines it won't work anymore. Use the database for that. – M. Deinum Sep 15 '15 at 07:07
  • Also what is the `generateRequestNumber` actually doing? (But that might be more appropriate in the other thread). – M. Deinum Sep 15 '15 at 07:11
  • @M.Deinum generateRequestNumber() generates a request number by joining two Database tables and finding the maximum request number the result generated. Also what do you mean by "Use the database for that" and "(But that might be more appropriate in the other thread)" – pkn1230 Sep 15 '15 at 07:15
  • To synchronize use the database, don't even try to fix this in code as it will fail as soon as you start adding application servers. Use the proper isolation level for it. You already have a thread add the actual `generateRequestNumber` there. I would probably put that in a separate service, annotate that method with `@Transactional(isolation-SERIALIZABLE)` to prevent excessive locking of the database (unless the number needs to be rollback in case of an error). – M. Deinum Sep 15 '15 at 07:17
  • Hi @M.Deinum I read somewhere that @Transactional(isolation-SERIALIZABLE) doesn't locks the database for read operations, Is it true? If yes then even after applying @Transactional(isolation-SERIALIZABLE) ,the problem won't resolve – pkn1230 Sep 15 '15 at 07:20
  • It will... Depending on your database you might need to tweak your select statement a little but it will. See also the link in the answer, which contains the following quote *"With a lock-based concurrency control DBMS implementation, serializability requires read and write locks (acquired on selected data) to be released at the end of the transaction."* – M. Deinum Sep 15 '15 at 07:23

2 Answers2

0

Writing transaction synchronization code is hard and will fail as soon as you start deploying the application to multiple servers. To resolve the issue use the proper isolation level for the transaction

First of all remove all the transaction and session management code and syncronized stuff as you don't need it. Next simply annotate your method with @Transactional(isolation=SERIALIZABLE) to have locking on the database level, which will work regardless the number of application servers you have.

@Transactional(isolation=SERIALIZABLE, rollbackFor = Exception.class)
public String addRequest(String actionCode) throws Exception {

    Session session = dao.getCurrentSession();
    System.out.println("start");

    certRequest
                .setRequestNbr(generateRequestNumber(certInsuranceRequestAddRq
                        .getAccountInfo().getAccountNumberId()));
    reqId = Utils.getUniqueId();
    certRequest.setRequestId(reqId);

    ItemIdInfo itemIdInfo = new ItemIdInfo();

    itemIdInfo.setInsurerId(certRequest.getRequestId());

    certRequest.setItemIdInfo(itemIdInfo);

    Serializable it = session.save(certRequest);
    if (it != null) {
            addAccountRel();
            System.out.println("\n \n Transaction value is as " + it);
            System.out.println("\n \n Refresh value is "
                    + generateRequestNumber(certInsuranceRequestAddRq
                            .getAccountInfo().getAccountNumberId()));
    }
    System.out.println("end1");
    return reqId;
}

To me it also looks like your code is flawed, as it looks like reqId and certRequest are instance variables, I don't see them passed into the method. For some reason it also looks wrong to me that you are generating a requestNumber twice, once outside and once inside the if statement.

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
  • Hi @M.Deinum , I have removed the Transaction and the session logic from my Java Code. But now what happens is, one of my thread executes successfully, but the other one gives a "Hibernate- flushing" exception. – pkn1230 Sep 15 '15 at 09:03
  • Without the exception this comment doesn't do much... Add it to your question, or start a new one. And I expressed a couple of concerns in my answer, could you respond to those as well as your class seems wrong on multiple levels? – M. Deinum Sep 15 '15 at 09:22
  • Hi @M.Deinum, please find the new question as well as the clarification for your questions at http://stackoverflow.com/questions/32582746/isolation-level-exception – pkn1230 Sep 15 '15 at 09:43
  • There is no clarification. Your service is flawed as it appears that you are keeping instance state... Don't do that. – M. Deinum Sep 15 '15 at 09:46
  • could you please clarify what do you mean by keeping "instance state..."? – pkn1230 Sep 15 '15 at 09:57
  • If you have to ask that question I suggest a basic Java tutorial. Your method only accepts the `actionCode`. However you are using other properties like `certRequest` and `reqId` which are never passed in or created inside the method. Hence they are probably declared at the instance level... As services are generally speaking singletons what do you think happens to the `certRequest` if you have 100 concurrent requests hammering on the method? – M. Deinum Sep 15 '15 at 09:58
  • please ignore my inexperience with Java, but could you please provide me with what should I change exactly? – pkn1230 Sep 15 '15 at 10:09
  • No i cannot because I don't now your project. Don't keep state in singletons as that is shared amongst threads... You have greater problems in your code then the generations of the next request id... – M. Deinum Sep 15 '15 at 10:11
  • Ok, i got it, Meanwhile could you please suggestion how to resolve the Exception that I am getting? Should I use isolation level as "READ_UNCOMMITTED"? – pkn1230 Sep 15 '15 at 10:19
  • No you need SERIALIZABLE else you won't get locking... Fix your code before trying to fix other things. Also why are things batched? That I don't get. – M. Deinum Sep 15 '15 at 10:24
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/89665/discussion-between-pkn1230-and-m-deinum). – pkn1230 Sep 15 '15 at 10:29
0

You are trying to create a new transaction thought you seem to say Spring to handle the transaction. Either you or it should do it.

From your comments/links on post, I understand that you have some dirty reads that doesn't allow you to achieve what you wanted. Your Isolation.SERIALIZABLE will help you on it.

Whatever M. Deinum has posted is correct.

Karthik R
  • 5,523
  • 2
  • 18
  • 30