spring揭秘19-spring事务01-事务抽象
文章目录
- 【README】
- 【1】事务基本元素
- 【1.1】事务分类
- 【2】java事务管理
- 【2.1】基于java的局部事务管理
- 【2.2】基于java的分布式事务管理
- 【2.2.1】基于JTA的分布式事务管理
- 【2.2.2】基于JCA的分布式事务管理
- 【2.3】java事务管理的问题
- 【3】spring事务抽象概述
- 【3.1】spring事务抽象的核心接口
- 【4】spring事务管理的3个接口
- 【4.1】TransactionDefinition事务定义
- 【4.1.1】隔离级别
- 【4.1.2】事务传播行为
- 【4.1.3】其他属性
- 【4.1.4】TransactionDefinition实现类
- 【4.2】TransactionStatus事务状态
- 【4.2.1】SavepointManager保存点抽象
- 【4.2.2】TransactionStatus接口实现类
- 【4.3】PlatformTransactionManager(平台事务管理器)
- 【4.3.1】PlatformTransactionManager实现类概览
- 【4.3.2】PlatformTransactionManager内部结构
- 【4.3.3】AbstractPlatformTransactionManager
- 【5】spring事务管理代码实践
- 【5.1】spring集成mybatis及spring事务管理
【README】
本文总结自《spring揭秘》,作者王福强,非常棒的一本书,墙裂推荐;
【1】事务基本元素
1)事务定义:一组sql操作集合; 是操作数据库的最小单元;
2)事务基本元素:
- ResourceManager:资源管理器; 简称RM; 是对数据库的抽象;
- TransactionProcessingMonitor:事务处理监控; 简称TPM 或 TP Monitor; 在分布式事务场景中协调包含多个RM(数据库)的事务处理;
- TransactionManager:事务管理器; 简称TM; 是TP Monitor中的核心模块,负责多RM(数据库)之间事务处理的协调工作,并提供事务界定,事务上下文传播等功能接口;
- Application:以独立形式存在的或者运行于容器中的应用程序,可以认为是事务边界的触发点;
3)实际上,并不是每个事务的场景中都会使用全部元素;
【1.1】事务分类
1)根据整个事务涉及的RM(数据库)数量来区分:
- 局部事务: 当前事务只涉及1个RM;我们称当前事务为局部事务(什么叫当前? 个人理解当前指的是当前线程);
- 全局事务(分布式事务): 整个事务处理过程涉及多个RM;
- 需要引入TP Monitor来协调多个RM之间的事务处理;
- TP Monitor采用两阶段提交协议来保证整个事务的ACID属性;
2)全局事务中各参与者之间的关系:
注意: 局部事务与全局事务(分布式事务)的主要区别在于事务中涉及多少RM,而不是系统中实际有多少RM;
【2】java事务管理
1)事务管理定义: 划分事务边界,规定事务起点与终点 ;
【2.1】基于java的局部事务管理
1)基于java的局部事务管理:要对数据库的访问过程中进行事务管理,每种数据访问技术都提供自身的事务管理api ,如jdbc,mybatis等;
- 数据库资源的局部事务管理:
- 基于jdbc的局部事务管理;
- 基于orm框架(如hibernate,mybaits)的局部事务管理;
- 消息服务资源的局部事务管理;
- 如JMS
【2.2】基于java的分布式事务管理
1)java分布式事务管理,主要通过JTA(java事务api, Java Transaction API) 或者 JCA(java连接器架构 ,Java Connector Architecture);
【2.2.1】基于JTA的分布式事务管理
1)JTA:由sun公司提出的标准化分布式事务访问的 java 接口规范。JTA规范定义的只是一套java接口定义,具体实现由相应提供商实现;
2)JTA提供商产品包括:
- JOTM;
- Atomikos;
- JBoss Transaction;
3)使用JTA的分布式事务管理有2种方式:
- JTA编程事务管理;
- JTA声明性事务管理;
4)JTA编程事务管理: 通常使用 UserTransaction 接口进行,各应用服务器都提供了针对他的JNDI查找服务;
详情可以参见: https://blog.csdn.net/zzuhkp/article/details/124672647
【2.2.2】基于JCA的分布式事务管理
1)JCA规范主要面向EIS(Enterprise Information System,企业信息系统)的集成; 通过为遗留的EIS系统和java ee 应用服务器指定统一的通信标准;
(具体本文不展开)
【2.3】java事务管理的问题
1)问题1: 事务管理逻辑绑定到了具体的数据访问技术上面,耦合性高;
- 使用JDBC数据访问技术,通过java.sql.Connection管理事务;使用Hibernate技术访问,则通过Session管理事务;这样使得事务管理代码与数据访问代码甚至业务代码耦合在一起,事务管理本身属于系统功能,不应该散落在各个业务代码逻辑上;(一个合理的设计应该是: 事务管理代码, 与数据访问代码或业务代码独立开 )
- 如果升级数据访问技术,则与事务管理相关的代码都需要重构,运维成本高;
2)问题2: 事务异常处理:(没有一个统一的事务相关异常体系,类似于原生SQL异常,每个数据库厂商实现不一样;如果数据库迁移或升级,可能需要修改业务代码,运维成本高)
3)问题3:事务处理API的多样性; 处理事务的API有很多,如JDBC,Mybaits,Hibernate等,但没有统一事务管理api ;
【3】spring事务抽象概述
1)spring对事务元素进行抽象, 客户端仅按照统一的编程模型管理事务,而不用关心数据访问技术以及具体要访问什么类型的事务资源;
- 此外:spring事务管理与spring提供的数据访问技术(如JdbcTemplate)进行结合;
2)spring事务框架设计的基本原则: 让事务管理逻辑与数据访问逻辑解耦;
具体也可以参见:spring揭秘15-spring集成数据访问技术(orm框架)总结
【3.1】spring事务抽象的核心接口
1)spring事务抽象的核心接口:PlatformTransactionManager ,平台事务管理器; 主要作用是为应用程序提供事务管理的统一接口;
【PlatformTransactionManager】
public interface PlatformTransactionManager extends TransactionManager {TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;// 获取事务void commit(TransactionStatus status) throws TransactionException; // 提交事务 void rollback(TransactionStatus status) throws TransactionException; // 回滚事务
}
2)PlatformTransactionManager 子类:
- AbstractPlatformTransactionManager:抽象平台事务管理器;
- DataSourceTransactionManager:数据源事务管理器;
- HibernateTransactionManager:Hibernate事务管理器;
- JdbcTransactionManager:Jdbc事务管理器;
- JpaTransactionManager:JPA事务管理器;
- JtaTransactionManager:JTA事务管理器;(分布式事务管理器)
- CallbackPreferringPlatformTransactionManager:回调偏好平台事务管理器;
- ResourceTransactionManager:资源事务管理器;
【4】spring事务管理的3个接口
1)spring事务抽象包括3个主要接口: PlatformTransactionManager , TransactionDefinition, TransactionStatus ;
- PlatformTransactionManager:平台事务管理器; 负责划定事务边界,即事务起点与终点;
- TransactionDefinition:事务定义;定义事务相关属性,包括隔离级别, 传播行为等 ;
- TransactionStatus:事务状态;
【4.1】TransactionDefinition事务定义
1)TransactionDefinition定义了事务属性:
- 事务隔离级别;isolation;
- 事务传播行为;propagation;
- 事务超时时间;timeout;
- 是否为只读事务;readOnly ;
【TransactionDefinition】
public interface TransactionDefinition {int PROPAGATION_REQUIRED = 0;int PROPAGATION_SUPPORTS = 1;int PROPAGATION_MANDATORY = 2;int PROPAGATION_REQUIRES_NEW = 3;int PROPAGATION_NOT_SUPPORTED = 4;int PROPAGATION_NEVER = 5;int PROPAGATION_NESTED = 6;int ISOLATION_DEFAULT = -1;int ISOLATION_READ_UNCOMMITTED = 1;int ISOLATION_READ_COMMITTED = 2;int ISOLATION_REPEATABLE_READ = 4;int ISOLATION_SERIALIZABLE = 8;int TIMEOUT_DEFAULT = -1;default int getPropagationBehavior() {return 0;}default int getIsolationLevel() {return -1;}default int getTimeout() {return -1;}default boolean isReadOnly() {return false;}@Nullabledefault String getName() {return null;}static TransactionDefinition withDefaults() {return StaticTransactionDefinition.INSTANCE;}
}
【4.1.1】隔离级别
1)TransactionDefinition 定义了如下5个常量用于表示隔离级别(类型为int);
- ISOLATION_DEFAULT: 如果指定隔离级别为ISOLATION_DEFAULT,则表示使用数据库默认隔离级别,通常情况下是 ReadCommitted;
- ISOLATION_READ_UNCOMMITTED: 读未提交;
- ISOLATION_READ_COMMITTED:读已提交;
- ISOLATION_REPEATABLE_READ:可重复读;
- ISOLATION_SERIALIZABLE:可串行化;
【4.1.2】事务传播行为
1)事务传播行为: 表示整个事务处理过程所跨越的业务对象,将以什么样的行为参与事务;
class TeachService { // 授课服务teach() {publicTeacherService.teach(); // 公办老师授课trainingTeacherService.teach(); // 培训学校老师授课 }
}// 公办授课服务
class PublicTeacherService{teach(); // (传播行为设置为 Required )
}// 培训学校授课服务
class TraningTeacherService {teach(); // (传播行为设置为 RequiredNew )
}
【场景解说】
- PublicTeacherService.teach()方法传播行为为 Required:
- 若TeachService.teach()本身开启事务1,则 PublicTeacherService.teach()方法复用事务1;
- 若TeachService.teach()本身没有开启事务,则 PublicTeacherService.teach()方法新开启事务1;
- TraningTeacherService.teach()方法传播行为为 RequiredNew:
- 若TeachService.teach()本身开启事务1,则 TraningTeacherService.teach()方法新开启事务2;
- 若TeachService.teach()本身没有开启事务,则 TraningTeacherService.teach()方法新开启事务2;
2)事务传播行为分类(类型为int):
- PROPAGATION_REQUIRED: 如果当前存在事务,则当前方法复用该事务;否则当前方法创建新事务;(什么是当前? 当前线程就是当前)(默认的事务传播行为)
- PROPAGATION_SUPPORTS: 如果当前开启事务,则当前方法复用该事务;否则,当前方法直接执行(不开启事务,如事务自动提交);
- PROPAGATION_MANDATORY:强行要求当前方法存在一个事务,否则抛出异常;
- PROPAGATION_REQUIRES_NEW:不管当前是否存在事务,都会创建新事务;如果当前存在事务,则把当前事务挂起suspend;
- PROPAGATION_NOT_SUPPORTED:不支持当前事务,而是在没有事务的情况下执行;若当前存在事务,则当前事务原则上被挂起suspend; 但这要看对应的 PlatformTransactionManager实现类是否支持事务挂起;
- PROPAGATION_NEVER:永远不需要当前存在事务;若当前存在事务,则抛出异常;
- PROPAGATION_NESTED:如果存在当前事务,则在当前事务的一个嵌套事务中执行(底层原理是保存点Savepoint,即在同一个事务新建多个保存点);否则与 PROPAGATION_REQUIRED 类似,即创建新事务,在新事务 中执行(注意:并非所有PlatformTransactionManager都支持嵌套事务传播行为 PROPAGATION_NESTED );
- PROPAGATION_NESTED中的嵌套事务依赖当前事务(底层原理是保存点);它们父子关系;嵌套事务不能独立于当前事务而存在,当前事务与嵌套事务共有事务状态;(嵌套事务应用场景:可以把一个大事务划分为多个小事务来处理,并且外层事务可以根据各个内部嵌套事务的执行结果,选择不同执行流程)
- PROPAGATION_REQUIRES_NEW新创建的事务与当前事务属于同一个级, 它们是兄弟,相互独立;
【嵌套事务代码示例】
A.service() { // PROPAGATION_REQUIRED, 必须事务try {B.service() // PROPAGATION_NESTED, 嵌套事务} catch(Exception e) {C.service(); // PROPAGATION_NESTED, 嵌套事务}
}
【4.1.3】其他属性
1)事务超时时间: 通过TIMEOUT_DEFAULT 常量来定义,默认值为-1 ,单位秒; 可以通过 TransactionDefinition 实现类提供自定义的事务超时时间;
2)只读事务:通过 isReadOnly() 方法来定义;
【4.1.4】TransactionDefinition实现类
1)DefaultTransactionDefinition是 TransactionDefinition 的默认实现类,其提供了各种事务属性的默认值;
【DefaultTransactionDefinition】 默认事务定义实现类
public class DefaultTransactionDefinition implements TransactionDefinition, Serializable {public static final String PREFIX_PROPAGATION = "PROPAGATION_";public static final String PREFIX_ISOLATION = "ISOLATION_";public static final String PREFIX_TIMEOUT = "timeout_";public static final String READ_ONLY_MARKER = "readOnly";static final Map<String, Integer> propagationConstants = Map.of("PROPAGATION_REQUIRED", 0, "PROPAGATION_SUPPORTS", 1, "PROPAGATION_MANDATORY", 2, "PROPAGATION_REQUIRES_NEW", 3, "PROPAGATION_NOT_SUPPORTED", 4, "PROPAGATION_NEVER", 5, "PROPAGATION_NESTED", 6);static final Map<String, Integer> isolationConstants = Map.of("ISOLATION_DEFAULT", -1, "ISOLATION_READ_UNCOMMITTED", 1, "ISOLATION_READ_COMMITTED", 2, "ISOLATION_REPEATABLE_READ", 4, "ISOLATION_SERIALIZABLE", 8);private int propagationBehavior = 0; // PROPAGATION_REQUIREDprivate int isolationLevel = -1; // ISOLATION_DEFAULT private int timeout = -1;private boolean readOnly = false;@Nullableprivate String name;public DefaultTransactionDefinition() {}public DefaultTransactionDefinition(TransactionDefinition other) {this.propagationBehavior = other.getPropagationBehavior();this.isolationLevel = other.getIsolationLevel();this.timeout = other.getTimeout();this.readOnly = other.isReadOnly();this.name = other.getName();}public DefaultTransactionDefinition(int propagationBehavior) {this.propagationBehavior = propagationBehavior;}// ......
}
2)TransactionDefinition实现类类图如下:
3)TransactionDefinition实现类按照编程式事务和声明式事务分为两类;
- 编程式事务:TransactionTemplate是进行编程式事务管理的模版方法类; TransactionTemplate继承了TransactionDefinition,即TransactionTemplate本身提供了事务属性设置功能;
- 声明式事务:TransactionAttribute应用于使用spring aop进行声明式事务管理的场景;它在TransactionDefinition基础上添加了一个rollbackOn() 方法,使用该方法,业务代码通过声明的方式指定业务方法在抛出哪些异常情况下可以回滚事务;
- 其直接实现类有DefaultTransactionAttribute;
4)DefaultTransactionAttribute下有2个子类,包括 RuledBasedTransactionAttribute 和 DelegatingTransactionAttribute。
- RuledBasedTransactionAttribute:基于规则的事务属性类; 其允许指定多个回滚规则; RuledBasedTransactionAttribute#rollbackOn()方法将使用传入的异常类型与这些回滚规则进行匹配,然后在决定是否要回滚事务;
- 回滚规则表示: RollbackRuleAttribute, 或者 NoRollbackRuleAttribute (RollbackRuleAttribute的子类);
- DelegatingTransactionAttribute:委派事务属性类,是抽象类; 它存在的目的就是被子类化; DelegatingTransactionAttribute会将所有方法调用委派给另一个具体的TransactionAttribute实现类;如DefaultTransactionAttribute,RuledBasedTransactionAttribute;
【TransactionAttribute】事务属性接口定义
public interface TransactionAttribute extends TransactionDefinition {@NullableString getQualifier();Collection<String> getLabels();boolean rollbackOn(Throwable ex);
}
【DefaultTransactionAttribute】默认事务属性接口实现类
public class DefaultTransactionAttribute extends DefaultTransactionDefinition implements TransactionAttribute {@Nullableprivate String descriptor;@Nullableprivate String timeoutString;@Nullableprivate String qualifier;private Collection<String> labels = Collections.emptyList();public DefaultTransactionAttribute() {}public DefaultTransactionAttribute(TransactionAttribute other) {super(other);}public DefaultTransactionAttribute(int propagationBehavior) {super(propagationBehavior);}......
}
【4.2】TransactionStatus事务状态
1)TransactionStatus:表示整个事务处理过程中的事务状态; 通常情况下,我们在编程式事务中使用该接口;
【TransactionStatus】
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {default boolean hasSavepoint() {return false;}default void flush() {}
}
【TransactionExecution】
public interface TransactionExecution {default String getTransactionName() {return "";}default boolean hasTransaction() {return true;}default boolean isNewTransaction() {return true;}default boolean isNested() {return false;}default boolean isReadOnly() {return false;}default void setRollbackOnly() {throw new UnsupportedOperationException("setRollbackOnly not supported");}default boolean isRollbackOnly() {return false;}default boolean isCompleted() {return false;}
}
【SavepointManager】
public interface SavepointManager {Object createSavepoint() throws TransactionException;void rollbackToSavepoint(Object savepoint) throws TransactionException;void releaseSavepoint(Object savepoint) throws TransactionException;
}
【Flushable】
public interface Flushable {/*** Flushes this stream by writing any buffered output to the underlying* stream.** @throws IOException If an I/O error occurs*/void flush() throws IOException;
}
【TransactionStatus类图】
2)TransactionStatus工作方式:
- 使用TransactionStatus查询事务状态;
- 通过 setRollbackOnly()方法标记当前事务以便回滚;
- 如果相应的PlatformTransactionManager支持Savepoint, 可以通过TransactionStatus在当前事务中创建内部嵌套事务;
【4.2.1】SavepointManager保存点抽象
1)保存点的抽象: SavepointManager对Savepoint进行了抽象;通过继承SavepointManager,TransactionStatus 获得可以管理Savapoint的能力,从而支持创建事务内部嵌套事务;
public interface SavepointManager {Object createSavepoint() throws TransactionException;void rollbackToSavepoint(Object savepoint) throws TransactionException;void releaseSavepoint(Object savepoint) throws TransactionException;
}
// TransactionStatus 继承 SavepointManager
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {default boolean hasSavepoint() {return false;}default void flush() {}
}
【4.2.2】TransactionStatus接口实现类
1)AbstractTransactionStatus:TransactionStatus接口的抽象类, 为子类提供一些基础设施;
- DefaultTransactionStatus(默认事务状态类): 是TransactionStatus主要实现类; spring事务框架中各个 TransactionManager的实现类,大都使用 DefaultTransactionStatus 来记载事务状态信息;
- SimpleTransactionStatus:仅供测试,不建议用于生产;
【4.3】PlatformTransactionManager(平台事务管理器)
1)PlatformTransactionManager: 负责划定事务边界,即事务起点与终点;
public interface PlatformTransactionManager extends TransactionManager {TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;// 获取事务void commit(TransactionStatus status) throws TransactionException; // 提交事务 void rollback(TransactionStatus status) throws TransactionException; // 回滚事务
}
【4.3.1】PlatformTransactionManager实现类概览
1)分为面向局部事务与全局事务(分布式事务)共计2个分支;
2)面向局部事务的PlatformTransactionManager实现类
- AbstractPlatformTransactionManager:抽象平台事务管理器;
- DataSourceTransactionManager:数据源事务管理器;
- HibernateTransactionManager:Hibernate事务管理器;
- JdbcTransactionManager:Jdbc事务管理器;
- JpaTransactionManager:JPA事务管理器;
- CallbackPreferringPlatformTransactionManager:回调偏好平台事务管理器;
- ResourceTransactionManager:资源事务管理器;
3)面向全局事务(分布式事务)的PlatformTransactionManager实现类
- JtaTransactionManager:JTA事务管理器;(分布式事务管理器);JtaTransactionManager对各种JTA实现提供的分布式事务进行统一封装;但底层会把事务管理操作委派给 具体的JTA实现类;
【4.3.2】PlatformTransactionManager内部结构
1)内部结构如下:
- TransactionObject:事务对象;承载了当前事务的必要信息,PlatformTransactionManager实现类可以根据事务对象来决定如何处理当前事务; 事务对象类似于 javax.transaction.Transaction 定义;
- TransactionSynchronization:可以注册到事务处理过程的回调接口;类似于事务监听器,如事务完成后或者回调方法清理系统资源;
- TransactionSynchronizationManager: 用于管理TransactionSynchronization, 当前事务状态以及具体的事务资源;类似于javax.transaction.TransactionSynchronizationRegistry定义;
2)spring事务抽象把PlatformTransactionManager作为核心接口及顶层接口,具体实现由不同实现类处理;整个事务管理框架的设计结合了策略模式与模版方法模式;PlatformTransactionManager类图如下:
【4.3.3】AbstractPlatformTransactionManager
1)AbstractPlatformTransactionManager:作为PlatformTransactionManager接口的抽象类,以模版方法模式封装了事务处理逻辑,而把与事务资源相关的操作交给子类实现;
【AbstractPlatformTransactionManager】抽象平台事务管理器主要模版方法
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, ConfigurableTransactionManager, Serializable {// 获取事务public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {// ......} // 挂起事务@Nullableprotected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {// ......}// 恢复事务protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder) throws TransactionException {// ......} // 提交事务public final void commit(TransactionStatus status) throws TransactionException {// ......}// 回滚事务 public final void rollback(TransactionStatus status) throws TransactionException {// ......}
}
2) AbstractPlatformTransactionManager定义的事务内部处理逻辑(算法步骤)如下:
- 根据当前线程是否存在事务,执行不同处理逻辑;
- 根据 TransactionDefinition指定的传播行为执行后续逻辑;
- 根据情况挂起或恢复事务;
- 提交事务前检查 readOnly,若为true,则用回滚事务替代提交事务;
- 在事务回滚的情况下,清理并恢复事务状态;
- 若事务的Synchronization 处于active状态,在事务处理的规定时点触发Synchronization 回调接口;
3)事务处理的完成有2种情况,包括回滚事务与提交事务,分别对应rollback() 与commit() 2个模版方法 ;commit()方法在提交事务前会检查rollBackOnly状态,若为true则执行回滚;(补充:可以通过TransactionStatus.setRollbackOnly()方法标记事务是否回滚)
3.1)rollback(TransactionStatus)包含3种情况:
- 回滚事务:
- 若当前事务是嵌套事务,则通过TransactionStatus释放 Savepoint;
- 若当前事务是新事务,则调用子类 doRollback(TransactionStatus)回滚事务;
- 若当前存在事务,且 rollbackOnly被设置,则调用 子类实现的 doSetRollbackOnly(TransactionStatus)方法,各子类会将TransactionObject的状态设置为 rollbackOnly;
- 触发Synchronization事件:
- 清理事务资源:
- 设置 TransactionStatus.completed为完成状态;
- 清理与当前事务相关的 Synchronization;
- 调用 doCleanupAfterCompletion() 方法释放事务资源,并解除 TransactionSynchronizationManager的资源绑定;
- 若有挂起的事务,则恢复;
3.2)commit(TransactionStatus)处理逻辑如下:
- 提交事务:
- 提交事务前判断全局rollBackOnly标志是否为true;如果最外层事务已经被标记为rollBackOnly,并且failEarlyOnGlobalRollbackOnly为true,则抛出异常;
- 若提交事务前发现TransactionStatus持有Savepoint,则释放它;这实际是在处理嵌套事务的提交;
- 若 TransactionStatus 表示要提交一个新事务,则调用子类的commit()方法提交事务;
- 触发Synchronization事件:
- 若 AbstractPlatformTransactionManager 的 rollbackOnCommitFailure状态被设置为true,则表示若事务提交异常,则回滚;
- 清理事务资源;
【5】spring事务管理代码实践
1)业务场景: 新增银行卡包括2个步骤,步骤1:先插入银行卡; 步骤2:然后再通过id查询银行卡;
- 步骤1:插入逻辑在SpringAndMybatisTxMngServiceByRequired中, 事务传播类型为 REQUIRED;
- 步骤2:查询逻辑在 SpringAndMybatisTxMngServiceByRequiredAndNew ,事务传播类型为 REQUIRES_NEW ;
两个service的事务传播类型不同,以此来比较不同传播模式的事务管理效果;
【5.1】spring集成mybatis及spring事务管理
【pom.xml】maven 依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.tom.springnote</groupId><artifactId>springDiscover</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><name>springDiscover</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.1.10</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>6.1.10</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>6.1.10</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>6.1.10</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.1.10</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>6.1.10</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-orm</artifactId><version>6.1.10</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>6.1.10</version></dependency><!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>3.0.4</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.16</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-dbcp2</artifactId><version>2.12.0</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.32</version></dependency><dependency><groupId>javax.annotation</groupId><artifactId>javax.annotation-api</artifactId><version>1.3.2</version></dependency><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version></dependency><!-- https://mvnrepository.com/artifact/com.alibaba/druid --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.22</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency></dependencies><build><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource><resource><directory>src/main/resources</directory></resource></resources></build></project>
【springAndMybatisIntegrate.xml】
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"><property name="locations"><value>jdbc-springdiscover.properties</value></property></bean><!--注册数据源--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"><property name="url" value="${jdbc.url}"/><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean><!--注册事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><!-- 自动扫描注解 --><context:component-scan base-package="com.tom.springnote.chapter20mybaits"/><!-- 通过注解驱动的声明式事务管理 --><tx:annotation-driven transaction-manager="transactionManager"/><!-- 注册sql会话工厂 --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/><property name="configLocation" value="classpath:mybatisConf.xml"/><!-- 自动扫描mapping.xml文件,**表示迭代查找,也可在sqlMapConfig.xml中单独指定xml文件--><property name="mapperLocations" value="classpath:com/tom/springnote/**/*.mapping.xml"/></bean><!-- mybatis spring sqlSessionTemplate,使用时直接让spring注入即可 --><bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"><constructor-arg index="0" ref="sqlSessionFactory"/></bean></beans>
【jdbc-springdiscover.properties】
jdbc.url=jdbc:mysql://localhost:3306/springdiscover?serverTimezone=Asia/Shanghai
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.username=root
jdbc.password=root
【mybatisConf.xml】mybaits配置 , 设置mybatis会话操作日志,如新建session,提交事务,回滚事务等日志;
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC"-//mybatis.org//DTD Config 3.0//EN""http://www.mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><settings><setting name="logImpl" value="STDOUT_LOGGING"/></settings>
</configuration>
【SpringTxMngServiceByRequiredAndNewMain】
public class SpringTxMngServiceByRequiredAndNewMain {public static void main(String[] args) {ClassPathXmlApplicationContext container = new ClassPathXmlApplicationContext("chapter20/mybatis/springAndMybatisIntegrate.xml");SpringAndMybatisTxMngServiceByRequired txMngService = container.getBean(SpringAndMybatisTxMngServiceByRequired.class);BankCardDto bankCardDto = txMngService.saveAndQryByPropagation(BankCardDto.newBankCardDto(BusiDatetimeUtils.getCurYyyyMmDdHhMmSs()));if (bankCardDto == null) {System.out.println("null");} else {System.out.println(bankCardDto);}}
}
【SpringAndMybatisTxMngServiceByRequired】
@Component("springAndMybatisTxMngServiceByRequired")
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
public class SpringAndMybatisTxMngServiceByRequired {@Autowiredprivate BankCardDao bankCardDao;@Autowiredprivate SpringAndMybatisTxMngServiceByRequiredAndNew springAndMybatisTxMngServiceByRequiredAndNew;public BankCardDto saveAndQryByPropagation(BankCardDto bankCardDto) {System.out.println("====== saveAndQryByPropagation begin");this.saveByPropagation(List.of(bankCardDto));BankCardDto result = springAndMybatisTxMngServiceByRequiredAndNew.queryById(bankCardDto.getId());System.out.println("====== saveAndQryByPropagation end");return result;}public void saveByPropagation(List<BankCardDto> bankCardDtoList) {System.out.println("====== saveByPropagation begin");bankCardDao.insertBankCard(bankCardDtoList.get(0));System.out.println("====== saveByPropagation end");}
}
【SpringAndMybatisTxMngServiceByRequiredAndNew】
@Component("springAndMybatisTxMngServiceByRequiredAndNew")
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
public class SpringAndMybatisTxMngServiceByRequiredAndNew {@Autowiredprivate BankCardDao bankCardDao;public BankCardDto queryById(Long id) {System.out.println("====== queryById begin");BankCardDto result = bankCardDao.qryBankCardById(id);System.out.println("====== queryById end");return result;}public BankCardDto saveAndQryByPropagation(BankCardDto bankCardDto) {System.out.println("====== saveAndQryByPropagation begin");this.saveByPropagation(List.of(bankCardDto));BankCardDto result = this.queryById(bankCardDto.getId());System.out.println("====== saveAndQryByPropagation end");return result;}public void saveByPropagation(List<BankCardDto> bankCardDtoList) {System.out.println("====== saveByPropagation begin");if (CollectionUtils.isEmpty(bankCardDtoList)) {return;}bankCardDao.insertBankCard(bankCardDtoList.get(0));System.out.println("====== saveByPropagation end");}
}
【BankCardDao】
@Repository
public class BankCardDao {@Autowiredprivate SqlSessionTemplate sqlSessionTemplate;private static final String NAMESPACE = "com.tom.springnote.chapter20mybaits.dao.bankcard";public void insertBankCard(BankCardDto bankCardDto) {sqlSessionTemplate.insert(NAMESPACE + ".insertBankCard", bankCardDto);}public BankCardDto qryBankCardById(Long id) {List<BankCardDto> resultList = sqlSessionTemplate.selectList(NAMESPACE + ".qryBankCardById", id);if (CollectionUtils.isEmpty(resultList)) {return null;} else {return resultList.get(0);}}
}
【BankCard.mapping.xml】
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tom.springnote.chapter20mybaits.dao.bankcard"><select id="qryBankCardById" resultType="com.tom.springnote.common.model.BankCardDto">select id, card_no, balance, remarkfrom bank_card_tbl where id = #{id}</select><insert id="insertBankCard">insert into bank_card_tbl (id, card_no, balance, remark)values (#{id}, #{cardNo}, #{balance}, #{remark})</insert>
</mapper>
【打印日志】
信息: {dataSource-1} inited
====== saveAndQryByPropagation begin====== saveByPropagation beginCreating a new SqlSessionRegistering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@724bade8]JDBC Connection [com.alibaba.druid.pool.DruidStatementConnection@6815c5f2] will be managed by Spring==> Preparing: insert into bank_card_tbl (id, card_no, balance, remark) values (?, ?, ?, ?)==> Parameters: 20240908163727(Long), 20240908163727(String), 20240908163727(BigDecimal), 备注20240908163727(String)<== Updates: 1Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@724bade8]====== saveByPropagation endTransaction synchronization suspending SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@724bade8]====== queryById beginCreating a new SqlSessionRegistering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6ab72419]JDBC Connection [com.alibaba.druid.pool.DruidStatementConnection@5bbc9f97] will be managed by Spring==> Preparing: select id, card_no, balance, remark from bank_card_tbl where id = ?==> Parameters: 20240908163727(Long)<== Total: 0Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6ab72419]====== queryById endTransaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6ab72419]Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6ab72419]Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6ab72419]Transaction synchronization resuming SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@724bade8]====== saveAndQryByPropagation end
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@724bade8]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@724bade8]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@724bade8]null
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
【日志解说】
1)事务传播机制:
- SpringAndMybatisTxMngServiceByRequired 事务传播机制是 Propagation.REQUIRED (当前线程存在事务则复用,否则新建事务);
- SpringAndMybatisTxMngServiceByRequiredAndNew 事务传播机制是 Propagation.REQUIRES_NEW (无论当前线程是否存在事务,则当前方法新建事务;若当前线程存在事务1,则先挂起事务1,然后新建事务2;事务2执行完成后,恢复事务1 )
2)新建会话及事务(一个会话就是一个数据库连接,1个会话对应多个事务):
- SpringAndMybatisTxMngServiceByRequired#saveAndQryByPropagation() 方法先调用 this.saveByPropagation() ,再调用 SpringAndMybatisTxMngServiceByRequiredAndNew.queryById() 方法;其中saveByPropagation的事务传播模式是REQUIRED ; queryById的事务传播模式是REQUIRES_NEW ;
- this.saveByPropagation() 方法执行时: 创建 SqlSession[DefaultSqlSession@724bade8] ,开启事务,执行insert操作;
- SpringAndMybatisTxMngServiceByRequiredAndNew.queryById() 执行前:实际先执行spring 事务切面,因为queryById是REQUIRES_NEW ,需要新建事务;所以会先挂起(suspending)当前会话(事务) SqlSession[DefaultSqlSession@724bade8] ,接着再新建会话[DefaultSqlSession@6ab72419]
- queryById()执行完成后,再提交事务(DefaultSqlSession@6ab72419),关闭会话;
- 最后一步是恢复(resuming)会话 [DefaultSqlSession@724bade8] ;
- SpringAndMybatisTxMngServiceByRequired.saveAndQryByPropagation() 执行完成后: 提交事务,关闭会话 [DefaultSqlSession@724bade8];
3)查询结果为null:
- SpringAndMybatisTxMngServiceByRequired#saveAndQryByPropagation是事务1,保存时没有提交事务;
- SpringAndMybatisTxMngServiceByRequiredAndNew#queryById是事务2;因为事务1没有提交,所以事务2查询不到数据,所以是null;(事务隔离级别读已提交)
相关文章:

