When the queue manager coordinates global units of work itself, it becomes possible to integrate database updates within the units of work. That is, a mixed MQI and SQL application can be written, and the MQCMIT and MQBACK verbs can be used to commit or roll back the changes to the queues and databases together.
The queue manager achieves this using the two-phase commit protocol described in X/Open Distributed Transaction Processing: The XA Specification. When a unit of work is to be committed, the queue manager first asks each participating database manager whether it is prepared to commit its updates. Only if all the participants, including the queue manager itself, are prepared to commit, are all the queue and database updates committed. If any participant cannot prepare its updates, the unit of work is backed out instead.
In general, a global unit of work is implemented in an application by the following method (in pseudocode):
The purpose of MQBEGIN is to denote the beginning of a global unit of work. The purpose of MQCMIT is to denote the end of the global unit of work, and to complete it with all participating resource managers, using the two-phase commit protocol.
When the unit of work (also known as a transaction) is completed successfully using MQCMIT, all actions taken within that unit of work are made permanent or irreversible. If, for any reason, the unit of work fails, all actions are instead backed out. It is not acceptable for one action comprising a unit of work to be made permanent while another is forgotten. This is the principle of a unit of work: either all actions within the unit of work are made permanent or none of them are.
In between MQBEGIN and MQCMIT, the queue manager does not make any calls to the database to update its resources. That is, the only way a database's tables are changed is by your code (for example, the SQL INSERT in the pseudocode above).
Full recovery support is provided if the queue manager loses contact with any of the database managers during the commit protocol. If a database manager becomes unavailable while it is in doubt, that is, it has successfully prepared to commit, but has yet to receive a commit or backout decision, the queue manager remembers the outcome of the unit of work until that outcome has been successfully delivered to the database. Similarly, if the queue manager terminates with incomplete commit operations outstanding, these are remembered over queue manager restart. If an application terminates unexpectedly, the integrity of the unit of work is not compromised, but the outcome depends on where in the process the application terminated, as described inTable 12.
What happens when the database or application program crashes is summarized in the tables below:
Before the application call to MQCMIT. | The unit of work is backed out. |
During the application call to MQCMIT, before all databases have indicated that they have successfully prepared. | The unit of work is backed out with a reason code of MQRC_BACKED_OUT. |
During the application call to MQCMIT, after all databases have indicated that they have successfully prepared, but before all have indicated that they have successfully committed. | The unit of work is held in recoverable state by the queue manager, with a reason code of MQRC_OUTCOME_PENDING. |
During the application call to MQCMIT, after all databases have indicated that they have successfully committed. | The unit of work is committed with a reason code of MQRC_NONE. |
After the application call to MQCMIT. | The unit of work is committed with a reason code of MQRC_NONE. |
Before the application call to MQCMIT. | The unit of work is backed out. |
During the application call to MQCMIT, before the queue manager has received the application's MQCMIT request. | The unit of work is backed out. |
During the application call to MQCMIT, after the queue manager has received the application's MQCMIT request. | The queue manager tries to commit using two-phase commit (subject to the database products successfully executing and committing their parts of the unit of work). |
In the case where the reason code on return from MQCMIT is MQRC_OUTCOME_PENDING, the unit of work is remembered by the queue manager until it has been able to reestablish contact with the database server, and tell it to commit its part of the unit of work. Refer to Administration tasks for information on how and when recovery is done.
The queue manager communicates with database managers using the XA interface as described in X/Open Distributed Transaction Processing: The XA Specification. Examples of these function calls are xa_open, xa_start, xa_end, xa_prepare, and xa_commit. We use the terms transaction manager and resource manager in the same sense as they are used in the XA specification.
The following restrictions apply to the database coordination support:
The switch load file is a shared library (a DLL on Windows systems) that is loaded by the code in your WebSphere MQ application and the queue manager. Its purpose is to simplify the loading of the database's client shared library, and to return the pointers to the XA functions.
The details of the switch load file must be specified before the queue manager is started. The details are placed in the qm.ini file (UNIX systems), or the Registry (Windows systems).
The C source for the switch load file is supplied with the WebSphere MQ installation if it supports Scenario 1 global units of work. The source contains a function called MQStart. When the switch load file is loaded, the queue manager calls this function, which returns the address of a structure called an XA switch.
The XA switch structure exists in the database client shared library, and contains a number of function pointers, as described in Table 13:
Function pointer name | XA function | Purpose |
---|---|---|
xa_open_entry | xa_open | Connect to database |
xa_close_entry | xa_close | Disconnect from database |
xa_start_entry | xa_start | Start a branch of a global unit of work |
xa_end_entry | xa_end | Suspend a branch of a global unit of work |
xa_rollback_entry | xa_rollback | Roll back a branch of a global unit of work |
xa_prepare_entry | xa_prepare | Prepare to commit a branch of a global unit of work |
xa_commit_entry | xa_commit | Commit a branch of a global unit of work |
xa_recover_entry | xa_recover | Discover from the database whether it has an in-doubt unit of work |
xa_forget_entry | xa_forget | Allow a database to forget a branch of a global unit of work |
xa_complete_entry | xa_complete | Complete a branch of a global unit of work |
During the first MQBEGIN call in your application, the WebSphere MQ code that executes as part of MQBEGIN loads the switch load file, and calls the xa_open function in the database shared library. Similarly, during queue manager startup, and on other subsequent occasions, some queue manager processes load the switch load file and call xa_open.
You can reduce the number of xa_* calls by using dynamic registration. For a complete description of this optimization technique, see XA dynamic registration.
There are several tasks that you must perform before a database manager can participate in global units of works coordinated by the queue manager. These are described here as follows:
The steps involved in installing and configuring your database product are, of course, described in that product's own documentation. Installation issues are well beyond the scope of this chapter, but we can list general configuration issues, as they relate to the interoperation between WebSphere MQ and the database.
An application that establishes a standard connection to the queue manager is associated with a thread in a separate local queue manager agent process. (A connection that is not a fastpath connection is a standard connection in this context. For more information, see "Connecting to a queue manager using the MQCONNX call" in the WebSphere MQ Application Programming Guide.)
When the application issues MQBEGIN, both it and the agent process call the xa_open function in the database client library. In response to this, the database client library code connects to the database that is to be involved in the unit of work from both the application and queue manager processes. These database connections are maintained as long as the application remains connected to the queue manager.
This is an important consideration if the database supports only a limited number of users or connections, because two connections are being made to the database to support the one application program.
The database client library that is loaded into the WebSphere MQ queue manager and application processes must be able to send to and receive from its server. Ensure that:
WebSphere MQ comes with a sample makefile, used to build switch load files for the supported database managers. This makefile, together with all the associated C source files required to build the switch load files, is installed in the following directories:
The sample source modules used to build the switch load files are:
When you generate switch load files it is recommended that 32-bit switch load files are installed in /var/mqm/exits and 64-bit switch load files are installed in /var/mqm/exits64.
If you have 32-bit queue managers then the sample make file, xaswit.mak, will install a 32-bit switch load file in /var/mqm/exits.
If you have 64-bit queue managers then the sample make file, xaswit.mak, will install a 32-bit switch load file in /var/mqm/exits, and a 64-bit switch load file in /var/mqm/exits64.
When you have created a switch load file for your database manager, and placed it in a safe location, you must specify that location to your queue manager.
Add an XAResourceManager stanza for the database that your queue manager is going to coordinate. The most common case is for there to be only one database, and therefore only one XAResourceManager stanza. More complicated configurations involving multiple databases, are discussed in Multiple database configurations. The attributes of the XAResourceManager stanza are as follows:
The name you choose must be unique; there must be only one XAResourceManager stanza with this name in this qm.ini file. The name should also be meaningful, because the queue manager uses it to refer to this resource manager both in queue manager error log messages and in output when the dspmqtrn command is used. (See Displaying outstanding units of work with the dspmqtrn command for more information.)
Once you have chosen a name, and have started the queue manager, do not change the Name attribute. This is discussed in more detail in Changing configuration information.
The code in the queue manager and WebSphere MQ application processes call the xa_open function on two occasions:
The code in the queue manager and WebSphere MQ application processes call the xa_close function on two occasions:
If the database client code allows threads to call the XA functions without serialization, the value for ThreadOfControl can be THREAD. The queue manager assumes that it can call the XA functions in the database client shared library from multiple threads at the same time, if necessary.
If the database client code does not allow threads to call its XA functions in this way, the value for ThreadOfControl must be PROCESS. In this case, the queue manager serializes all calls to the database client shared library so that only one call at a time is made from within a particular process. You probably also need to ensure that your application performs similar serialization if it runs with multiple threads.
Note that this issue, of the database product's ability to cope with multi-threaded processes in this way, is an issue for that product's vendor. Consult the database product's documentation for details on whether you can set the ThreadOfControl attribute to THREAD or PROCESS. We recommend that, if you can, you set ThreadOfControl to THREAD. If in doubt, the safer option is to set it to PROCESS, although you will lose the potential performance benefits of using THREAD.
The sample application programs for Scenario 1 global units of work that are supplied with a WebSphere MQ installation are described in the WebSphere MQ Application Programming Guide.
In general, a global unit of work is implemented in an application by the following method (in pseudocode):
The purpose of MQBEGIN is to denote the beginning of a global unit of work. The purpose of MQCMIT is to denote the end of the global unit of work, and to complete it with all participating resource managers, using the two-phase commit protocol.
In between MQBEGIN and MQCMIT, the queue manager does not make any calls to the database to update its resources. That is, the only way a database's tables are changed is by your code (for example, the SQL INSERT in the pseudocode above).
The role of the queue manager, as far as the database is concerned, is to tell it when a global unit of work has started, when it has ended, and whether the global unit of work should be committed or rolled-back.
As far as your application is concerned, the queue manager performs two roles: a resource manager (where the resources are messages on queues) and the transaction manager for the global unit of work.
We recommend that you start with the supplied sample programs, and work through the various WebSphere MQ and database API calls that are being made in those programs. The API calls concerned are fully documented in the WebSphere MQ Application Programming Guide, the WebSphere MQ Application Programming Reference, and (in the case of the database's own API) the database's own documentation.
You only know whether your application and system are correctly configured by running them during testing. You can test the system's configuration (the successful communication between queue manager and database) by building and running one of the supplied sample programs.
Notices |
Downloads |
Library |
Support |
Feedback
![]() ![]() |
eguow |