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. dplyr-高效的数据变换与整理工具--转载

    1.背景简介 在数据分析工作中,经常需要对原始的数据集进行清洗.整理以及变换.常用的数据整理与变换工作主要包括:特定分析变量的选取.满足条件的数据记录的筛选.按某一个或几个变量排序.对原始变量进行加工 ...

  2. idea中git pull push需要反复输入密码

    在使用idea开发的过程中,在终端terminal中git pull和git push时遇到一个问题,一个是 每次提交都需要输入用户名和密码,,从网上找了下解决方案,记录一下. 解决: 打开git终端 ...

  3. docker 日志分析

    日志分两类,一类是 Docker 引擎日志:另一类是 容器日志. Docker 引擎日志 Docker 引擎日志 一般是交给了 Upstart(Ubuntu 14.04) 或者 systemd (Ce ...

  4. SQL 中常用的功能函数,自定义的功能行数

    在SQL Server指定的数据库中,有Programmability目录,在这个目录下,有存储过程,有功能函数. set ANSI_NULLS ON set QUOTED_IDENTIFIER ON ...

  5. Android 错误集合

    1. Error:java.util.concurrent.ExecutionException: com.android.tools.aapt2.Aapt2Exception: AAPT2 erro ...

  6. IntelliJ IDEA平台下JNI编程(五)—本地C代码创建Java对象及引用

    本文学习如何在C代码中创建Java对象和对象数组,前面我们学习了C代码中访问Java对象的属性和方法,其实在创建对象时本质上也就是调用构造函数,因此本文知识学习起来也很轻松.有了前面学习数组创建的方法 ...

  7. ionic日历插件

       1:引入插件的两个文件 timePicker.js 和timePicker.css文件    2:填加插件模块到项目模块中CorderYuan->app.js的moudule    3:在 ...

  8. learn python the hard way 习题6~10总结

    习题6总结 定义字符串: 名字 = 值 其他 你也可以用 {types_of_people}的方式把它放在任何字符串中. 也就是说你可以在其他字符串中添加{},然后前面加一个 f,可用print()进 ...

  9. U8800 手机恢复出厂设置出现轻触Android开始页面 处理办法

    U8800 恢复出厂设置出现轻触Android开始页面处理办法 问题现象 Huawei 手机U8800刷机后,点击恢复出厂默认设置后,出现了一个一直停留在“欢迎使用Android 轻触 Android ...

  10. LeetCode--455--分发饼干

    问题描述: 假设你是一位很棒的家长,想要给你的孩子们一些小饼干.但是,每个孩子最多只能给一块饼干.对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸:并且每块饼干 j , ...