spring揭秘19-spring事务01-事务抽象
文章目录 【README】【1】事务基本元素【1.1】事务分类 【2】java事务管理【2.1】基于java的局部事务管理【2.2】基于java的分布式事务管理【2.2.1】基于JTA的分布式事务管理【2.2.2】基于JCA的分布式事务管理 【2.3】java事务管理的问题 【3】spring事务抽象概述【3.1】spring…...

基于Matlab的图像去雾系统(四种方法)关于图像去雾的基本算法代码的集合,方法包括局部直方图均衡法、全部直方图均衡法、暗通道先验法、Retinex增强。
基于Matlab的图像去雾系统(四种方法) 关于图像去雾的基本算法代码的集合,方法包括局部直方图均衡法、全部直方图均衡法、暗通道先验法、Retinex增强。 所有代码整合到App designer编写的GUI界面中,包括导入图片,保存处…...

油猴插件录制请求,封装接口自动化参数
参考:如何使用油猴插件提高测试工作效率 一、背景 在酷家乐设计工具测试中,总会有许多高频且较繁琐的工作,比如: 查询插件版本:需要打开Chrome控制台,输入好几个命令然后过滤出版本信息。 查询模型商品&…...

循环购模式!结合引流和复购于一体的商业模型!
欢迎各位朋友,我是你们的电商策略顾问吴军。今天,我将向大家介绍一种新颖的商业模式——循环购模式,它将如何改变我们的消费和收益方式。你是否好奇,为何商家会提供如此慷慨的优惠?消费一千元,不仅能够得到…...

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧
Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用&…...

