Using advanced queueing v42.7.3.1
New Feature
Advanced queueing is available in JDBC 42.3.2.1 and later.
EDB Postgres Advanced Server advanced queueing provides message queueing and message processing for the EDB Postgres Advanced Server database. User-defined messages are stored in a queue, and a collection of queues is stored in a queue table. You must first create a queue table before creating a queue that depends on it.
On the server side, procedures in the DBMS_AQADM
package create and manage message queues and queue tables. Use the DBMS_AQ
package to add or remove messages from a queue or register or unregister a PL/SQL callback procedure. For more information about DBMS_AQ
and DBMS_AQADM
, see the DBMS_AQ.
On the client side, the application uses EDB-JDBC driver's JMS API to enqueue and dequeue message.
Enqueueing or dequeueing a message
For more information about using EDB Postgres Advanced Server's advanced queueing functionality, see Built-in packages.
Server-side setup
To use advanced queueing functionality on your JMS-based Java application perform following steps in EDB-PSQL or EDB-JDBC:
- Create a user-defined message type, which may be one of the standard JMS message types. However, EDB JDBC also supports any user-defined types. These types will be covered in detail in the upcoming sections.
- Create a queue table specifying the payload type. This type will typically be the one created in step 1.
- Create a queue using the queue table created in the previous step.
- Start the queue on the database server.
- You have the option to use either EDB-PSQL or EDB-JDBC JMS API in your Java application.
Using EDB-PSQL
Invoke EDB-PSQL and connect to the EDB Postgres Advanced Server host database. Use the following SPL commands at the command line.
Creating a user-defined type
To specify a RAW data type, create a user-defined type. This example creates a user-defined type named as mytype
.
Create the queue table
A queue table can hold multiple queues with the same payload type. This example creates a table named MSG_QUEUE_TABLE
.
Create the queue
This example creates a queue named MSG_QUEUE
in the table MSG_QUEUE_TABLE
.
Start the queue
Once the queue is created, invoke the following SPL code at the command line to start a queue in the EDB database.
Using EDB-JDBC JMS API
Tip
The following sequence of steps is required only if you want to create message types, queue table and queue programmatically. If the message types, queue table, and queue are created using EDB-PSQL then you can use the standard JMS API.
The following JMS API calls perform the same steps performed using EDB-PSQL to:
- Connect to the EDB Postgres Advanced Server database
- Create the user-defined type
- Create the queue table and queue
- Start the queue
Setting up JMS application
After creating the queue table and queue for the message types and starting the queue, you can follow these steps to set up your JMS Application:
- Create a Connection Factory.
- Create a Connection using the connection factory.
- Create a Session using the connection.
- Get the Queue from the session.
- Create a message producer using the session and queue.
- Send messages.
- Create a message consumer using the session and queue.
- Receive messages.
Connection factory
The Connection Factory is used to create connections. EDBJmsConnectionFactory is an implementation of ConnectionFactory and QueueConnectionFactory, used to create Connection and QueueConnection. A connection factory can be created using one of the constructors of the EDBJmsConnectionFactory class. All three constructors can be used to create either a ConnectionFactory or QueueConnectionFactory.
This example shows how to create a ConnectionFactory using an existing java.sql.Connection
:
This example shows how to create a QueueConnectionFactory using a connection string, username, and password:
Connection
A Connection is a client's active connection that can be created from the ConnectionFactory and used to create sessions. EDBJmsConnection is an implementation of Connection, while EDBJmsQueueConnection is an implementation of QueueConnection and extends EDBJmsConnection. A Connection can be created using ConnectionFactory, while QueueConnection can be created from QueueConnectionFactory.
This example shows how to create a Connection and a QueueConnection:
A connection must be started in order for the consumer to receive messages. On the other hand, a producer can send messages without starting the connection. To start a connection, use the following code:
A connection can be stopped at any time to cease receiving messages, and can be restarted when needed. However, a closed connection cannot be restarted.
To stop and close the connection, use the following code:
Session
The Session in EDBJms is used for creating producers and consumers, and for sending and receiving messages. EDBJmsSession implements the basic Session functionality, while EDBJmsQueueSession extends EDBJmsSession and implements QueueSession. A session can be created from a Connection.
This example shows how to create a Session and a QueueSession:
A Session or QueueSession is also used to create queues. It's important to note that in this context, "creating a queue" does not refer to physically creating the queue. As discussed earlier, the queue needs to be created and started as part of the server-side setup. In this context, creating a queue means getting the queue, related queue table, and payload type that have already been created.
This example shows how to create a queue:
Message producer
A message producer is responsible for creating and sending messages. It is created using a session and queue. EDBJmsMessageProducer is an implementation of MessageProducer, but in most cases, you will be using the standard MessageProducer.
This example shows how to create a message producer, create a message, and send it. Creating messages of different types will be discussed in the following sections.
Message consumer
A Message consumer is used to receive messages. It is created using a session and a queue. EDBJmsMessageConsumer is an implementation of MessageConsumer, but you will most often use the standard MessageConsumer.
This example shows how to create a message consumer and receive a message:
Message acknowledgement
Acknowledgement of messages is controlled by the two arguments to the createSession() and createQueueSession() methods:
If the first argument is true, it indicates that the session mode is transacted, and the second argument is ignored. However, if the first argument is false, then the second argument comes into play, and the client can specify different acknowledgment modes. These acknowledgment modes include,
- Session.AUTO_ACKNOWLEDGE
- Session.CLIENT_ACKNOWLEDGE
- Session.DUPS_OK_ACKNOWLEDGE
The following sections describe different modes of acknowledgement:
Transacted session
In transacted sessions, messages are both sent and received during a transaction. These messages are acknowledged by making an explicit call to commit(). If rollback() is called, all received messages will be marked as not acknowledged.
A transacted session always has an active transaction. When a client calls the commit() or rollback() method, the current transaction is either committed or rolled back, and a new transaction is started.
This example explains how the transacted session works:
AUTO_ACKNOWLEDGE mode
If the first argument to createSession() or createQueueSession() is false and the second argument is Session.AUTO_ACKNOWLEDGE, the messages are automatically acknowledged.
DUPS_OK_ACKNOWLEDGE mode
This mode instructs the session to lazily acknowledge the message, and it is okay if some messages are redelivered. However, in EDB JMS, this option is implemented the same way as Session.AUTO_ACKNOWLEDGE, where messages will be acknowledged automatically.
CLIENT_ACKNOWLEDGE mode
If the first argument to createSession() or createQueueSession() is false and the second argument is Session.CLIENT_ACKNOWLEDGE, the messages are acknowledged when the client acknowledges the message by calling the acknowledge() method on a message. Acknowledging happens at the session level, and acknowledging one message will cause all the received messages to be acknowledged.
For example, if we send 5 messages and then receive the 5 messages, acknowledging the 5th message will cause all 5 messages to be acknowledged.
Message types
EDB-JDBC JMS API supports the following message types and can be used in a standard way:
Message type | JMS type |
---|---|
aq$_jms_message | javax.jms.Message |
aq$_jms_text_message | javax.jms.TextMessage |
aq$_jms_bytes_message | javax.jms.BytesMessage |
aq$_jms_object_message | javax.jms.ObjectMessage |
Please note that the corresponding payload types (user-defined types) are not pre-defined and must be created by the user before configuring the queue table. This is discussed in the upcoming sections.
You can specify schema-qualified user-defined types, but the property types and message types must be in the same schema.
Message properties
All of the above-mentioned message types support setting and getting message properties. Before creating the actual message type, you must create the corresponding user-defined type for message properties.
This example shows how to create the user-defined type for message properties:
All primitive types of message properties are supported.
TextMessage
Text messages can be sent using the TextMessage interface. EDBTextMessageImpl is an implementation of TextMessage, but for most cases, you will be using the standard TextMessage.
Before using the text message, it is necessary to create a user-defined type for it. This example shows how to create the user-defined type for TextMessage:
Once the user-defined type is created, you can then proceed to create the queue table using this type:
After setting up the queue table, you can send and receive TextMessages using the standard procedure outlined in the Java code snippet:
BytesMessage
The BytesMessage is used to send a stream of bytes. EDBBytesMessageImpl is an implementation of BytesMessage, but in most cases, you will use the standard BytesMessage. Before using the bytes message, a user-defined type must be created.
This example shows how to create the user-defined type for BytesMessage:
Now, BytesMessage can be sent and received in the standard way.
This example shows how to create and use a BytesMessage in Java:
ObjectMessage
An ObjectMessage is used to send a serializable object as a message. EDBObjectMessageImpl is an implementation of ObjectMessage, but the standard ObjectMessage is most commonly used.
Before using the ObjectMessage, it is necessary to create the user-defined type for the object message.
This example shows how to create the user-defined type for ObjectMessage:
For example we have the following serializable Java class:
This example shows how to use ObjectMessage to send a message containing an object of this class:
Message
A Message can be used to send a message with only properties and no body. EDBMessageImpl is an implementation of a Message, but you will most often use the standard Message. Before using a message, it is required to create a user-defined type.
This example shows how to create the user-defined type for Message:
This example shows how to send a message that contains only properties and no body:
Non-standard message
EDB-JDBC JMS allows users to send and receive non-standard messages that are fully controlled by the API user. These messages do not support the setting and getting of properties. The process involves creating a user-defined type and setting it as the payload for the queue table.
This example shows how to create a Java Bean corresponding to the type you created:
Note
- To create a user-defined class, it must extend the com.edb.aq.operations.UDTType class and override the getParamValues() method. In this method, you should add the attribute values to an ArrayList in the same order as they appear in the CREATE TYPE SQL statement in the database.
- Additionally, make sure to use the annotation @CompareValue(0) with setter methods, as this specifies the order of methods when using the reflection API to reconstruct the object after dequeuing the message from the queue.
Failure to meet these requirements may result in errors.
This example shows how to send an object of this class as a message:
This example shows how to receive this object as a message:
InnermostCustom.java:
InnerCustom.java
CustomType.java
This example shows how to read such nested types: