分布式事务实现
一、链式调用法
问题假设需要A、B、C三个服务中的a()、b()、c()方法并需要事务
1:再a()、b()、c()三个方法中搁置加入事务。然后进行链式调用
@Transactional
public void a() {
//TODO 执行A服务的a()方法的方法体
doSomething();
//TODO 调用B服务的b()方法
B.b();
}
@Transactional
public void B() {
//TODO 执行B服务的b()方法的方法体
doSomething();
//TODO 调用C服务的c()方法
C.c();
}
二、推送同步法
1:把当前需要调用的多个服务拼装成对象(List)
@Data
public class PostParam {
public PostParam(){}
public PostParam(String method){
this.method = method;
}
public PostParam(String method, Object body){
this.method = method;
this.body = body;
}
private String method;
private Object body;
}
2:通过mysql的insert方法把第1步中拼装的对象插入数据库中
1.事务表结构
@Data
@Accessors(chain = true)
@TableName("distributed_transactional")
public class DistributedTransactional implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 事务id
*/
@TableId(value = "transactional_id", type = IdType.AUTO)
private String transactionalId;
/**
* 事务内容,JSONAray格式
*/
@TableField("content")
private String content;
/**
* 操作人
*/
@TableField("operate_user")
private String operateUser;
/**
* 操作时间
*/
@TableField("operate_time")
private LocalDateTime operateTime;
/**
* 操作次数
*/
@TableField("operate_number")
private int operateNumber;
}
2.执行分布式事务的方法
public void excute (List<PostParam> list) {
DistributedTransactional transactional = new DistributedTransactional()
transactional.setTransactionalId(UUID.getUUID());
transactional.setContent(JSONObject.toJSONString(list));
transactional.setOperateUser(loginUser);
transactional.setOperateTime(LocalDateTime.now());
//TODO 先把事务信息插入数据库中
distributedTransactionalDao.inset(transactional);
//TODO 此处处理业务流程
for (PostParam param : list) {
//TODO 此处发送业务数据去具体的某个服务,并进行单个服务的业务处理
sendPost(param);
}
//TODO 如果一切顺利,则删除本条事务数据
distributedTransactionalDao.delete(transactional);
}
3:启动定时任务,读取数据库表中第2步中插入的数据,解析后继续第3步中失败的任务
@Component
@EnableScheduling
@Slf4j
public class TransactionalSchedule {
@Autowired
private DistributedTransactionalDao distributedTransactionalDao;
@Scheduled(cron = "0 0 3 * * ?")
public void excute() {
//TODO 此处扫描全表的再2.2中处理失败的事务(如果数据可能太多,可以分页)
List<DistributedTransactional> transactionalList = distributedTransactionalDao.selectList();
for (DistributedTransactional dtl : transactionalList) {
try{
List<PostParam> list = JSONArray.parseArray(dtl.getContent(), PostParam.class);
//TODO 此处处理业务流程
for (PostParam param : list) {
//TODO 此处发送业务数据去具体的某个服务,并进行单个服务的业务处理
sendPost(param);
}
//TODO 如果本次操作成功;删除此事务信息
distributedTransactionalDao.delete(dtl);
} catch (Exception e) {
//TODO 如果本次依然操作失败;操作次数+1
dtl.setOperateNumber(dtl.getOperateNumber()+1);
distributedTransactionalDao.update(dtl);
}
}
}
}
三、使用外部插件实现
1:使用seata:http://seata.io/zh-cn/docs/user/api.html