Transactions

As we said earlier, data is an important part of enterprise applications. Creating and managing data is critical. It is also necessary to maintain the integrity of the data while performing operations.

Transactions are sets of operations that can be carried out on the entities. Transaction management essentially involves managing the life cycle of the entities to maintain the integrity of the data. When a transaction executes a set of operations, it will either succeed or be rolled back if there are any failures. There is no way in which half the operations will execute, leaving the data in an inconsistent state.

Let's take a look at how to handle transactions in Java EE applications. We will discuss how we can use the Java Transaction API with both EJBs and CDI-managed beans using the @Transactional and @TransactionAttribute annotations. We will also look at how the transaction lifecycle is managed and how to handle exceptions.

Consider the following EJB, which is used to create the identity of a person:

@Stateless
class App {
@Inject
private lateinit var identityCreator: IdentityCreator

@PersistenceContext(unitName="local")
private lateinit var entityManager: EntityManager

fun createIdentity(inputData: InputData): Person {
val person = identityCreator.createPerson(inputData)
entityManager.persist(person)
return person
}

fun findAllPerson(): List<Identity> {
return
entityManager.createNamedQuery(Queries.FIND_ALL_PERSON,
Person::class.java).resultList
}
}

By default, the EJB business function starts new transactions. This means that both the createIdentity() and findAllPerson() functions will be executed within a transaction. Once the function completes the execution and returns it, the transaction will be committed to the database.

We could also specify a different transaction handling function using the @TransactionAttribute from the EJB by specifying a type that is, by default, a REQUIRED type. This means that a new transaction is required:

@Stateless
class App {
@Inject
private lateinit var identityCreator: IdentityCreator

@PersistenceContext(unitName="local")
private lateinit var entityManager: EntityManager

@TransactionAttribute(TransactionAttributeType.REQUIRED)
fun createIdentity(inputData: InputData): Person {
        val person = identityCreator.createPerson(inputData)
entityManager.persist(person)
return person
}

fun findAllPerson(): List<Identity> {
return
entityManager.createNamedQuery(Queries.FIND_ALL_PERSON,
Person::class.java).resultList
}
}

We could also specify another attribute, TransactionAttributeType.REQUIRES_NEW, which requires a new transaction.

For example, let's say we have two EJBs and the second one requires a new transaction. When the second EJB's function executes, the first transaction will be suspended. Then, the second transaction will be executed. Once it is committed, the first transaction resumes and continues its execution.

We can also specify that a transaction is not supported using TransactionAttributeType.NOT_SUPPORTED.

Here's an example:
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
fun deleteIdentity(inputData: InputData): Person {
  //...
}

By default, CDI-managed beans' functions don't execute in a transaction. However, we can use the @Transactional annotation that comes from the Java Transaction API to specify that a transaction is required, or that a new transaction will be started. A transaction type (TxType) is used to specify the transaction. Consider the following code:

@Dependent
class IdentityCreator {
@Inject
private lateinit var defaultPreferredLanguage: PreferredLanguage

@Transactional(TxType.REQUIRED)
fun createPerson(inputData: InputData): Person {
val person = Person()
person.preferredLanguage = if (inputData.preferredLanguage ==
null)
            defaultPreferredLanguage
else
inputData.preferredLanguage
return person
}
}

We can also specify REQUIRES_NEW; this requires a new subsequent transaction:

    @Transactional(TxType.REQUIRES_NEW)
fun createPerson(inputData: InputData): Person {
val person = Person()
person.preferredLanguage = if (inputData.preferredLanguage ==
null)
defaultPreferredLanguage
else
inputData.preferredLanguage
return person
}

When the function execution is completed and returned, the transaction will be committed.

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

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