浅谈MyBatis 事务管理
1.运行环境Enviroment
当MyBatis与不同的应用结合时,需要不同的事务管理机制。与Spring结合时,由Spring来管理事务;单独使用时需要自行管理事务,在容器里运行时可能由容器进行管理。
MyBatis用Enviroment来表示运行环境,其封装了三个属性:
publicclassConfiguration{
//一个MyBatis的配置只对应一个环境
protectedEnvironmentenvironment;
//其他属性.....
}
publicfinalclassEnvironment{
privatefinalStringid;
privatefinalTransactionFactorytransactionFactory;
privatefinalDataSourcedataSource;
}
2.事务抽象
MyBatis把事务管理抽象出Transaction接口,由TransactionFactory接口的实现类负责创建。
publicinterfaceTransaction{
ConnectiongetConnection()throwsSQLException;
voidcommit()throwsSQLException;
voidrollback()throwsSQLException;
voidclose()throwsSQLException;
IntegergetTimeout()throwsSQLException;
}
publicinterfaceTransactionFactory{
voidsetProperties(Propertiesprops);
TransactionnewTransaction(Connectionconn);
TransactionnewTransaction(DataSourcedataSource,TransactionIsolationLevellevel,booleanautoCommit);
}
Executor的实现持有一个SqlSession实现,事务控制是委托给SqlSession的方法来实现的。
publicabstractclassBaseExecutorimplementsExecutor{
protectedTransactiontransaction;
publicvoidcommit(booleanrequired)throwsSQLException{
if(closed){
thrownewExecutorException("Cannotcommit,transactionisalreadyclosed");
}
clearLocalCache();
flushStatements();
if(required){
transaction.commit();
}
}
publicvoidrollback(booleanrequired)throwsSQLException{
if(!closed){
try{
clearLocalCache();
flushStatements(true);
}finally{
if(required){
transaction.rollback();
}
}
}
}
//省略其他方法、属性
}
3.与Spring集成的事务管理
3.1配置TransactionFactory
与Spring集成时,通过SqlSessionFactoryBean来初始化MyBatis。
protectedSqlSessionFactorybuildSqlSessionFactory()throwsIOException{
Configurationconfiguration;
XMLConfigBuilderxmlConfigBuilder=null;
if(this.configuration!=null){
configuration=this.configuration;
if(configuration.getVariables()==null){
configuration.setVariables(this.configurationProperties);
}elseif(this.configurationProperties!=null){
configuration.getVariables().putAll(this.configurationProperties);
}
}elseif(this.configLocation!=null){
xmlConfigBuilder=newXMLConfigBuilder(this.configLocation.getInputStream(),null,this.configurationProperties);
configuration=xmlConfigBuilder.getConfiguration();
}else{
configuration=newConfiguration();
configuration.setVariables(this.configurationProperties);
}
if(this.objectFactory!=null){
configuration.setObjectFactory(this.objectFactory);
}
if(this.objectWrapperFactory!=null){
configuration.setObjectWrapperFactory(this.objectWrapperFactory);
}
if(this.vfs!=null){
configuration.setVfsImpl(this.vfs);
}
if(hasLength(this.typeAliasesPackage)){
String[]typeAliasPackageArray=tokenizeToStringArray(this.typeAliasesPackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
for(StringpackageToScan:typeAliasPackageArray){
configuration.getTypeAliasRegistry().registerAliases(packageToScan,
typeAliasesSuperType==null?Object.class:typeAliasesSuperType);
}
}
if(!isEmpty(this.typeAliases)){
for(Class>typeAlias:this.typeAliases){
configuration.getTypeAliasRegistry().registerAlias(typeAlias);
}
}
if(!isEmpty(this.plugins)){
for(Interceptorplugin:this.plugins){
configuration.addInterceptor(plugin);
}
}
if(hasLength(this.typeHandlersPackage)){
String[]typeHandlersPackageArray=tokenizeToStringArray(this.typeHandlersPackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
for(StringpackageToScan:typeHandlersPackageArray){
configuration.getTypeHandlerRegistry().register(packageToScan);
}
}
if(!isEmpty(this.typeHandlers)){
for(TypeHandler>typeHandler:this.typeHandlers){
configuration.getTypeHandlerRegistry().register(typeHandler);
}
}
if(this.databaseIdProvider!=null){//fix#64setdatabaseIdbeforeparsemapperxmls
try{
configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
}catch(SQLExceptione){
thrownewNestedIOException("FailedgettingadatabaseId",e);
}
}
if(this.cache!=null){
configuration.addCache(this.cache);
}
if(xmlConfigBuilder!=null){
try{
xmlConfigBuilder.parse();
}catch(Exceptionex){
thrownewNestedIOException("Failedtoparseconfigresource:"+this.configLocation,ex);
}finally{
ErrorContext.instance().reset();
}
}
//创建SpringManagedTransactionFactory
if(this.transactionFactory==null){
this.transactionFactory=newSpringManagedTransactionFactory();
}
//封装成Environment
configuration.setEnvironment(newEnvironment(this.environment,this.transactionFactory,this.dataSource));
if(!isEmpty(this.mapperLocations)){
for(ResourcemapperLocation:this.mapperLocations){
if(mapperLocation==null){
continue;
}
try{
XMLMapperBuilderxmlMapperBuilder=newXMLMapperBuilder(mapperLocation.getInputStream(),
configuration,mapperLocation.toString(),configuration.getSqlFragments());
xmlMapperBuilder.parse();
}catch(Exceptione){
thrownewNestedIOException("Failedtoparsemappingresource:'"+mapperLocation+"'",e);
}finally{
ErrorContext.instance().reset();
}
}
}else{
}
returnthis.sqlSessionFactoryBuilder.build(configuration);
}
publicclassSqlSessionFactoryBuilder{
publicSqlSessionFactorybuild(Configurationconfig){
returnnewDefaultSqlSessionFactory(config);
}
}
重点是在构建MyBatisConfiguration对象时,把transactionFactory配置成SpringManagedTransactionFactory,再封装成Environment对象。
3.2运行时事务管理
Mapper的代理对象持有的是SqlSessionTemplate,其实现了SqlSession接口。
SqlSessionTemplate的方法并不直接调用具体的SqlSession的方法,而是委托给一个动态代理,通过代理SqlSessionInterceptor对方法调用进行拦截。
SqlSessionInterceptor负责获取真实的与数据库关联的SqlSession实现,并在方法执行完后决定提交或回滚事务、关闭会话。
publicclassSqlSessionTemplateimplementsSqlSession,DisposableBean{
privatefinalSqlSessionFactorysqlSessionFactory;
privatefinalExecutorTypeexecutorType;
privatefinalSqlSessionsqlSessionProxy;
privatefinalPersistenceExceptionTranslatorexceptionTranslator;
publicSqlSessionTemplate(SqlSessionFactorysqlSessionFactory,ExecutorTypeexecutorType,
PersistenceExceptionTranslatorexceptionTranslator){
notNull(sqlSessionFactory,"Property'sqlSessionFactory'isrequired");
notNull(executorType,"Property'executorType'isrequired");
this.sqlSessionFactory=sqlSessionFactory;
this.executorType=executorType;
this.exceptionTranslator=exceptionTranslator;
//因为SqlSession接口声明的方法也不少,
//在每个方法里添加事务相关的拦截比较麻烦,
//不如创建一个内部的代理对象进行统一处理。
this.sqlSessionProxy=(SqlSession)newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
newClass[]{SqlSession.class},
newSqlSessionInterceptor());
}
publicintupdate(Stringstatement){
//在代理对象上执行方法调用
returnthis.sqlSessionProxy.update(statement);
}
//对方法调用进行拦截,加入事务控制逻辑
privateclassSqlSessionInterceptorimplementsInvocationHandler{
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{
//获取与数据库关联的会话
SqlSessionsqlSession=SqlSessionUtils.getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try{
//执行SQL操作
Objectresult=method.invoke(sqlSession,args);
if(!SqlSessionUtils.isSqlSessionTransactional(sqlSession,SqlSessionTemplate.this.sqlSessionFactory)){
//如果sqlSession不是Spring管理的,则要自行提交事务
sqlSession.commit(true);
}
returnresult;
}catch(Throwablet){
Throwableunwrapped=unwrapThrowable(t);
if(SqlSessionTemplate.this.exceptionTranslator!=null&&unwrappedinstanceofPersistenceException){
SqlSessionUtils.closeSqlSession(sqlSession,SqlSessionTemplate.this.sqlSessionFactory);
sqlSession=null;
Throwabletranslated=SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException)unwrapped);
if(translated!=null){
unwrapped=translated;
}
}
throwunwrapped;
}finally{
if(sqlSession!=null){
SqlSessionUtils.closeSqlSession(sqlSession,SqlSessionTemplate.this.sqlSessionFactory);
}
}
}
}
}
SqlSessionUtils封装了对Spring事务管理机制的访问。
//SqlSessionUtils
publicstaticSqlSessiongetSqlSession(SqlSessionFactorysessionFactory,ExecutorTypeexecutorType,PersistenceExceptionTranslatorexceptionTranslator){
//从Spring的事务管理机制那里获取当前事务关联的会话
SqlSessionHolderholder=(SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);
SqlSessionsession=sessionHolder(executorType,holder);
if(session!=null){
//已经有一个会话则复用
returnsession;
}
//创建新的会话
session=sessionFactory.openSession(executorType);
//注册到Spring的事务管理机制里
registerSessionHolder(sessionFactory,executorType,exceptionTranslator,session);
returnsession;
}
privatestaticvoidregisterSessionHolder(SqlSessionFactorysessionFactory,ExecutorTypeexecutorType,
PersistenceExceptionTranslatorexceptionTranslator,SqlSessionsession){
SqlSessionHolderholder;
if(TransactionSynchronizationManager.isSynchronizationActive()){
Environmentenvironment=sessionFactory.getConfiguration().getEnvironment();
if(environment.getTransactionFactory()instanceofSpringManagedTransactionFactory){
holder=newSqlSessionHolder(session,executorType,exceptionTranslator);
TransactionSynchronizationManager.bindResource(sessionFactory,holder);
//重点:注册会话管理的回调钩子,真正的关闭动作是在回调里完成的。
TransactionSynchronizationManager.registerSynchronization(newSqlSessionSynchronization(holder,sessionFactory));
holder.setSynchronizedWithTransaction(true);
//维护会话的引用计数
holder.requested();
}else{
if(TransactionSynchronizationManager.getResource(environment.getDataSource())==null){
}else{
thrownewTransientDataAccessResourceException(
"SqlSessionFactorymustbeusingaSpringManagedTransactionFactoryinordertouseSpringtransactionsynchronization");
}
}
}else{
}
}
publicstaticvoidcloseSqlSession(SqlSessionsession,SqlSessionFactorysessionFactory){
//从线程本地变量里获取Spring管理的会话
SqlSessionHolderholder=(SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);
if((holder!=null)&&(holder.getSqlSession()==session)){
//Spring管理的不直接关闭,由回调钩子来关闭
holder.released();
}else{
//非Spring管理的直接关闭
session.close();
}
}
SqlSessionSynchronization是SqlSessionUtils的内部私有类,用于作为回调钩子与Spring的事务管理机制协调工作,TransactionSynchronizationManager在适当的时候回调其方法。
privatestaticfinalclassSqlSessionSynchronizationextendsTransactionSynchronizationAdapter{
privatefinalSqlSessionHolderholder;
privatefinalSqlSessionFactorysessionFactory;
privatebooleanholderActive=true;
publicSqlSessionSynchronization(SqlSessionHolderholder,SqlSessionFactorysessionFactory){
this.holder=holder;
this.sessionFactory=sessionFactory;
}
publicintgetOrder(){
returnDataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER-1;
}
publicvoidsuspend(){
if(this.holderActive){
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
}
}
publicvoidresume(){
if(this.holderActive){
TransactionSynchronizationManager.bindResource(this.sessionFactory,this.holder);
}
}
publicvoidbeforeCommit(booleanreadOnly){
if(TransactionSynchronizationManager.isActualTransactionActive()){
try{
this.holder.getSqlSession().commit();
}catch(PersistenceExceptionp){
if(this.holder.getPersistenceExceptionTranslator()!=null){
DataAccessExceptiontranslated=this.holder
.getPersistenceExceptionTranslator()
.translateExceptionIfPossible(p);
if(translated!=null){
throwtranslated;
}
}
throwp;
}
}
}
publicvoidbeforeCompletion(){
if(!this.holder.isOpen()){
TransactionSynchronizationManager.unbindResource(sessionFactory);
this.holderActive=false;
//真正关闭数据库会话
this.holder.getSqlSession().close();
}
}
publicvoidafterCompletion(intstatus){
if(this.holderActive){
TransactionSynchronizationManager.unbindResourceIfPossible(sessionFactory);
this.holderActive=false;
//真正关闭数据库会话
this.holder.getSqlSession().close();
}
this.holder.reset();
}
}
3.3创建新会话
//DefaultSqlSessionFactory
privateSqlSessionopenSessionFromDataSource(ExecutorTypeexecType,TransactionIsolationLevellevel,booleanautoCommit){
Transactiontx=null;
try{
finalEnvironmentenvironment=configuration.getEnvironment();
//获取事务工厂实现
finalTransactionFactorytransactionFactory=getTransactionFactoryFromEnvironment(environment);
tx=transactionFactory.newTransaction(environment.getDataSource(),level,autoCommit);
finalExecutorexecutor=configuration.newExecutor(tx,execType);
returnnewDefaultSqlSession(configuration,executor,autoCommit);
}catch(Exceptione){
closeTransaction(tx);//mayhavefetchedaconnectionsoletscallclose()
throwExceptionFactory.wrapException("Erroropeningsession.Cause:"+e,e);
}finally{
ErrorContext.instance().reset();
}
}
privateTransactionFactorygetTransactionFactoryFromEnvironment(Environmentenvironment){
if(environment==null||environment.getTransactionFactory()==null){
returnnewManagedTransactionFactory();
}
returnenvironment.getTransactionFactory();
}
4.小结
- MyBatis的核心组件Executor通过Transaction接口来进行事务控制。
- 与Spring集成时,初始化Configuration时会把transactionFactory设置为SpringManagedTransactionFactory的实例。
- 每个Mapper代理里注入的SqlSession是SqlSessionTemplate的实例,其实现了SqlSession接口;
- SqlSessionTemplate把对SqlSession接口里声明的方法调用委托给内部的一个动态代理,该代理的方法处理器为内部类SqlSessionInterceptor。
- SqlSessionInterceptor接收到方法调用时,通过SqlSessionUtil访问Spring的事务设施,如果有与Spring当前事务关联的SqlSession则复用;没有则创建一个。
- SqlSessionInterceptor根据Spring当前事务的状态来决定是否提交或回滚事务。会话的真正关闭是通过注册在TransactionSynchronizationManager上的回调钩子实现的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。