c中 int 和 unsigned int
c语言中,char、short、int、int64以及unsigned char、unsigned short、unsigned int、unsigned int64等等类型都可以表示整数。但是他们表示整数的位数不同,比如:char/unisigned char表示8位整数; short/unsigned short表示16位整…...

sheng的学习笔记-AI-话题模型(topic model),LDA模型,Unigram Model,pLSA Model
AI目录:sheng的学习笔记-AI目录-CSDN博客 基础知识 什么是话题模型(topic model) 话题模型(topic model)是一族生成式有向图模型,主要用于处理离散型的数据(如文本集合),在信息检索、自然语言处理等领域有广泛应用…...

html 页面引入 vue 组件之 http-vue-loader.js
一、http-vue-loader.js http-vue-loader.js 是一个 Vue 单文件组件加载器,可以让我们在传统的 HTML 页面中使用 Vue 单文件组件,而不必依赖 Node.js 等其他构建工具。它内置了 Vue.js 和样式加载器,并能自动解析 Vue 单文件组件中的所有内容…...

html+css网页设计 旅行 蜘蛛旅行社3个页面
htmlcss网页设计 旅行 蜘蛛旅行社3个页面 网页作品代码简单,可使用任意HTML辑软件(如:Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作)。 获取源码 1&#…...

