1

I am currently creating a small project to mimic simple bank transactions.

Currently there are two types of transactions.

  1. Request transaction
    • Transaction is can be accepted or rejected.
    • Transaction can only be completed when recipient has made the decision
  2. Transfer transaction
    • Direct and instant. Minimum amount to send is 1 £
    • Transaction is one way and is completed immediately

I represent each transaction in a separate table linked to the users account

To send a transfer or a request I get the current logged in user from the getFacesContext()... Then from there I create a new transaction and persist it using the user who is the owner of the relationship.

Each user can view their transactions. Each transaction is separated based on whether it has been successful, revoked and awaiting.

If the user is the recipient they will have the option to revoke or accept a transaction in the awaiting section.

Sending transfers and request works as well as I could expect. However, When I try to confirm or revoke a request as the recipient user the transfer does not complete because the database update (...merge()) does not work.

I thought It would be as easy as getting the current user (who is already logged in ) and the sender of the transaction (from the transaction object) and just updating the values for each.

I get the transaction to update from a table in the users transactions page using the DataModel class.

Below is a snippet of my logic for updating the two users

ViewTransactionBean.class

User curr;

private void init() { // loads current user (the one viewing their transactions);
curr = securityService.getCurrentUser();  // using FacesContext context = .... getUserPrincipal();

 // thinking of replacing this because I am not user if it is persisted or updated when values change later on.
 // could just use it to get the current user id as that does not change. 

}

public String confrim() {
       ....  //ignored for brevity
          
      long rID = transaction.getRecepientID(); // get recipient id from transaction

      User rUser = userService.getEntityManager().find(rID);  // load recipient data into managed persistence -  
 - context
     
      (....) //ignored for brevity - validations to check if you can send money that is available only.

      rUser.transfer(rUser.getBalance() + transaction.getAmount() );
      curr.transfer(curr.getBalance() - transaction.getAmount());
      
      // here is the issue.  Only the first statement (user entity) updates 
      userService.set(curr); // updates 
      userService.set(rUser); // does not sync with database
      
      .....
      transaction.complete();

      tService.set(transaction); //does not sync


      // set() abstracts the javax.persistance .. merge(Object o) method
}

public String revoke() {...} // only updates transaction entity status from AWAITING to REVOKED

I have tried checking whether some of them are detached but all of them are detached including User curr.

When I rearrange the statements only the first gets executed i.e. .set(rUser) before .set(curr) only rUser is synced

I have tried getting the EntityTransaction to do a step by stem commit and rollback but this is not possible using just JTA Cannot use an EntityTransaction while using JTA. no luck...

I have tried flushing each one individually e.g. .set(rUser); followed by getEntityManager().flush(); no luck...

I have tried updating the managed entities that are returned by .merge() but no luck...


Persistence configuration file

<persistence version="2.2" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
  <!-- Define Persistence Unit -->
  <persistence-unit name="BankProjectDBPU" transaction-type="JTA">
    <jta-data-source>jdbc/BankProjectDB</jta-data-source>
    <properties>
      <property name="javax.persistence.schema-generation.database.action" value="create"/>
    </properties>
  </persistence-unit>
</persistence>

Please if anyone can assist me with this I would be very grateful. Thank you

If there are any questions just let me know I would be happy to clarify.

  • If you are using JTA (the error states you are) how have yo configured and hooked this up to JPA? Your transactional context controls the begin/commit for you. You'll have to show your persistence configuration, and transactional demarcation - your container has to have a way to specify that your 'confrim' method requires a transaction and that you want all tService.getEntityManager().set calls to be within it – Chris May 04 '22 at 16:59
  • Hey @Chris I am not sure what you mean by transactional demarcation. I have configured my persistence context. I assumed that the error is from me trying to manually control the transactions when the managed container already does that. I assume if I were to need to manually use JTA I would need to use EntityManagerFactory and use `@PersistanceUnit` instead of `@PersistanceContext` in my `@EJB` service. But the issue is whether or not this would fix the problem of being able to merge more than one transaction consecutively because when I try only the last one gets committed. Thanks – Brevyn Kurt May 05 '22 at 13:50
  • @Chris Can you also explain to me what you mean by letting the managed container know that 'confirm' requires a transaction? Is there a decorator for that or? I will edit my post to add the persistence.xml configuration. Thanks – Brevyn Kurt May 05 '22 at 13:53
  • Mine was a question to you - how have you told your container about where (JTA) transactions belong, when to start and commit etc? If you haven't, there aren't going to be any in a JTA environment, and I am surprised you see anything on your getEntityManager().set() calls at all. – Chris May 05 '22 at 16:37
  • @Chris Sorry for the late reply. I have not explicitly set where exactly my JTA transactions belong. How exactly can I do this? I assumed the managed EntityManager handled transactions. `getEntityManager()` is a function that gets the `javax.persistance.EntityManager` for merge call. I made a mistake it should be merge not set ` BankCustomerService.class - EJB @PersistanceContext(name="BankDBPU") EntityManager em; public BankCustomer set(BankCustomer e){ return em.merge(e); } EntityManager getEntityManager() { return em; } ` – Brevyn Kurt May 08 '22 at 19:46
  • 1
    Your assumption is incorrect, EntityManagers do not handle transactions, but can take part in them. Each merge call is a non-operation until flush or the wrapping transaction commits - and you should get an error if you call flush and it isn't in a transactional context. You have specified JTA transactions, and so need to look into how they are used and configured within your container; see https://en.wikipedia.org/wiki/Jakarta_Transactions – Chris May 09 '22 at 15:31

0 Answers0