浅谈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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。