我希望设置一个将用作消息队列的数据库表。该表将在其中插入带有唯一ID和时间戳以及状态为“PENDING”的消息。
假设正确处理了对此表的插入,我想知道使用简单的HSQLDB 2.0数据库从该表事务处理消息的最佳方法是什么(尽管此问题应该适用于所有支持事务的数据库)。 / p>
我希望读取状态为“pending”的下一条消息,并确保没有其他队列处理器也可以处理相同的记录,然后提交或回滚。
我提供了一些代码片段,说明我计划如何使用普通的旧JDBC实现此目的。
DDL:
create table message_queue (
qidx integer,
message varchar(120),
status varchar(20),
inserted_date timestamp,
inserted_by varchar(20),
processed_date timestamp,
processed_by varchar(20),
)
insert into message_queue values (1,'Important message here','PENDING','2010-08-10 00:01:00', 'BOB', null,null)
这是我的队列读取SQL:
SET AUTOCOMMIT FALSE
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
START TRANSACTION
DECLARE nextID INTEGER DEFAULT 0
SET nextID = select max(qidx) from message_queue where status = 'PENDING'
update message_queue set status = 'CONSUMED' where QIDX = nextID
select * from message_queue where QIDX = nextID
ROLLBACK
这是我的连接代码片段:
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
try {
String message = getNextMessage(conn); // uses sql in snippet
processMessage(message);
conn.commit(); // should commit
} catch (Exception e) {
conn.rollback(); // should rollback update
}
答案 0 :(得分:3)
在这些情况下使用的一般模式(跨数据库,没有锁,没有等待 - 准确的乐观锁):
答案 1 :(得分:2)
当您必须考虑数据库的多用户特性时,排队绝对是一个非平凡的架构。一般来说,您不希望自己实现这些类型的东西。正如我相信您很快发现的那样,问题在于,当有多个读取器尝试从同一队列中读取时,您只需要一个进程来获取单个消息。也就是说,您必须确保仅处理一次消息。那么你就开始思考“好吧,好吧,我会更新那条记录,以便其他进程无法获得它”,但是你会意识到,在你提交之前,其他进程将无法看到你的变化。如果您锁定记录,那么在完成第一个处理之前,您不能从队列中读取另一个进程,基本上是序列化整个事务。
根据设计,队列事务必须与从队列中读取的进程的事务有些正交。不幸的是,这是每个数据库的实现将显着不同的一个领域。
也许更好的方法是使用另一个库(不一定是数据库)来进行消息传递。由于HSQLDB没有内置的排队支持,因此队列的不同(java)实现可能是这种情况的工具。