安装教程
在数据库本地事务隔离级别是读已提交(Read Committed)或以上的基础上,AT模式的默认全局隔离级别是读未提交(Read Uncommitted)。如果必须要求全局的读已提交,目前seata的方式是通过select for update语句的代理。SELECT FOR UPDATE 语句的执行会查询全局锁,如果全局锁被其他事务持有,则释放本地锁(回滚 SELECT FOR UPDATE 语句的本地执行)并重试。这个过程中,查询是被 block 住的,直到全局锁拿到,即读取的相关数据是已提交的,才返回。
AT 会对写操作的 SQL 进行拦截,提交本地事务前,会向 TC 获取全局锁,未获取到全局锁的情况下,不能进行写,以此来保证不会发生写冲突:
表结构sql:
-- auto-generated definition
create table student
(
urid int auto_increment
primary key,
code varchar(255) null,
name varchar(255) null
);
代码示例:
package cn.itcast.user.service.impl;
import cn.itcast.user.mapper.StudentMapper;
import cn.itcast.user.pojo.Student;
import cn.itcast.user.service.SeataTestService;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class SeataTestServiceImpl implements SeataTestService {
@Autowired
private StudentMapper studentMapper;
@Override
@GlobalTransactional
public void withoutLocalTransaction() throws InterruptedException {
Student student = new Student();
student.setCode("103");
student.setName("0206");
studentMapper.insert(student);
// 模拟中间的一些业务操作
Thread.sleep(1000);
Student studentInDB = studentMapper.getStudentByCode("103");
System.out.println("此时数据库中的数据:" + studentInDB);
studentInDB.setName("2311");
studentMapper.updateById(studentInDB);
// 模拟中间的一些业务操作
Thread.sleep(1000);
studentInDB = studentMapper.getStudentByCode("103");
System.out.println("修改后数据库中的数据:" + studentInDB);
}
}
另外使用了一个新的请求来模拟中间的查询调用:
最后的日志结果全文如下:
02-06 23:32:38:646 DEBUG 1800 --- [nio-8081-exec-3] .s.i.h.TransactionPropagationIntercepter : xid in RootContext[null] xid in HttpContext[null]
02-06 23:32:38:647 DEBUG 1800 --- [nio-8081-exec-3] i.s.c.r.n.AbstractNettyRemotingClient : offer message: timeout=60000,transactionName=withoutLocalTransaction()
02-06 23:32:38:647 DEBUG 1800 --- [Send_TMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : write message:SeataMergeMessage timeout=60000,transactionName=withoutLocalTransaction()
, channel:[id: 0xad179dd9, L:/127.0.0.1:54807 - R:/127.0.0.1:8091],active?true,writable?true,isopen?true
02-06 23:32:38:651 DEBUG 1800 --- [ctor_TMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : io.seata.core.rpc.netty.TmNettyRemotingClient@8fc6ef9 msgId:42, body:MergeResultMessage xid=172.16.11.4:8091:366004859934097408;extraData=;
02-06 23:32:38:651 DEBUG 1800 --- [nio-8081-exec-3] io.seata.core.context.RootContext : bind 172.16.11.4:8091:366004859934097408
02-06 23:32:38:651 INFO 1800 --- [nio-8081-exec-3] i.seata.tm.api.DefaultGlobalTransaction : Begin new global transaction [172.16.11.4:8091:366004859934097408]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2f9479cf] was not registered for synchronization because synchronization is not active
JDBC Connection [io.seata.rm.datasource.ConnectionProxy@2153924d] will not be managed by Spring
==> Preparing: INSERT INTO student ( code, name ) VALUES ( ?, ? )
==> Parameters: 106(String), 020600(String)
02-06 23:32:38:655 DEBUG 1800 --- [nio-8081-exec-3] i.s.c.r.n.AbstractNettyRemotingClient : offer message: xid=172.16.11.4:8091:366004859934097408,branchType=AT,resourceId=jdbc:mysql://127.0.0.1:3306/gotest,lockKey=student:11
02-06 23:32:38:655 DEBUG 1800 --- [Send_RMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : write message:SeataMergeMessage xid=172.16.11.4:8091:366004859934097408,branchType=AT,resourceId=jdbc:mysql://127.0.0.1:3306/gotest,lockKey=student:11
, channel:[id: 0x0107a5c3, L:/127.0.0.1:52087 - R:/127.0.0.1:8091],active?true,writable?true,isopen?true
02-06 23:32:38:658 DEBUG 1800 --- [ctor_RMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : io.seata.core.rpc.netty.RmNettyRemotingClient@cee3f84 msgId:46, body:MergeResultMessage BranchRegisterResponse: branchId=366004859967651840,result code =Success,getMsg =null
02-06 23:32:38:659 DEBUG 1800 --- [nio-8081-exec-3] i.s.r.d.undo.AbstractUndoLogManager : Flushing UNDO LOG: {"@class":"io.seata.rm.datasource.undo.BranchUndoLog","xid":"172.16.11.4:8091:366004859934097408","branchId":366004859967651840,"sqlUndoLogs":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.undo.SQLUndoLog","sqlType":"INSERT","tableName":"student","beforeImage":{"@class":"io.seata.rm.datasource.sql.struct.TableRecords$EmptyTableRecords","tableName":"student","rows":["java.util.ArrayList",[]]},"afterImage":{"@class":"io.seata.rm.datasource.sql.struct.TableRecords","tableName":"student","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":"urid","keyType":"PRIMARY_KEY","type":4,"value":11},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"code","keyType":"NULL","type":12,"value":"106"},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"name","keyType":"NULL","type":12,"value":"020600"}]]}]]}}]]}
<== Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2f9479cf]
02-06 23:32:41:257 DEBUG 1800 --- [nio-8081-exec-5] .s.i.h.TransactionPropagationIntercepter : xid in RootContext[null] xid in HttpContext[null]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4b70b320] was not registered for synchronization because synchronization is not active
JDBC Connection [io.seata.rm.datasource.ConnectionProxy@5cca8640] will not be managed by Spring
==> Preparing: select * from student where code = 106
==> Parameters:
<== Columns: urid, code, name
<== Row: 11, 106, 020600
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4b70b320]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f8f0f8] was not registered for synchronization because synchronization is not active
JDBC Connection [io.seata.rm.datasource.ConnectionProxy@416739] will not be managed by Spring
==> Preparing: select * from student where code = 106
==> Parameters:
<== Columns: urid, code, name
<== Row: 11, 106, 020600
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14f8f0f8]
此时数据库中的数据:Student(urid=11, code=106, name=020600)
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5cd009e2] was not registered for synchronization because synchronization is not active
JDBC Connection [io.seata.rm.datasource.ConnectionProxy@6de996f8] will not be managed by Spring
==> Preparing: UPDATE student SET code=?, name=? WHERE urid=?
==> Parameters: 106(String), 2325(String), 11(Long)
02-06 23:32:43:733 DEBUG 1800 --- [nio-8081-exec-3] i.s.c.r.n.AbstractNettyRemotingClient : offer message: xid=172.16.11.4:8091:366004859934097408,branchType=AT,resourceId=jdbc:mysql://127.0.0.1:3306/gotest,lockKey=student:11
02-06 23:32:43:733 DEBUG 1800 --- [Send_RMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : write message:SeataMergeMessage xid=172.16.11.4:8091:366004859934097408,branchType=AT,resourceId=jdbc:mysql://127.0.0.1:3306/gotest,lockKey=student:11
, channel:[id: 0x0107a5c3, L:/127.0.0.1:52087 - R:/127.0.0.1:8091],active?true,writable?true,isopen?true
02-06 23:32:43:735 DEBUG 1800 --- [ctor_RMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : io.seata.core.rpc.netty.RmNettyRemotingClient@cee3f84 msgId:48, body:MergeResultMessage BranchRegisterResponse: branchId=366004881262133248,result code =Success,getMsg =null
02-06 23:32:43:736 DEBUG 1800 --- [nio-8081-exec-3] i.s.r.d.undo.AbstractUndoLogManager : Flushing UNDO LOG: {"@class":"io.seata.rm.datasource.undo.BranchUndoLog","xid":"172.16.11.4:8091:366004859934097408","branchId":366004881262133248,"sqlUndoLogs":["java.util.ArrayList",[{"@class":"io.seata.rm.datasource.undo.SQLUndoLog","sqlType":"UPDATE","tableName":"student","beforeImage":{"@class":"io.seata.rm.datasource.sql.struct.TableRecords","tableName":"student","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":"urid","keyType":"PRIMARY_KEY","type":4,"value":11},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"code","keyType":"NULL","type":12,"value":"106"},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"name","keyType":"NULL","type":12,"value":"020600"}]]}]]},"afterImage":{"@class":"io.seata.rm.datasource.sql.struct.TableRecords","tableName":"student","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":"urid","keyType":"PRIMARY_KEY","type":4,"value":11},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"code","keyType":"NULL","type":12,"value":"106"},{"@class":"io.seata.rm.datasource.sql.struct.Field","name":"name","keyType":"NULL","type":12,"value":"2325"}]]}]]}}]]}
<== Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5cd009e2]
02-06 23:32:46:808 DEBUG 1800 --- [nio-8081-exec-4] .s.i.h.TransactionPropagationIntercepter : xid in RootContext[null] xid in HttpContext[null]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1dc57973] was not registered for synchronization because synchronization is not active
JDBC Connection [io.seata.rm.datasource.ConnectionProxy@1b3aeffb] will not be managed by Spring
==> Preparing: select * from student where code = 106
==> Parameters:
<== Columns: urid, code, name
<== Row: 11, 106, 2325
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1dc57973]
02-06 23:32:48:658 DEBUG 1800 --- [ctor_TMROLE_1_1] i.s.c.r.n.AbstractNettyRemotingClient : will send ping msg,channel [id: 0xad179dd9, L:/127.0.0.1:54807 - R:/127.0.0.1:8091]
02-06 23:32:48:658 DEBUG 1800 --- [ctor_TMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : write message:services ping, channel:[id: 0xad179dd9, L:/127.0.0.1:54807 - R:/127.0.0.1:8091],active?true,writable?true,isopen?true
02-06 23:32:48:659 DEBUG 1800 --- [ctor_TMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : io.seata.core.rpc.netty.TmNettyRemotingClient@8fc6ef9 msgId:43, body:services pong
02-06 23:32:48:659 DEBUG 1800 --- [ctor_TMROLE_1_1] i.s.c.r.p.c.ClientHeartbeatProcessor : received PONG from /127.0.0.1:8091
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@614c4ad4] was not registered for synchronization because synchronization is not active
JDBC Connection [io.seata.rm.datasource.ConnectionProxy@2438f2e] will not be managed by Spring
==> Preparing: select * from student where code = 106
==> Parameters:
<== Columns: urid, code, name
<== Row: 11, 106, 2325
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@614c4ad4]
修改后数据库中的数据:Student(urid=11, code=106, name=2325)
02-06 23:32:48:784 DEBUG 1800 --- [nio-8081-exec-3] i.s.c.r.n.AbstractNettyRemotingClient : offer message: xid=172.16.11.4:8091:366004859934097408,extraData=null
02-06 23:32:48:784 DEBUG 1800 --- [Send_TMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : write message:SeataMergeMessage xid=172.16.11.4:8091:366004859934097408,extraData=null
, channel:[id: 0xad179dd9, L:/127.0.0.1:54807 - R:/127.0.0.1:8091],active?true,writable?true,isopen?true
02-06 23:32:48:786 DEBUG 1800 --- [ctor_TMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : io.seata.core.rpc.netty.TmNettyRemotingClient@8fc6ef9 msgId:45, body:MergeResultMessage globalStatus=Committed,ResultCode=Success,Msg=null
02-06 23:32:48:786 DEBUG 1800 --- [nio-8081-exec-3] io.seata.core.context.RootContext : unbind 172.16.11.4:8091:366004859934097408
02-06 23:32:48:786 DEBUG 1800 --- [nio-8081-exec-3] i.seata.tm.api.DefaultGlobalTransaction : Suspending current transaction,xid = 172.16.11.4:8091:366004859934097408
02-06 23:32:48:786 INFO 1800 --- [nio-8081-exec-3] i.seata.tm.api.DefaultGlobalTransaction : [172.16.11.4:8091:366004859934097408] commit status: Committed
02-06 23:32:48:789 DEBUG 1800 --- [nio-8081-exec-6] .s.i.h.TransactionPropagationIntercepter : xid in RootContext[null] xid in HttpContext[null]
02-06 23:32:48:791 DEBUG 1800 --- [nio-8081-exec-6] .s.i.h.TransactionPropagationIntercepter : xid in RootContext[null] xid in HttpContext[null]
02-06 23:32:49:077 DEBUG 1800 --- [ctor_RMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : io.seata.core.rpc.netty.RmNettyRemotingClient@cee3f84 msgId:10, body:xid=172.16.11.4:8091:366004859934097408,branchId=366004859967651840,branchType=AT,resourceId=jdbc:mysql://127.0.0.1:3306/gotest,applicationData=null
02-06 23:32:49:078 INFO 1800 --- [h_RMROLE_1_5_32] i.s.c.r.p.c.RmBranchCommitProcessor : rm client handle branch commit process:xid=172.16.11.4:8091:366004859934097408,branchId=366004859967651840,branchType=AT,resourceId=jdbc:mysql://127.0.0.1:3306/gotest,applicationData=null
02-06 23:32:49:078 INFO 1800 --- [h_RMROLE_1_5_32] io.seata.rm.AbstractRMHandler : Branch committing: 172.16.11.4:8091:366004859934097408 366004859967651840 jdbc:mysql://127.0.0.1:3306/gotest null
02-06 23:32:49:078 INFO 1800 --- [h_RMROLE_1_5_32] io.seata.rm.AbstractRMHandler : Branch commit result: PhaseTwo_Committed
02-06 23:32:49:078 DEBUG 1800 --- [h_RMROLE_1_5_32] i.s.c.r.p.c.RmBranchCommitProcessor : branch commit result:xid=172.16.11.4:8091:366004859934097408,branchId=366004859967651840,branchStatus=PhaseTwo_Committed,result code =Success,getMsg =null
02-06 23:32:49:078 DEBUG 1800 --- [h_RMROLE_1_5_32] i.s.c.rpc.netty.AbstractNettyRemoting : write message:xid=172.16.11.4:8091:366004859934097408,branchId=366004859967651840,branchStatus=PhaseTwo_Committed,result code =Success,getMsg =null, channel:[id: 0x0107a5c3, L:/127.0.0.1:52087 - R:/127.0.0.1:8091],active?true,writable?true,isopen?true
02-06 23:32:49:079 DEBUG 1800 --- [ctor_RMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : io.seata.core.rpc.netty.RmNettyRemotingClient@cee3f84 msgId:11, body:xid=172.16.11.4:8091:366004859934097408,branchId=366004881262133248,branchType=AT,resourceId=jdbc:mysql://127.0.0.1:3306/gotest,applicationData=null
02-06 23:32:49:079 INFO 1800 --- [h_RMROLE_1_6_32] i.s.c.r.p.c.RmBranchCommitProcessor : rm client handle branch commit process:xid=172.16.11.4:8091:366004859934097408,branchId=366004881262133248,branchType=AT,resourceId=jdbc:mysql://127.0.0.1:3306/gotest,applicationData=null
02-06 23:32:49:079 INFO 1800 --- [h_RMROLE_1_6_32] io.seata.rm.AbstractRMHandler : Branch committing: 172.16.11.4:8091:366004859934097408 366004881262133248 jdbc:mysql://127.0.0.1:3306/gotest null
02-06 23:32:49:079 INFO 1800 --- [h_RMROLE_1_6_32] io.seata.rm.AbstractRMHandler : Branch commit result: PhaseTwo_Committed
02-06 23:32:49:079 DEBUG 1800 --- [h_RMROLE_1_6_32] i.s.c.r.p.c.RmBranchCommitProcessor : branch commit result:xid=172.16.11.4:8091:366004859934097408,branchId=366004881262133248,branchStatus=PhaseTwo_Committed,result code =Success,getMsg =null
02-06 23:32:49:079 DEBUG 1800 --- [h_RMROLE_1_6_32] i.s.c.rpc.netty.AbstractNettyRemoting : write message:xid=172.16.11.4:8091:366004859934097408,branchId=366004881262133248,branchStatus=PhaseTwo_Committed,result code =Success,getMsg =null, channel:[id: 0x0107a5c3, L:/127.0.0.1:52087 - R:/127.0.0.1:8091],active?true,writable?true,isopen?true
02-06 23:32:49:823 DEBUG 1800 --- [AsyncWorker_1_1] i.s.r.d.undo.AbstractUndoLogManager : batch delete undo log size 2
02-06 23:32:58:810 DEBUG 1800 --- [ctor_TMROLE_1_1] i.s.c.r.n.AbstractNettyRemotingClient : will send ping msg,channel [id: 0xad179dd9, L:/127.0.0.1:54807 - R:/127.0.0.1:8091]
02-06 23:32:58:810 DEBUG 1800 --- [ctor_TMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : write message:services ping, channel:[id: 0xad179dd9, L:/127.0.0.1:54807 - R:/127.0.0.1:8091],active?true,writable?true,isopen?true
02-06 23:32:58:810 DEBUG 1800 --- [ctor_TMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : io.seata.core.rpc.netty.TmNettyRemotingClient@8fc6ef9 msgId:46, body:services pong
02-06 23:32:58:811 DEBUG 1800 --- [ctor_TMROLE_1_1] i.s.c.r.p.c.ClientHeartbeatProcessor : received PONG from /127.0.0.1:8091
02-06 23:32:59:106 DEBUG 1800 --- [ctor_RMROLE_1_1] i.s.c.r.n.AbstractNettyRemotingClient : will send ping msg,channel [id: 0x0107a5c3, L:/127.0.0.1:52087 - R:/127.0.0.1:8091]
02-06 23:32:59:106 DEBUG 1800 --- [ctor_RMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : write message:services ping, channel:[id: 0x0107a5c3, L:/127.0.0.1:52087 - R:/127.0.0.1:8091],active?true,writable?true,isopen?true
02-06 23:32:59:107 DEBUG 1800 --- [ctor_RMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : io.seata.core.rpc.netty.RmNettyRemotingClient@cee3f84 msgId:49, body:services pong
02-06 23:32:59:107 DEBUG 1800 --- [ctor_RMROLE_1_1] i.s.c.r.p.c.ClientHeartbeatProcessor : received PONG from /127.0.0.1:8091
02-06 23:33:08:829 DEBUG 1800 --- [ctor_TMROLE_1_1] i.s.c.r.n.AbstractNettyRemotingClient : will send ping msg,channel [id: 0xad179dd9, L:/127.0.0.1:54807 - R:/127.0.0.1:8091]
02-06 23:33:08:829 DEBUG 1800 --- [ctor_TMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : write message:services ping, channel:[id: 0xad179dd9, L:/127.0.0.1:54807 - R:/127.0.0.1:8091],active?true,writable?true,isopen?true
02-06 23:33:08:830 DEBUG 1800 --- [ctor_TMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : io.seata.core.rpc.netty.TmNettyRemotingClient@8fc6ef9 msgId:47, body:services pong
02-06 23:33:08:830 DEBUG 1800 --- [ctor_TMROLE_1_1] i.s.c.r.p.c.ClientHeartbeatProcessor : received PONG from /127.0.0.1:8091
02-06 23:33:09:125 DEBUG 1800 --- [ctor_RMROLE_1_1] i.s.c.r.n.AbstractNettyRemotingClient : will send ping msg,channel [id: 0x0107a5c3, L:/127.0.0.1:52087 - R:/127.0.0.1:8091]
02-06 23:33:09:125 DEBUG 1800 --- [ctor_RMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : write message:services ping, channel:[id: 0x0107a5c3, L:/127.0.0.1:52087 - R:/127.0.0.1:8091],active?true,writable?true,isopen?true
02-06 23:33:09:126 DEBUG 1800 --- [ctor_RMROLE_1_1] i.s.c.rpc.netty.AbstractNettyRemoting : io.seata.core.rpc.netty.RmNettyRemotingClient@cee3f84 msgId:50, body:services pong
02-06 23:33:09:126 DEBUG 1800 --- [ctor_RMROLE_1_1] i.s.c.r.p.c.ClientHeartbeatProcessor : received PONG from /127.0.0.1:8091
能够明显的看到当内部没有本地事务的时候每个数据库操作都会是一个事务。
且在全局事务提交之前能够读取到数据库更新后的内容。
to be continue