考拉悠然产品发布会丨以悠然远智全模态AI应用平台探索AI行业应用
9月6日,成都市大模型新技术新成果发布暨供需对接系列活动——考拉悠然专场,在成都市高新区菁蓉汇盛大举行。考拉悠然重磅发布了悠然远智丨全模态AI应用平台,并精彩展示了交通大模型应用——智析快处等最新的AI产品和技术成果。 在四川省科学…...

LLM大模型学习:揭秘LLM应用构建:探究文本加载器的必要性及在LangChain中的运用
构建 LLM 应用为什么需要文本加载器,langchain 中如何使用文本加载器? 在不同的应用场景中需要使用不同的文本内容作为内容的载体,针对不同的类型的文本,langchain 提供了多种文本加载器来帮助我们快速的将文本切片,从…...

Flutter函数
在Dart中,函数为 一等公民,可以作为参数对象传递,也可以作为返回值返回。 函数定义 // 返回值 (可以不写返回值,但建议写)、函数名、参数列表 showMessage(String message) {//函数体print(message); }void showMessage(String m…...

P3565 [POI2014] HOT-Hotels
~~~~~ P3565 [POI2014] HOT-Hotels ~~~~~ 总题单链接 思路 ~~~~~ 设 g [ u ] [ i ] g[u][i] g[u][i] 表示在 u u u 的子树内,距离 u u u 为 i i i 的点的个数。 ~~~~~ 设 d p [ u ] [ i ] dp[u][i] dp[u][i] 表示: u u u 的子树内存在两个点 x , …...

