前言:
测试环境:两个微服务,分别为customer和goods。
概念:调用方(customer),被调用方(goods)
下图是customer的程序入口,里面调用了goods的feign接口。
这里是seata服务的数据库,存在3张表。
branch_table用来记录当前事务的插入批次信息。批次id用来后续查询undo_log进行回滚
global_table 用来记录当前的请求的全局事务信息。保证整个调用链是同一个全局事务,重点就是xid
事务调用方:
注解的实现类为:
GlobalTransactionalInterceptor类
TransactionalTemplate类execute方法:
注意:commitTransaction这个方法并没有提交数据库事务,只是通知。如果这里打断点的话,是在表里面找不到数据的。
事务被调用方(即feign接口服务类):
SeataHandlerInterceptor类 第一步拦截feign接口请求,查看请求头是否带有TX_XID
然后直接到执行目标的dll方法↓
这里就是常规的mybatis插入。但是!seata通过注入statement的实现类,从而由mybatis底层方法,执行到seata的底层方法
可以说这里就是被调用方seata的入口。PreparedStatementProxy的实际实现类为ExecuteTemplate
实际执行的是父类BaseTransactionalExecutor中的execute方法






{
"@class":"io.seata.rm.datasource.undo.BranchUndoLog",
"xid":"192.168.100.66:8191:316614175000367104",
"branchId":316614175235248100,
"sqlUndoLogs":[
"java.util.ArrayList",
[
{
"@class":"io.seata.rm.datasource.undo.SQLUndoLog",
"sqlType":"INSERT",
"tableName":"undo_log",
"beforeImage":{
"@class":"io.seata.rm.datasource.sql.struct.TableRecords$EmptyTableRecords",
"tableName":"undo_log",
"rows":[
"java.util.ArrayList",
[
]
]
},
"afterImage":{
"@class":"io.seata.rm.datasource.sql.struct.TableRecords",
"tableName":"undo_log",
"rows":[
"java.util.ArrayList",
[
{
"@class":"io.seata.rm.datasource.sql.struct.Row",
"fields":[
"java.util.ArrayList",
[
{
"@class":"io.seata.rm.datasource.sql.struct.Field",
"name":"id",
"keyType":"PRIMARY_KEY",
"type":-5,
"value":[
"java.lang.Long",
84
]
},
{
"@class":"io.seata.rm.datasource.sql.struct.Field",
"name":"branch_id",
"keyType":"NULL",
"type":-5,
"value":[
"java.lang.Long",
1
]
},
{
"@class":"io.seata.rm.datasource.sql.struct.Field",
"name":"xid",
"keyType":"NULL",
"type":12,
"value":null
},
{
"@class":"io.seata.rm.datasource.sql.struct.Field",
"name":"context",
"keyType":"NULL",
"type":12,
"value":null
},
{
"@class":"io.seata.rm.datasource.sql.struct.Field",
"name":"rollback_info",
"keyType":"NULL",
"type":-4,
"value":null
},
{
"@class":"io.seata.rm.datasource.sql.struct.Field",
"name":"log_status",
"keyType":"NULL",
"type":4,
"value":null
},
{
"@class":"io.seata.rm.datasource.sql.struct.Field",
"name":"log_created",
"keyType":"NULL",
"type":93,
"value":null
},
{
"@class":"io.seata.rm.datasource.sql.struct.Field",
"name":"log_modified",
"keyType":"NULL",
"type":93,
"value":null
}
]
]
}
]
]
}
}
]
]
}
总结:
调用方通过开启全局seata事务,调用方生成全局事务信息即global_table表数据,生成的xid添加到feigin接口的请求头。被调用方根据xid是否存在,执行是否加入全局事务的逻辑。被调用方会直接提交数据库事务(可以在数据库直接查到新数据),并生成undol_og,和banch_table的数据。
回滚的时候,会通过banchId去查询undo_log的数据,banch_table同时记录了数据库的信息,而undo_log里面记录了新增数据的主键,回滚的时候就可以连接对应的数据库根据主键删掉新增的数据