需求: 实现service-order和service-pay的分布式事务
1.service-order
1.1pom.xml
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--activemq-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<!--activemq pool-->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mysql:MyBatis相关依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!-- mysql:mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- mysql:阿里巴巴数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
<!-- json-lib -->
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
1.2applications.yml
server:
port: 5001
#应用名称及验证账号
spring:
application:
name: service-order
activemq:
broker-url: tcp://127.0.0.1:61616
user: admin
password: admin
pool:
enabled: true
max-connections: 100
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/service_order?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: ***
dbcp2:
initial-size: 5
min-idle: 5
max-total: 5
max-wait-millis: 200
validation-query: SELECT 1
test-while-idle: true
test-on-borrow: false
test-on-return: false
mybatis:
mapper-locations:
- classpath:mapper/*.xml
1.3Java 代码:
1.3.1ActiveMQConfig
@Configuration
public class ActiveMQConfig {
@Value("${spring.activemq.broker-url}")
private String brokerUrl;
@Bean
public Queue queue() {
return new ActiveMQQueue("ActiveMQQueue");
}
@Bean
public ActiveMQConnectionFactory connectionFactory(){
return new ActiveMQConnectionFactory(brokerUrl);
}
}
1.3.2TblOrderEvent
@Data
public class TblOrderEvent implements Serializable {
private Integer id;
/**
* 事件类型(支付表支付完成,订单表修改状态)
*/
private String orderType;
/**
* 事件环节(new,published,processed)
*/
private String process;
/**
* 事件内容,保存事件发生时需要传递的数据
*/
private String content;
private Date createTime;
private Date updateTime;
private static final long serialVersionUID = 1L;
}
1.3.3 ProduceTask:定时任务读取时间表,将orderType为1的的事件发送给消息队列
@Component
public class ProduceTask {
@Autowired
private TblOrderEventDao tblOrderEventDao;
@Autowired
private Queue queue;
@Autowired
JmsMessagingTemplate jmsMessagingTemplate;
@Scheduled(cron = "0/5 * * * * ?")
@Transactional(rollbackFor = Exception.class)
public void task() {
System.out.println("定时任务");
List<TblOrderEvent> tblOrderEventList = tblOrderEventDao.selectByOrderType("1");
for (int i = 0; i < tblOrderEventList.size(); i++) {
TblOrderEvent event = tblOrderEventList.get(i);
// 更改这条数据的orderType为2
tblOrderEventDao.updateEvent(event.getOrderType());
System.out.println("修改数据库完成");
jmsMessagingTemplate.convertAndSend(queue, JSONObject.fromObject(event).toString());
}
}
}
1.3.4 启动类
@SpringBootApplication
@EnableJms
@EnableScheduling
public class ServiceOrderApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceOrderApplication.class, args);
}
}
2.service-pay
2.1pom.xml与service-order相同
2.2 application.yml
server:
port: 5002
spring:
application:
name: service-pay
activemq:
broker-url: tcp://127.0.0.1:61616
user: admin
password: admin
pool:
enabled: true
max-connections: 100
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/service_pay?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: ***
dbcp2:
initial-size: 5
min-idle: 5
max-total: 5
max-wait-millis: 200
validation-query: SELECT 1
test-while-idle: true
test-on-borrow: false
test-on-return: false
mybatis:
mapper-locations:
- classpath:mapper/*.xml
2.3java代码
2.3.1 ActiveMQConfig
@Configuration
public class ActiveMQConfig {
@Value("${spring.activemq.broker-url}")
private String brokerUrl;
/**
* 连接工厂
* @param redeliveryPolicy
* @return
*/
@Bean
public ActiveMQConnectionFactory connectionFactory(RedeliveryPolicy redeliveryPolicy){
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory("admin","admin",brokerUrl);
activeMQConnectionFactory.setRedeliveryPolicy(redeliveryPolicy);
return activeMQConnectionFactory;
}
/**
* 重发配置
* @return
*/
@Bean
public RedeliveryPolicy redeliveryPolicy(){
RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy();
return redeliveryPolicy;
}
/**
* 设置消息队列 确认机制
* @param activeMQConnectionFactory
* @return
*/
@Bean
public JmsListenerContainerFactory jmsListenerContainerFactory(ActiveMQConnectionFactory activeMQConnectionFactory){
DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
bean.setConnectionFactory(activeMQConnectionFactory);
// 1: 自动确认,2: 客户端手动确认,3:自动批量确认,4 事务提交并确认。
bean.setSessionAcknowledgeMode(2);
return bean;
}
}
2.3.2 ConsumerQueue
@Component
public class ConsumerQueue {
@Autowired
private TblOrderEventDao tblOrderEventDao;
@JmsListener(destination = "ActiveMQQueue",containerFactory = "jmsListenerContainerFactory")
public void receive(TextMessage textMessage, Session session) throws JMSException {
try {
System.out.println("收到的消息:"+textMessage.getText());
String content = textMessage.getText();
TblOrderEvent tblOrderEvent = (TblOrderEvent) JSONObject.toBean(JSONObject.fromObject(content),TblOrderEvent.class);
tblOrderEventDao.insert(tblOrderEvent);
// 业务完成,确认消息 消费成功
textMessage.acknowledge();
}catch (Exception e){
// 回滚消息
e.printStackTrace();
// e.getMessage(); // 放到log中。
System.out.println("异常了");
session.recover();
}
}
/**
* 补偿 处理(人工,脚本)。自己根据自己情况。
* @param text
*/
@JmsListener(destination = "ActiveMQ.DLQ")
public void receive2(String text){
System.out.println("死信队列:"+text);
}
}
2.3.3 启动类
@SpringBootApplication
@EnableJms
public class ServicePayApplication {
public static void main(String[] args) {
SpringApplication.run(ServicePayApplication.class, args);
}
}