1. 客户端怎样显式地使用事务?

producer 开启事务(代码片段):

ActiveMQSession session = (ActiveMQSession)connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("TEST.FOO");
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.PERSISTENT); // 开启事务
// 发送 TransactionInfo 消息 BEGIN
session.getTransactionContext().begin(); for (int i = 0; i < 2; i++) {
// Create a message
String text = "zhang";
TextMessage message = session.createTextMessage(text);
producer.send(message);
}
// session.getTransactionContext().rollback();
//提交事务
// 发送 TransactionInfo 消息 COMMIT_ONE_PHASE
session.getTransactionContext().commit();

2. broker 处理事务的入口:

TransportConnection.processBeginTransaction
TransportConnection.processCommitTransactionOnePhase
TransportConnection.processCommitTransactionTwoPhase

broker 处理事务的逻辑在 TransactionBroker 类中。

那么,具体在 Queue 中是怎样体现事务的呢?

ActiveMQ 客户端默认不会开启事务,而如果客户端显式地开启了事务,则 Queue 中可能会存在多个事务,一个事务中必然会有一个消息列表,当客户端提交事务时,Queue 接收事务对应的消息列表,而如果客户端回滚事务,则 Queue 会删除这些消息。

Queue 中的事务变量:

// 键是Transaction,值是对应的消息列表
final ConcurrentHashMap<Transaction, SendSync> sendSyncs = new ConcurrentHashMap<Transaction, SendSync>();
private final LinkedList<Transaction> orderIndexUpdates = new LinkedList<Transaction>();

Queue 内部类 SendSync 封装了消息和同步操作:

class SendSync extends Synchronization {

    class MessageContext {
public Message message;
public ConnectionContext context; public MessageContext(ConnectionContext context, Message message) {
this.context = context;
this.message = message;
}
} final Transaction transaction;
// 这就是我要找的消息列表
List<MessageContext> additions = new ArrayList<MessageContext>(); public SendSync(Transaction transaction) {
this.transaction = transaction;
} public void add(ConnectionContext context, Message message) {
additions.add(new MessageContext(context, message));
} @Override
public void beforeCommit() throws Exception {
synchronized (orderIndexUpdates) {
orderIndexUpdates.addLast(transaction);
}
} @Override
public void afterCommit() throws Exception {
ArrayList<SendSync> syncs = new ArrayList<SendSync>(200);
sendLock.lockInterruptibly();
try {
synchronized (orderIndexUpdates) {
Transaction next = orderIndexUpdates.peek();
while( next!=null && next.isCommitted() ) {
syncs.add(sendSyncs.remove(orderIndexUpdates.removeFirst()));
next = orderIndexUpdates.peek();
}
}
for (SendSync sync : syncs) {
sync.processSend();
}
} finally {
sendLock.unlock();
}
for (SendSync sync : syncs) {
sync.processSent();
}
} // called with sendLock
private void processSend() throws Exception { for (Iterator<MessageContext> iterator = additions.iterator(); iterator.hasNext(); ) {
MessageContext messageContext = iterator.next();
// It could take while before we receive the commit
// op, by that time the message could have expired..
if (broker.isExpired(messageContext.message)) {
broker.messageExpired(messageContext.context, messageContext.message, null);
destinationStatistics.getExpired().increment();
iterator.remove();
continue;
}
sendMessage(messageContext.message);
messageContext.message.decrementReferenceCount();
}
} private void processSent() throws Exception {
for (MessageContext messageContext : additions) {
messageSent(messageContext.context, messageContext.message);
}
} @Override
public void afterRollback() throws Exception {
try {
for (MessageContext messageContext : additions) {
messageContext.message.decrementReferenceCount();
}
} finally {
sendSyncs.remove(transaction);
}
}
}

3. 那么 XA 事务又是什么呢?ActiveMQ 实现了分布式事务,当系统中存在多数据源的情况下,也许会需要使用 XA ,为了方便,只提供一个单数据源的例子:

Xid xid = new MyXid(1, new byte[]{0x01}, new byte[]{0x02});
session.getTransactionContext().start(xid, XAResource.TMSUCCESS);
// 操作mq
session.getTransactionContext().end(xid, XAResource.TMSUCCESS);
int prepare = session.getTransactionContext().prepare(xid);
System.out.println("prepare:" + prepare);
// 根据prepare结果决定是否提交
session.getTransactionContext().commit(xid, false);

这些操作步骤,和 MySQL的 XA 是一样的,也是 start,end,prepare,commit,实现的都是javax transaction 那一套接口。

public class MyXid implements Xid {
private int formatId;
private byte[] globalTid;
private byte[] branchQ; public MyXid(int formatId, byte[] globalTid, byte[] branchQ) {
this.formatId = formatId;
this.globalTid = globalTid;
this.branchQ = branchQ;
} public byte[] getBranchQualifier() {
return this.branchQ;
} public int getFormatId() {
return formatId;
} public byte[] getGlobalTransactionId() {
return this.globalTid;
}
}

