本文主要是介绍流程图解Spring Framework(九) Spring 如何进行事务管理的?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Jdbc事务简述
首先我们来了解一下JDBC的是如何处理事务的
代码很简单
try {// 设置为手动提交,否则执行完一条sql就提交一次事务conn.setAutoCommit(false); // 实际业务操作开始ps.executeUpdate("修改表1");ps.executeUpdate("修改表2"); // 实际业务操作结束// 提交事务conn.commit();} catch (Exception e) { // 出现异常,进行回滚conn.rollback(); e.printStackTrace(); }
查看以上代码可以发现,有如下个流程
- 设置事务手动提交
- 业务操作
- 无异常,正常提交
- 出现异常,事务回滚
看起来也不难的哦,
但是有一个问题是,我们每一次写事务代码,都需要写一些重复的代码,
我们分析以下代码,可以看到这里面操作的都是同一个对象,类型为Connection,
这时候我们思考一下,如果我们把这个connection对象实例包装起来,是不是就可以利用AOP在业务代码前后添加connection的代码了,
我们的思路就是把业务代码设置为一个切面,我们通过在切面前置操作中开启事务,切面后置操作中提交事务或者回滚事务,是不是就好了,那么我们看一下spring是如何操作的
spring 配置事务
java config
EnableTransactionManagement
注解开启
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {//其实 就是@Transactional注解的为切面BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();// 配置匹配规则advisor.setTransactionAttributeSource(transactionAttributeSource());// 设置增强器advisor.setAdvice(transactionInterceptor());advisor.setOrder(this.enableTx.<Integer>getNumber("order"));return advisor;}@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public TransactionAttributeSource transactionAttributeSource() {return new AnnotationTransactionAttributeSource();}@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public TransactionInterceptor transactionInterceptor() {TransactionInterceptor interceptor = new TransactionInterceptor();interceptor.setTransactionAttributeSource(transactionAttributeSource());if (this.txManager != null) {interceptor.setTransactionManager(this.txManager);}return interceptor;}}
- 配置一个事务拦截器
- 配置一个AnnotationTransactionAttributeSource,用于为事务拦截器提供切面声明支持
需要我们再配置一个事务管理器
@Beanpublic DataSource druidDataSource(){DruidDataSource datasource = new DruidDataSource();datasource.setUrl(dbUrl);datasource.setUsername(username);datasource.setPassword(password);datasource.setDriverClassName(driverClassName);return datasource;}@Beanpublic PlatformTransactionManager txManager(DataSource druidDataSource){return new DataSourceTransactionManager(druidDataSource);}
在代码上,我们已经可以添加了@Transactional注解来是方法在事务之中即可。
源码初探
在上一小节可以看到spring中开启事务有一个关键的bean,类型是DataSourceTransactionManager
,那么重点我们就看一下这个Manager做了什么,它是如何开启事务的
首先看一下类图
PlatformTransactionManager有如下三个方法
// 获取一个有效的事务TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;// 提交事务void commit(TransactionStatus status) throws TransactionException;// 回滚事务void rollback(TransactionStatus status) throws TransactionException;
通过我们第一节的介绍,可以知道有了这三个方法即可实现事务
首先分析以下AbstractPlatformTransactionManager.getTransaction()
方法
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {// 这个方法是一个abstract方法,由具体的事务管理器实现Object transaction = doGetTransaction();//判断逻辑已省略//......// No existing transaction found -> check propagation behavior to find out how to proceed.if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");}else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {SuspendedResourcesHolder suspendedResources = suspend(null);if (debugEnabled) {logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);}try {boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);DefaultTransactionStatus status = newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);// 这个方法是一个abstract方法,由具体的事务管理器实现,doBegin(transaction, definition);prepareSynchronization(status, definition);return status;}catch (RuntimeException ex) {resume(null, suspendedResources);throw ex;}catch (Error err) {resume(null, suspendedResources);throw err;}}else {// Create "empty" transaction: no actual transaction, but potentially synchronization.if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {logger.warn("Custom isolation level specified but no actual transaction initiated; " +"isolation level will effectively be ignored: " + definition);}boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);}}
我们具体就看两个Abstrat方法的实现
DataSourceTransactionManager.doGetTransaction
protected Object doGetTransaction() {DataSourceTransactionObject txObject = new DataSourceTransactionObject();txObject.setSavepointAllowed(isNestedTransactionAllowed());// 从数据源获取一个连接ConnectionHolder conHolder =(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);txObject.setConnectionHolder(conHolder, false);return txObject;}
DataSourceTransactionManager.doBegin
protected void doBegin(Object transaction, TransactionDefinition definition) {DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;Connection con = null;try {if (txObject.getConnectionHolder() == null ||txObject.getConnectionHolder().isSynchronizedWithTransaction()) {Connection newCon = this.dataSource.getConnection();if (logger.isDebugEnabled()) {logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");}txObject.setConnectionHolder(new ConnectionHolder(newCon), true);}txObject.getConnectionHolder().setSynchronizedWithTransaction(true);// 获取数据库连接con = txObject.getConnectionHolder().getConnection();Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);txObject.setPreviousIsolationLevel(previousIsolationLevel);// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,// so we don't want to do it unnecessarily (for example if we've explicitly// configured the connection pool to set it already).if (con.getAutoCommit()) {txObject.setMustRestoreAutoCommit(true);if (logger.isDebugEnabled()) {logger.debug("Switching JDBC Connection [" + con + "] to manual commit");}// 设置手动提交con.setAutoCommit(false);}txObject.getConnectionHolder().setTransactionActive(true);int timeout = determineTimeout(definition);if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {txObject.getConnectionHolder().setTimeoutInSeconds(timeout);}// Bind the session holder to the thread.if (txObject.isNewConnectionHolder()) {TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());}}catch (Throwable ex) {if (txObject.isNewConnectionHolder()) {DataSourceUtils.releaseConnection(con, this.dataSource);txObject.setConnectionHolder(null, false);}throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);}}
DataSourceTransactionManager.doCommit
@Overrideprotected void doCommit(DefaultTransactionStatus status) {DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();// 获取连接Connection con = txObject.getConnectionHolder().getConnection();if (status.isDebug()) {logger.debug("Committing JDBC transaction on Connection [" + con + "]");}try {// 事务提交con.commit();}catch (SQLException ex) {throw new TransactionSystemException("Could not commit JDBC transaction", ex);}}
DataSourceTransactionManager.doCommit
@Overrideprotected void doRollback(DefaultTransactionStatus status) {DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();// 获取连接Connection con = txObject.getConnectionHolder().getConnection();if (status.isDebug()) {logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");}try {// 事务回滚con.rollback();}catch (SQLException ex) {throw new TransactionSystemException("Could not roll back JDBC transaction", ex);}}
可以看到spring的处理和我们手写的处理没什么两样,但是仅凭上面的,我们也没有看到我们的业务代码是在哪里实现的,我们来看一下@Transactional
的实现
TransactionInterceptor
首先我们可以看到MethodInteceptor
,我们就可以知道这是一个方法拦截器,主要看他的invoke
方法
public Object invoke(final MethodInvocation invocation) throws Throwable {// Work out the target class: may be {@code null}.// The TransactionAttributeSource should be passed the target class// as well as the method, which may be from an interface.Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);// Adapt to TransactionAspectSupport's invokeWithinTransaction...return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {@Overridepublic Object proceedWithInvocation() throws Throwable {return invocation.proceed();}});}
我们可以看到有一个callback,不妨猜一下就是在事务开启成功后调用
查看TransactionAspectSupport.invokeWithinTransaction
方法
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)throws Throwable {// 获取事务属性,Transactional注解final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);// 获取事务拦截器final PlatformTransactionManager tm = determineTransactionManager(txAttr);final String joinpointIdentification = methodIdentification(method, targetClass);if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {// Standard transaction demarcation with getTransaction and commit/rollback calls.// 创建事务TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);Object retVal = null;try {// This is an around advice: Invoke the next interceptor in the chain.// This will normally result in a target object being invoked.// 果然,我们猜的没有错retVal = invocation.proceedWithInvocation();}catch (Throwable ex) {// target invocation exceptioncompleteTransactionAfterThrowing(txInfo, ex);throw ex;}finally {cleanupTransactionInfo(txInfo);}commitTransactionAfterReturning(txInfo);return retVal;}else {// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.// 编程式事务try {Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,new TransactionCallback<Object>() {@Overridepublic Object doInTransaction(TransactionStatus status) {TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);try {return invocation.proceedWithInvocation();}catch (Throwable ex) {if (txAttr.rollbackOn(ex)) {// A RuntimeException: will lead to a rollback.if (ex instanceof RuntimeException) {throw (RuntimeException) ex;}else {throw new ThrowableHolderException(ex);}}else {// A normal return value: will lead to a commit.return new ThrowableHolder(ex);}}finally {cleanupTransactionInfo(txInfo);}}});// Check result: It might indicate a Throwable to rethrow.if (result instanceof ThrowableHolder) {throw ((ThrowableHolder) result).getThrowable();}else {return result;}}catch (ThrowableHolderException ex) {throw ex.getCause();}}}
以上可以看到,利用这个拦截器,可以实现方法的切面调用,进行事务的开启。这样我们就可以知道了spring是如何管理事务的了
有关事务传播行为和隔离级别的博客可以详见
https://blog.csdn.net/u013076044/article/details/79996198
https://blog.csdn.net/u013076044/article/details/79950916
这篇关于流程图解Spring Framework(九) Spring 如何进行事务管理的?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!