oo

Multithreading Process

Liferay DXP 7.4 U10+ or Liferay Portal 7.4 GA14+

Your Upgrade Processes may involve making complex changes to large data sets. If performance is critical, use the processConcurrently() method in the UpgradeProcess class of your application. This method executes in multiple threads and can shorten your upgrade times.

Deploy Version 1.0.0

Start a new Liferay DXP instance by running

docker run -it -m 8g -p 8080:8080 liferay/dxp:2024.q1.1

Sign in to Liferay at http://localhost:8080 using the email address test@liferay.com and the password test. When prompted, change the password to learn.

Then, follow these steps:

  1. Download and unzip Multithreading Process.

    curl https://resources.learn.liferay.com/dxp/latest/en/building-applications/data-frameworks/upgrade-processes/liferay-j7z3.zip -O
    
    unzip liferay-j7z3.zip
    
  2. Move into the 1.0.0 directory, build and deploy.

    cd 1.0.0
    
    ../gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
    
    Note

    This command is the same as copying the deployed jars to /opt/liferay/osgi/modules on the Docker container.

  3. Confirm the deployment in the Liferay Docker container console.

    STARTED com.acme.j7z3.api_1.0.0 [1030]
    STARTED com.acme.j7z3.service_1.0.0 [1031]
    

Add Entries to the App

  1. Navigate to the Script console at Control PanelServer AdministrationScript.

  2. Add some entries by executing the following script.

    import com.acme.j7z3.service.J7Z3EntryLocalServiceUtil;
    
    import com.liferay.portal.kernel.dao.orm.QueryUtil;
    
    entry1 = J7Z3EntryLocalServiceUtil.createJ7Z3Entry(1);
    entry2 = J7Z3EntryLocalServiceUtil.createJ7Z3Entry(2);
    entry3 = J7Z3EntryLocalServiceUtil.createJ7Z3Entry(3);
    
    entry1.setName("able");
    entry2.setName("able");
    entry3.setName("able");
    
    J7Z3EntryLocalServiceUtil.addJ7Z3Entry(entry1);
    J7Z3EntryLocalServiceUtil.addJ7Z3Entry(entry2);
    J7Z3EntryLocalServiceUtil.addJ7Z3Entry(entry3);
    
    

    The J7Z3_J7Z3Entry table now has three entries.

    The three entries can been verified in the database table.

Execute the Upgrade

  1. Move into the 1.0.1 directory, build and deploy.

    cd ../1.0.1
    
    ../gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
    
  2. Navigate to the Gogo shell console at Control PanelGogo Shell.

  3. Verify that the 1.0.1 upgrade is available by entering the command upgrade:list com.acme.j7z3.service. The 1.0.1 version appears as a registered upgrade process in the output window.

  4. Execute the upgrade by entering the command upgrade:execute com.acme.j7z3.service. The output window shows that the upgrade was completed.

    Execute the upgrade and the output should display that the upgrade was completed.

  5. The J7Z3_J7Z3Entry table entries have now been updated.

    The updated entries can been verified in the database table.

Implement the Multithreading Method

In the UpgradeProcess class of your application, override the processConcurrently() method.

@Override
protected void doUpgrade() throws Exception {
	processConcurrently(
		"select j7z3EntryId, name from J7Z3_J7Z3Entry",
		resultSet -> new Object[] {
			resultSet.getLong("j7z3EntryId"), resultSet.getString("name")
		},
		columns -> {
			long j7z3EntryId = (Long)columns[0];

			try (PreparedStatement preparedStatement =
					connection.prepareStatement(
						"update J7Z3_J7Z3Entry set name = ? where " +
							"j7z3EntryId = ?")) {

				preparedStatement.setString(1, "baker");
				preparedStatement.setLong(2, j7z3EntryId);

				preparedStatement.executeUpdate();
			}
		},
		null);
}

The method has four parts:

  1. SQL Query - An SQL statement to query the database data.

  2. Gathering objects - Receive a result set and return an array of objects based on the result set.

  3. Processing objects - Execute business logic on the array of objects.

  4. Exception - Send a message if an exception occurs.

The sample project shows a simple example where the name field is processed and modified by the processConcurrently() method.

  1. select j7z3EntryId, name from J7Z3_J7Z3Entry - The SQL statement queries all the entries.

  2. resultSet -> new Object[] {
    		 resultSet.getLong("j7z3EntryId"), resultSet.getString("name")
    

    The objects are gathered and stored in the resultSet array.

  3. columns -> {
    	    long j7z3EntryId = (Long)columns[0];
    
    	    try (PreparedStatement preparedStatement =
    			  connection.prepareStatement(
    				   "update J7Z3_J7Z3Entry set name = ? where " +
    					    "j7z3EntryId = ?")) {
    
    		     preparedStatement.setString(1, "baker");
    		     preparedStatement.setLong(2, j7z3EntryId);
    
    		     preparedStatement.executeUpdate();
    		 }
    	}
    

    For every j7z3EntryId, the name field is set as baker.

  4. The exception is set to null.

The processConcurrently() method has two different signatures. One signature passes a SQL query as the source, as seen in this tutorial example. The other signature passes an array as the source. See the BaseDBProcess javadocs to learn more.