设计模式 | 单例模式
定义 单例设计模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。这种模式常用于需要控制对某些资源的访问的场景,例如数据库连接、日志记录等。 单例模式涉…...

Web安全之CSRF攻击详解与防护
在互联网应用中,安全性问题是开发者必须时刻关注的核心内容之一。跨站请求伪造(Cross-Site Request Forgery, CSRF),是一种常见的Web安全漏洞。通过CSRF攻击,黑客可以冒用受害者的身份,发送恶意请求&#x…...

IDEA运行Java程序提示“java: 警告: 源发行版 11 需要目标发行版 11”
遇到这个提示一般是在pom.xml中已经指定了构建的Java版本环境是11例如(此时添加了build插件的情况下虽然不能直接运行代码但是maven是可以正常打包构建): <build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><…...

车载测试| 汽车的五域架构 (含线控技术知识)
汽车的五域架构是一种将汽车电子控制系统按照功能进行划分的架构模式,主要包括动力域、底盘域、座舱域、自动驾驶域和车身域。(汽车三域架构通常是指将汽车电子系统划分为三个主要领域:动力域、底盘域和智能座舱域(或车身舒适域&a…...

【Linux】gcc/g++ 、make/Makefile、git、gdb 的使用
目录 1. Linux编译器-gcc/g1.1 编译器gcc/g的工作步骤1.2 函数库1.2.1 函数库的作用及分类1.2.2 动态链接和静态链接1.2.3 动态库和静态库的优缺点 1.3 gcc选项 2. Linux项目自动化构建工具-make/Makefile2.1 .PHONY2.2 尝试编写进度条程序 3. git3.1 安装 git3.2 下载项目到本…...

Elastic Stack--ES的DSL语句查询
前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除 学习B站博主教程笔记: 最新版适合自学的ElasticStack全套视频(Elk零基础入门到精通教程)Linux运维必备—Elastic…...

ARM基础知识---CPU---处理器
目录 一、ARM架构 1.1.RAM---随机存储器 1.2.ROM---只读存储器 1.3.flash---闪存存储器 1.4.时钟(振晶) 1.5.复位 二、CPU---ARM920T 2.1.R0~R12---通用寄存器 2.2.PC程序计数器 2.3.LR连接寄存器 2.4.SP栈指针寄存器 2.5.CPSR当前程序状态寄存…...

将星 x17 安装ubuntu 20.04 双系统
准备工作,包含关闭快速启动,关闭Secret Boot 1.进入控制面板选择小图标,找到电源选项 2.点击更改当前不可用的设置,关闭快速启动 3.开机启动时快速按F2,进入BIOS 4.选择Setup Utiltity,选择Security&#…...

E31.【C语言】练习:指针运算习题集(上)
Exercise 1 求下列代码的运行结果 #include <stdio.h> int main() {int a[5] { 1, 2, 3, 4, 5 };int* ptr (int*)(&a 1);printf("%d",*(ptr - 1));return 0; } 答案速查: 分析: Exercise 2 求下列代码的运行结果 //在x86环境下 //假设结…...

git分支的管理
分支管理是 Git 版本控制系统中的一个核心功能,它涉及如何创建、管理、合并和删除分支,以便在团队协作和开发过程中更有效地组织代码。以下是分支管理中的一些关键概念和实践: 1. 分支的创建 创建新分支:在开发新功能、修复 bug…...

对于消息队列的一些思考
如何保证消息不被重复消费 唯一ID:你提到的通过唯一ID解决重复消费问题非常重要。这通常通过业务系统引入唯一消息ID(如UUID)来实现。在消费端,先检查消息ID是否已经被处理,未处理过的才进行处理,确保幂等…...

IM即时通讯软件-WorkPlus私有化部署的局域网即时通讯工具
随着企业对通讯安全和数据掌控的需求不断增加,许多企业开始选择私有化部署的即时通讯工具,以在内部局域网环境中实现安全、高效的沟通与协作。IM-WorkPlus作为一款受欢迎的即时通讯软件,提供了私有化部署的选项,使企业能够在自己的…...

AI大模型的饕餮盛宴,系统学习大模型技术,你想要的书都在这里了
AI大模型的饕餮盛宴,系统学习大模型技术,你想要的书都在这里了 要说现在最热门的技术,可谓非大模型莫属!不少小伙伴都想要学习大模型技术,转战AI领域,以适应未来的大趋势,寻求更有前景的发展~~…...

支付宝开放平台-开发者社区——AI 日报「9 月 9 日」
1 离开 OpenAl 后,llya 拿了10亿美金对抗 Al 作恶 极窖公园 丨阅读原文 lya Sutskever, OpenAl的前联合创始人,成立了SS1 (Safe Superintelligence),旨在构建安全的Al模型。SSl获得了10亿美元的融资,估值达到50亿美元ÿ…...

将AI与情境定位结合以确保品牌安全
你可能会看到一些广告,感觉它们跟你在线阅读或观看的内容有奇怪的关联。这就是上下文广告在起作用。这种基于广告的解决方案在不断变化的数字环境中逐步发展,已经成为每个广告主的必备工具。不过,这种广告不只是把广告和上下文进行匹配这么简…...

OpenAI 联合 SWE 发布 AI 软件工程能力测试集,Gru.ai 荣登榜首
在 9 月 3 日,Gru.ai 在 SWE-Bench-Verified 评估最新发布的数据中以 45.2% 的高分排名第一。SWE-Bench-Verified 是 OpenAI 联合 SWE 发布测试集,旨在更可靠的评估 AI 解决实际软件问题的能力。该测试集经由人工验证打标,被认为是评估 AI 软…...

一文读懂SpringMVC的工作原理
前言 MVC是经典的软件架构设计模式,几乎在各个领域各种开发语言中,均采纳了这个思想。此刻博主突然想到了Thinking in xxx系列设计书籍。换句话说,就是“各人自扫门前雪”和“术业有专攻”。当职责分配得当后,剩下的就是发挥各“…...