ActiveMQ 事务和XA的更多相关文章

  1. ActiveMQ 事务、集群、持久订阅者、ActiveMQ监控

    JMS介绍 JMS是什么? JMS的全称Java Message Service,既Java消息服务. JMS是SUN提供的旨在统一各种MOM(Message-Oriented Middleware) ...

  2. 分布式事务、XA、两阶段提交、一阶段提交

    本文原文连接:http://blog.csdn.net/bluishglc/article/details/7612811 ,转载请注明出处! 1.XA XA是由X/Open组织提出的分布式事务的规范 ...

  3. 关于分布式事务,XA协议的学习笔记

    XA分布式事务协议,包含二阶段提交(2PC),三阶段提交(3PC)两种实现. 1.二阶段提交方案:强一致性 事务的发起者称协调者,事务的执行者称参与者. 处理流程: 1.准备阶段 事务协调者,向所有事 ...

  4. jms中activemq事务探讨

    http://blog.csdn.net/dly1580854879/article/details/68945997

  5. 如何实现XA式、非XA式Spring分布式事务

    Spring应用的几种事务处理机制 Java Transaction API和XA协议是Spring常用的分布式事务机制,不过你可以选择选择其他的实现方式.理想的实现取决于你的应用程序使用何种资源,你 ...

  6. 非XA式Spring分布式事务

    Spring应用的几种事务处理机制 Java Transaction API和XA协议是Spring常用的分布式事务机制,不过你可以选择选择其他的实现方式.理想的实现取决于你的应用程序使用何种资源,你 ...

  7. MySQL数据库分布式事务XA优缺点与改进方案

    1 MySQL 外部XA分析 1.1 作用分析 MySQL数据库外部XA可以用在分布式数据库代理层,实现对MySQL数据库的分布式事务支持,例如开源的代理工具:ameoba[4],网易的DDB,淘宝的 ...

  8. MySQL 中基于 XA 实现的分布式事务

    1 XA协议 首先我们来简要看下分布式事务处理的XA规范可知XA规范中分布式事务有AP,RM,TM组成: 其中应用程序(Application Program ,简称AP):AP定义事务边界(定义事务 ...

  9. spring boot 分布式事务实现(XA方式)

    关于spring boot 支持分布式事务,XA是常用的一种方式. 这里把相关的配置记下,方便以后使用. 首先配置两个不同的数据源 : 订单库.持仓库. /** * Created by zhangj ...

随机推荐

  1. 【抓包】【Charles】

    Mac抓包神器-----Charles Charles 是一款Mac上的HTTP代理服务器.HTTP监视器.反向代理服务器,可以让开发者监视查看所有连接互联网的HTTP通信,包括请求,响应和HTTP头 ...

  2. 理解 Redis(3) - 字符串值

    正如前面所讲的, redis 的数据结构就是一系列的键值对键 -> printable ASCII (可打印的 ASCII 码, 最大值是 512MB)值 -> Primitives (基 ...

  3. hdu 3208 Integer’s Power 筛法

    Integer’s Power Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  4. SPOJ 刷题记录

    按点赞数降序 297 二分 #include<bits/stdc++.h> using namespace std; #define fi first #define se second ...

  5. 合并k个排序的列表 Merge k Sorted Lists

    2018-11-25 22:58:52 问题描述: 问题求解: 本题可以使用优先队列高效的进行求解,整体的时间复杂度为O(nlogk). public ListNode mergeKLists(Lis ...

  6. selenium+Page Objects(第二话)

    前面介绍了什么是po模式,并且简单分析了一下使用po模式编写脚本的思路,接下来开始正式编写 1.先编写一个页面基类BasePage.py,里面封装每个页面常用的一些方法 # coding: utf-8 ...

  7. (转)c#中const与readonly区别

    const 的概念就是一个包含不能修改的值的变量.常数表达式是在编译时可被完全计算的表达式.因此不能从一个变量中提取的值来初始化常量.如果 const int a = b+1;b是一个变量,显然不能再 ...

  8. Getting Started with Processing 第四章总结

    为什么要使用变量: 我们使用变量的一个重要原因就是避免变成过程中的重复工作,如果你重复使用某一个数字超过了一次,就可以考虑使用一个变量来代替它,这样你的程序会更加通用并且易于更新. 定义变量 定义变量 ...

  9. Wannafly挑战赛26 B 冥土追魂

    首先,证明结果一定是取某些整行,再加上一个多余的一行的前几个. 假如: x1<=x2<=x3<=x4<=x5 y1<=y2<=y3<=y4<=y5 取6 ...

  10. [LintCode] Serialize and Deserialize Binary Tree(二叉树的序列化和反序列化)

    描述 设计一个算法,并编写代码来序列化和反序列化二叉树.将树写入一个文件被称为“序列化”,读取文件后重建同样的二叉树被称为“反序列化”. 如何反序列化或序列化二叉树是没有限制的,你只需要确保可以将二叉 ...