0 Replies Latest reply on Nov 30, 2006 11:06 AM by twwwt

    EntityManager.merge() very slow compared to fetch-update-sto

    twwwt

      Hi all,

      I played with this simple code in a session EJB and realised that the merge operation of EntityManager is very slow (more than one second):

      public void transfer(Account from, Account to, double value) throws AccountOverdrawException, IllegalArgumentException {
      try
      {
       to.deposit(value);
       em.merge(to);
       from.withdraw(value);
       em.merge(from);
      
      }
      catch (AccountOverdrawException e)
      {
       context.setRollbackOnly();
       throw e;
      }
      catch (IllegalArgumentException e)
      {
       context.setRollbackOnly();
       throw e;
      }
      }
      


      After that, I tried this version which is much faster (about 10ms):

      public void transfer(Account from, Account to, double value) throws AccountOverdrawException, IllegalArgumentException {
      try
      {
       Account f = em.find(Account.class, from.getAccountID());
       Account t = em.find(Account.class, to.getAccountID());
       t.deposit(value);
       f.withdraw(value);
      
      }
      catch (AccountOverdrawException e)
      {
       context.setRollbackOnly();
       throw e;
      }
      catch (IllegalArgumentException e)
      {
       context.setRollbackOnly();
       throw e;
      }
      }
      


      My first guess was that it might be slow because of cascaded merge of associated objects inside Account (see code below). But then I read in the EJB specification that by default there is no cascading, i.e., it has to be explicetly set in the annotations. Is there any other thing I'm currently not aware of that causes the difference.

      Thanks,
      Thorsten





      @Entity
      public class Account implements Serializable
      {
       private static final long serialVersionUID = 7443656659402964861L;
      
       private double balance;
       private long accountID;
       private Customer customer;
       private Bank bank;
      
       Account()
       {
       super();
       }
      
       public Account(Customer owner)
       {
       this.customer = owner;
       }
      
       @Id
       @GeneratedValue(strategy = GenerationType.SEQUENCE)
       public long getAccountID()
       {
       return accountID;
       }
      
       void setAccountID(long newID)
       {
       this.accountID = newID;
       }
      
       @Column
       public double getBalance()
       {
       return balance;
       }
      
       void setBalance(double newBalance)
       {
       this.balance = newBalance;
       }
      
       @ManyToOne
       public Bank getBank()
       {
       return bank;
       }
      
       public void setBank(Bank bank)
       {
       this.bank = bank;
       }
      
       @ManyToOne
       public Customer getCustomer()
       {
       return customer;
       }
      
       void setCustomer(Customer newCustomer)
       {
       this.customer = newCustomer;
       }
      
       /**
       * @param amount Deposit the given amount to the account.
       * @throws IllegalArgumentException if the given amount is less than zero.
       */
       public void deposit(double amount)
       {
       if (amount < 0) throw new IllegalArgumentException("Deposit of negative amount is not allowed");
       setBalance(getBalance() + amount);
       }
      
       /**
       * @param amount Withdraw the given amount from the account.
       * @throws IllegalArgumentException if the given amount is less than zero.
       * @throws AccountOverdrawException in case given amout is greather than acount balance.
       */
       public void withdraw(double amount) throws AccountOverdrawException
       {
       if (amount < 0) throw new IllegalArgumentException("Withdraw of negative amount is not allowed");
       if (amount > balance) throw new AccountOverdrawException("The operation would lead to overdrawing the account and was rejected.");
       setBalance(getBalance() - amount);
       }
      }
      


      Note that Customer in turn has a list of Account(s) and Bank has a list of Customer(s) and Account(s), whereby the fetch type of those properties is set to lazy.