CMP Transactions

Find this tutorial in: /usr/local/resin/webapps/resin-doc/amber/tutorial/cmp-xa
Try the Tutorial

Demonstrates protecting database updates using some basic transaction patterns.

Topics:

  • Stateless session beans for transaction management
  • UserTransaction for direct control of transactions
  • REQUIRED for updating methods
  • SUPPORTS for read-only methods

See also:

  1. Files in this tutorial
  2. Course Entity Definition
    1. Database Schema
    2. Bean Implementation
  3. Session Bean Implementation
    1. TransactionAttribute REQUIRED
  4. Swap Servlet
    1. Dependency Injection
    2. SessionBean swap
    3. UserTransaction swap

Files in this tutorial

WEB-INF/web.xml web.xml configuration
WEB-INF/classes/example/Course.java The course bean
WEB-INF/classes/example/SwapBean.java The swap stateless session bean
WEB-INF/classes/example/Swap.java The swap stateless session interface
WEB-INF/classes/example/SwapServlet.java The swap servlet

Course Entity Definition

Database Schema

course.sql
CREATE TABLE ejb3_xa_courses (
  id INTEGER PRIMARY KEY auto_increment,

  course VARCHAR(250),
  teacher VARCHAR(250)
);

INSERT INTO basic_courses VALUES('Potions', 'Severus Snape');
INSERT INTO basic_courses VALUES('Transfiguration', 'Minerva McGonagall');

Bean Implementation

The Course is identical to the basic field bean. It uses FIELD enhancement to define the database columns.

Course.java
@Entity(access=FIELD)
@Table(name="ejb3_xa_courses")
public class Course {

  @Id(generate=AUTO)
  @Column(name="id")
  private int _id;

  @Basic
  @Column(name="course")
  private String _course;

  @Basic
  @Column(name="teacher")
  private String _teacher;
}

Session Bean Implementation

SwapBean.java
import static javax.ejb.TransactionAttributeType.REQUIRED;

@javax.ejb.Stateless(name="swap")
public class SwapBean implements Swap {

  @javax.ejb.TransactionAttribute(REQUIRED)
  public void swap(Course a, Course b)
  {
    String teacher = a.getTeacher();
    a.setTeacher(b.getTeacher());
    b.setTeacher(teacher);
  }
}

TransactionAttribute REQUIRED

The TransactionAttribute marks the transaction type of the method. The two most common types are REQUIRED and SUPPORTS. A REQUIRED method expects to modify the data and wants to ensure the update is consistent. A SUPPORTS method will only read data, so it can avoid the overhead of a transaction.

A transaction is the database equivalent of a synchronized lock. Transactions are somewhat more complicated locks because they need to work with multiple machines and possibly multiple databases, but they're still just sophisticated locks. The typical transaction patterns are similar to familiar lock patterns.

A REQUIRED attribute tells Resin that the method must be protected by a transaction. In this case, the swap needs protection from simultaneous threads trying to swap at the same time.

A SUPPORTS attribute would tell Resin that the method doesn't need a transaction, but the method should join any transaction that already exists.

Swap Servlet

SwapServlet.java
import javax.ejb.EntityManager;
import javax.transaction.UserTransaction;

public class CourseServlet extends HttpServlet {
  @javax.ejb.Inject
  private EntityManager _manager;

  @javax.ejb.Inject
  private UserTransaction _uTrans;

  @javax.ejb.EJB(name="swap")
  private Swap _swap;

  ...

  private void doService(PrintWriter out)
    throws Exception
  {
    CourseBean []course = new CourseBean[2];

    course[0] = (CourseBean) _manager.find("CourseBean", new Integer(1));
    course[1] = (CourseBean) _manager.find("CourseBean", new Integer(2));

    // swap the courses using the session bean
    _swap.swap(course[0], course[1]);

    // swap using a user transaction
    _uTrans.begin();
    try {
      String teacher = course[0].getTeacher();
      course[0].setTeacher(course[1].getTeacher());
      course[1].setTeacher(teacher);
    } finally {
      _uTrans.commit();
    }
  }
}

Dependency Injection

The servlet needs to lookup the EntityManager, UserTransaction, and the Swap bean in JNDI.

ObjectJNDI
EntityManagerjava:comp/EntityManager
UserTransactionjava:comp/UserTransaction
Swapjava:comp/env/ejb/swap

Since Resin's servlets understand the EJB 3.0 injection annotations, the tutorial can just annotate the setters and let Resin configure them. In other cases, it may be necessary to put the JNDI lookup in the servlet's init() method.

SessionBean swap

The first swap in the tutorial switches the teachers using a stateless session bean.

// swap the courses using the session bean
_swap.swap(course[0], course[1]);

Because the swap method was marked as transaction REQUIRED, Resin will start a transaction if none already exists. If the method exits cleanly, Resin will commit the transaction. If the method throws a RuntimeException, Resin will roll the transaction back.

The swap method will throw a runtime exception if the transaction fails to commit. For example, the databse might detect a deadlock and roll the transaction back.

UserTransaction swap

The second swap in the tutorial restores the teachers using the underlying UserTransaction. It's essentially identical to the work that the transaction REQUIRED swap method provides. In fact, Resin implements the REQUIRED annotation using UserTransaction.

_uTrans.begin();
try {
  String teacher = course[0].getTeacher();
  course[0].setTeacher(course[1].getTeacher());
  course[1].setTeacher(teacher);
} finally {
  _uTrans.commit();
}

The main differences between the two are the added capabilities of the REQUIRED.

  • REQUIRED automatically rolls back on a RuntimeException
  • REQUIRED joins any existing transaction. In contrast, UserTransaction throws an exception if called in a transaction.

Try the Tutorial


Copyright © 1998-2006 Caucho Technology, Inc. All rights reserved.
Resin® is a registered trademark, and HardCoretm and Quercustm are trademarks of Caucho Technology, Inc.