Persisting an object using JPA

Up to this point, we configured and used the persistence layer to connect and retrieve information from the database but have not tried to store data into it. This is a pretty straightforward procedure that involves the Entity Manager component—the same one we used in Chapter 3, Java EE Basics – Persistence, Query, and Presentation,—to read data from MySQL, and also a transaction, which is something we haven't seen yet.

The concept is pretty widespread nowadays, so there's no need to have painstaking explanations here but just a quick refresher. We use transactions to coordinate efforts on disparate resources—which obviously must support it—so we have a consistent unit of work. The ACID concept (atomicity, consistency, isolation, and durability) states the primary attributes that must be observed when a transaction is used:

  • All or none of the participating resources are committed
  • If an error happens, no resource is updated
  • The changes being made inside a transaction aren't visible to resources outside of it
  • If a transaction finishes as expected and is committed, the participating resources must ensure that the data will be persisted so that even when a failure occurs, its state is correctly kept

When using an application server such as WebLogic, we can access its transaction manager via the Java Transaction API (JTA); by doing this, we have access to the resources mapped by the container that supports transactions, for example a JMS queue, a data source, a local EJB, or even a remote EJB (hosted at another WebLogic Server).

Understanding the available transaction contexts

If the code that must deal with a transaction happens to be inside an EJB, you can use container-managed transactions (CMT), meaning that you don't have to acquire and control the transaction manually—the container takes care of all boilerplate procedures involved in this process.

Tip

For a complete list of transaction context availability in constructors and EJB interface methods such as afterBegin() or ejbCreate(), refer to the Web resources section at the end of this chapter for the Programming JTA for Oracle WebLogic Server entry.

On the other hand, you can take control of everything by disabling the container's transaction control and deal with the transaction manager, and an actual transaction, through code; this mode is called bean-managed transaction (BMT).

You can declare which mode will be used by decorating the bean with the TransactionManagement annotation and setting its value to TransactionManagementType.CONTAINER or TransactionManagementType.BEAN.

CMT is the default setting when no explicit annotations are found by the application server.

Using container-managed transactions

So, if container-managed transactions (CMT) is the way to go, you don't need to use @TransactionManagement because it already is the default strategy.

For each method, you can use another annotation, TransactionAttribute, to tell the container how a transaction should be set up when a request to the method is made, if this is the case. You must set its value with an entry from the enum TransactionAttributeType that fits your requirement. Here's a list of possible values and a description of how each one works:

Value

Description

REQUIRED

If the caller already has a transaction context, the method participates in it. If not, a new transaction is created and finished upon completion of the method. This is the default value.

MANDATORY

If a transaction context is passed along by the caller, the method is executed using it. If not, an exception is raised.

NOT_SUPPORTED

The caller should not pass a transaction context. If a transaction happens to be present, the container suspends it and creates a new one. At the end of the execution, the local transaction is finished and the original one is resumed.

SUPPORTS

It has the same behavior as REQUIRED if a transaction context has been received, and same as NOT_SUPPORTED when no caller transaction is found.

NEVER

The method states that it will not accept or create a transaction. If the caller passes one, an exception is thrown.

REQUIRES_NEW

A new transaction context is always created. What is done inside this transaction is committed before passing the control back to the caller. If a context is present, the manager suspends it before passing the control to the method and resumes it after the method finishes.

To demonstrate the CMT feature, we're going to create and save a Ticket instance in the generate method of ReservationCodeBean, the one that generates the control number we will send as part of the SOAP web service call we're about to create:

  1. Open the singleton session bean ReservationCodeBean from the Store project.
  2. Inject an Entity Manager to get access to the persistence layer:
    @PersistenceContext(unitName = "StoreBO")
    private EntityManager em;
  3. The controlled number returned by the generate method is sensitive information, so we're going to annotate it to create a new transaction each time it's called. This way, it doesn't participate in previously opened transactions, avoiding data tampering. Also, we're going to assign two parameters to the method's signature that is necessary to create the Ticket instance:
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public String generate(int theaterRef, int exhibitionRef)
  4. After the generation of the control number, we create and load an instance of the class Ticket with the necessary data:
    // Create an instance
    Ticket ticket = new Ticket();
    
    // Create Mandatory reference (Ticket --> Theater)
    Theater theater = new Theater();
    theater.setId(theaterRef);
    
    // Set
    ticket.setTheater(theater);
    ticket.setExhibitionRef(exhibitionRef);
    ticket.setControl(control);
  5. We are all set; now we just need to instruct the entity manager to save the object:
    // Save
    em.persist(ticket);
  6. The method still returns the generated control number, so there is no need to change the return instruction.
  7. As soon as the method exits, the transaction is committed, and a new record in the table Ticket (inside the store_db database) is created.

    Tip

    The @TransactionAttribute decoration is the single line of code that mentions a transaction, and even this one isn't mandatory for our use case.

Using bean-managed transactions

As said earlier, this mode leaves all of the responsibility of acquiring and releasing a transaction to the bean's code. There are some helpers that can be used to ease these procedures, but it is the developer's burden to code it all.

To reach the same outcome of the previous section, the code should look as follows:

  1. The class must be decorated with TransactionManagement and the value BEAN:
    @Singleton
    @TransactionManagement(TransactionManagementType.BEAN)
    public class ReservationCodeBean {
       ...
  2. As we are coding an EJB, we still can use CDI to get a persistence context:
    @PersistenceContext
    private EntityManager em;
  3. We also need to inject a UserTransaction component so we can demarcate our transaction:
    @Resource
    private UserTransaction ut;
  4. The load procedure for Theater and Ticket instances remains unchanged. When the data is ready to be saved, we must start a transaction, save the objects, and then commit the transaction. The catch block checks whether there is an active transaction that must be rolled back:
    // Save
    try {
      ut.begin();
      em.persist(ticket);
      ut.commit();
    } catch (Exception e) {
      try {
        if (Status.STATUS_ACTIVE == ut.getStatus()) {
            ut.rollback();
        }
        } catch (Exception rbe) {
          rbe.printStackTrace();
      }
    }

Not that much work, but you do have to put some extra effort when compared to CMT. The decision of using bean-managed transactions is usually taken when several business steps must be executed as a whole, but some of them must be committed even though the bigger transaction must be rolled back if an error occurs. Also, keep in mind that not participating in a global transaction can be both a strength and a weakness, depending on the business scenario you must implement.

Tip

If a javax.persistence.TransactionRequiredException error pops up when you try to run your bean-managed transaction business method, go back and check the code. Most likely, you must have forgotten to acquire a transaction context.

Acquiring a transaction context manually

We discussed the usage of transactions inside the context of EJBs, but you can also acquire and use transactions where CDI isn't available. WebLogic exposes a helper class to make this process easier:

import weblogic.transaction.TransactionHelper; 
…
TransactionHelper th = TransactionHelper.getTransactionHelper();
UserTransaction anotherUT = th.getUserTransaction();

The other pieces of code—opening and closing a transaction and saving an object—are exactly the same.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.8.153