spring中的事务

来源:互联网 发布:软件锁许可管理器 cad 编辑:程序博客网 时间:2024/06/05 19:22
1)spring的事务管理器:package org.springframework.transaction;public interface PlatformTransactionManager {TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;void commit(TransactionStatus status) throws TransactionException;void rollback(TransactionStatus status) throws TransactionException;}2)spring的事务定义类:package org.springframework.transaction;import java.sql.Connection;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;// 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则等价于PROPAGATION_REQUIRED。// 事务的隔离级别int ISOLATION_DEFAULT = -1;// 使用底层数据库的默认隔离级别。int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;/** * Use the default timeout of the underlying transaction system, or none if timeouts are not supported. */// 事务超时:指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。// 默认为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。int TIMEOUT_DEFAULT = -1;int getPropagationBehavior();int getIsolationLevel();int getTimeout();boolean isReadOnly();String getName();}3)spring中事务的回滚:1)spring推荐以抛出异常的方式来回滚一个事务。2)spring事务管理器会捕捉任何未处理的异常,然后根据相应的配置来判断是否回滚抛出异常的事务。1>默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。2>可以配置在抛出哪些异常时回滚事务,包括checked异常;也可以明确设置哪些异常抛出时不回滚事务。4)@Transactional注解属性类型描述valueString可选的限定描述符,指定使用的事务管理器propagationenum 可选的事务传播行为设置isolationenum 可选的事务隔离级别设置readOnlyboolean读写或只读事务,默认读写timeoutint (in seconds granularity)事务超时时间设置rollbackFor(继承Throwable的)Class数组导致事务回滚的异常类数组rollbackForClassName(继承Throwable的)类名数组导致事务回滚的异常类名字数组noRollbackFor(继承Throwable的)Class数组不会导致事务回滚的异常类数组noRollbackForClassName(继承Throwable的)类名数组不会导致事务回滚的异常类名字数组用法:可以写在类(接口)上,也可以方法上。1)当作用于类上时,该类的所有public方法将都具有该类型的事务属性。2)可以在方法上使用该注解来覆盖类级别上的设置。3)Spring建议不要在接口或接口方法上使用该注解,因为只有在使用基于接口的代理时它才会生效。4)在private、protected、default的方法上使用该注解,则该注解将被忽略,也不会抛出任何异常。5)默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是说:类内部方法调用本类内部的其它方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰!5)原理:1)spring的事务管理是通过spring的AOP(动态代理)来实现的。spring中事务生效的一个前提:调用的方法必须被TransactionInterceptor拦截。说明:只有通过TransactionInterceptor拦截的方法才会被加入到spring的事务管理中。举例:在方法A中调用@Transactional修饰的方法B时,如果方法A与方法B在同一个类TestClass中,则加在方法B上的@Transactional注解不起作用,因为此时方法A对方法B的调用是不会被拦截器拦截的!解决办法:在方法A中,使用当前的代理对象来调用方法B。eg:((TestClass)AopContext.currentProxy()).B();2)对于正常的事务管理,必须关闭数据库的自动提交模式,spring会将底层连接的自动提交特性设置为false。package org.springframework.jdbc.datasource;public class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean {private DataSource dataSource;/** * This implementation sets the isolation level but ignores the timeout. */@Overrideprotected 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); // 【spring将底层连接的自动提交设置为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) {DataSourceUtils.releaseConnection(con, this.dataSource);throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);}}}6)配置文件:1)注解的形式:spring + mybatis:说明:mybatis会自动参与到spring事务的管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源与DataSourceTransactionManager引用的数据源一致即可,否则事务管理不起作用。<!-- 定义事务管理器 -->  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean> <!-- 使用注解的形式管理事务 -->  <tx:annotation-driven transaction-manager="transactionManager" /> <!-- 定义SqlSessionFactory --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource" /><property name="configLocation" value="classpath:/mybatis_advertise.xml" /></bean>spring + hibernate:<!-- 事务管理器 --><bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory" ref="sessionFactory" /></bean><!-- 使用注解的形式管理事务 --><tx:annotation-driven transaction-manager="transactionManager"/><!-- 定义SessionFactory -->              <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  <property name="dataSource" ref="dataSource" />                <property name="configLocation" value="classpath:hibernate.cfg.xml" />             </bean>  2)切面的形式:<!-- 定义事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean><!-- 事务的处理策略:相当于注解形式中的@Transactional注解 --><tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><!-- 设置事务的属性,相当于@Transactional注解的属性 --><tx:method name="query*" read-only="true" /><tx:method name="save*" propagation="REQUIRED" /><tx:method name="*" /> </tx:attributes></tx:advice><aop:config><!--定义需要使用事务的切入点 --><aop:pointcut id="myPointcut" expression="execution(* com.jxn.mybatis.service.*.*(..))" /><!--将事务的处理策略应用到指定的切入点 --><aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut" /></aop:config>

原创粉丝点击