Wednesday 14 September 2011

REQUIRED VS REQUIRES_NEW transaction attribute type

This article uses code examples to illustrate the difference between REQUIRED and REQUIRES_NEW transaction attribute type.

Create two entity beans.

@Entity
@Table(name="T_COMPANY")
public class Company{
    
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    
    @Column(name = "NAME")
    private String name;
    
    public Company() {
        super();
    }
    
    public Company(String name) {
        super();
        this.name = name;
    }
}


@Entity
@Table(name="T_PERSON")
public class Person{
    
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    
    @Column(name = "NAME")
    private String name;
    
    public Person() {
        super();
    }
    
    public Person(String name) {
        super();
        this.name = name;
    }
}

Create a stateless session bean (companyBean) with a method having REQUIRES_NEW transaction attribute type.

@Stateless(name="companyBean")
@Local(CompanyManager.class)
public class CompanyManagerBean 
    implements CompanyManager {

    @PersistenceContext(unitName="unit")
    private EntityManager em;
    
    @Override
    @TransactionAttribute
    (TransactionAttributeType.REQUIRES_NEW)
    public void save(Company company) {
        em.persist(company);
    }
}

Create another stateless session bean (personBean), and inject the companyBean into the personBean.

@Stateless(name="personBean")
@Local(PersonManager.class)
public class PersonManagerBean 
    implements PersonManager {

    @PersistenceContext(unitName="unit")
    private EntityManager em;
    
    @EJB(beanName="companyBean")
    private CompanyManager companyManager;
    
    @Override
    @TransactionAttribute
    (TransactionAttributeType.REQUIRED)
    public void save(Person person) {
        companyManager.save(new Company("Oracle"));
        em.persist(person);
    }
} 

Write a servlet to test

public class PersonServlet extends HttpServlet {

    @EJB(beanName="personBean")
    private PersonManager personManager = null;
    
    @Override
    protected void doGet(HttpServletRequest req, 
            HttpServletResponse resp)
            throws ServletException, IOException {
        personManager.save(new Person("Mingtao001"));
    }
}

Result:

Table T_COMPANY



Table T_PERSON



Now throw an exception in personBean

@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void save(Person person) {
    companyManager.save(new Company("Oracle"));
    em.persist(person);
    throw new RuntimeException("error!");
}

Clean the table and retest the servlet

Result:

Table T_COMPANY



Table T_PERSON


The SQL that saves the person has been rolled back while the SQL that saves the company was not affected.

Now change the transaction attribute type from REQUIRES_NEW to REQUIRED in companyBean.

@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void save(Company company) {
    em.persist(company);
}

Clean the table and retest the servlet

Result:

Table T_COMPANY



Table T_PERSON



Both SQLs have been rolled back as they are in the same transaction.

No comments:

Post a Comment