Site icon Pro Liferay

Liferay Service Builder and Transaction

transaction-top


Liferay Service Builder is one of the great tool to auto generate code to interact with database. But have you ever thought of transaction in Liferay Service Layer? In simple I am just reminding you about database roll back. In this post I will focus on the Transactional aspect of Liferay Service Layer.  

NoteA transaction is a set of tasks that you want to treat as a unit. The unit should be completed as a whole or not at all.


Real-time Example:
Say you want to transfer money on-line from your account to another account. The whole process can be considered as
i) Check the sufficient balance.
ii) Deduct specific amount from account.
iii) Deposit the same amount to the destination account.

In this case the whole process is a set of 3 tasks. If any one of these task fails then the whole process must be rolled back. For example consider the last task No. (iii) got failed. That means that amount is deducted from your account but its not deposited in the destination account. In this situation we must consider about transaction.


I am assuming that you know the Liferay Service Builder tool. This post does not explain how to use to Liferay Service builder. 

service.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.2.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_2_0.dtd">
<service-builder package-path="com.proliferay.demo.sbuilder">
	<author>Hamidul Islam</author>
	<namespace>transaction</namespace>

	<entity name="Customer" local-service="true" remote-service="true">
		<column name="customerId" type="long" primary="true" />
		<column name="firstName" type="String" />
		<column name="middleName" type="String" />
		<column name="lastName" type="String" />
		<column name="age" type="int" />
	</entity>

	<entity name="Address" local-service="true" remote-service="true">
		<column name="addressId" type="long" primary="true" />
		<column name="customerId" type="long" primary="true" />
		<column name="address" type="String" />
		<column name="contactNo" type="int" />
	</entity>
</service-builder>

 In the above service.xml there are two entities. First entity is Customer and second entity is Address


Note: The services methods are executed in a transaction which means that if your database supports it, then if there is an error in the middle of the execution of a service method (or in any other method invoked by it), all the previous operations will be undone (rolled back) automatically for you. Liferay implements this under the hood using Spring’s transactions mechanisms.


 

Scenario 1

We need add customer and their respective address. Both has to be inserted in different database tables. Consider every Customer should have valid address.  That means that after adding customer there must be a valid address record in address table. Therefore if we fail to add address then we must also should not add any customer without address. 

Solution:

Every liferay service methods are Transactional in nature. That means every local service impl methods are transnational. We can add records in both the tables from a single method by adding custom method in local service impl file. 

	public void addCustomerAddress(Customer customer, Address address) throws SystemException{
			/**
			 * Inserting data to Customer
			 */
			long customerId = counterLocalService.increment(Customer.class.getName());
			customer.setCustomerId(customerId);
			customer = customerLocalService.addCustomer(customer);

			/**
			 * Inserting data to Address
			 */
			long addressId = counterLocalService.increment(Customer.class.getName());
			address.setAddressId(addressId);
			address.setCustomerId(customer.getCustomerId());
			addressLocalService.addAddress(address);

	}

 According to the above code after insertion of customer object if insertion of address object fails then whole process will be rolled back. Liferay handle this  Transaction without writing any custom code. Is not it fantastic? 

Scenario 2

Sometimes we want to roll back in some certain conditions. Say you are adding records in five tables one after another in a single method as shown in the above.

Solution:

If you want to roll back on the basis of certain conditions then we can explicitly throw any one of the below two exceptions

i) com.liferay.portal.kernel.exception.PortalException

 Or

ii) com.liferay.portal.kernel.exception.SystemException

For example:

throw new PortalException();

The above code is sufficient to to roll back the previous insertions. 


Good to know

Internally Liferay services are annotated by @Transactional(isolation = Isolation.PORTAL, rollbackFor =  {PortalException.class, SystemException.class}) 

This will be mentioned in your ${EntityName}LocalService interface. That means that service layer methods are Transactional. Roll back will be happened for the exceptions PortalException as well as SystemException. 


Exit mobile version