Spring中的事务管理

Spring提供事务管理API:

PlatformTransactionManager 平台事务管理器.

  1. commit(TransactionStatus status)
  2. rollback(TransactionStatus status)
  3. getTransaction(TransactionDefinition definition)

Spring为不同的持久化框架提供了不同PlatformTransactionManager接口实现

  • org.springframework.jdbc.datasource.DataSourceTransactionManager
    使用Spring JDBC或iBatis 进行持久化数据时使用
  • org.springframework.orm.hibernate3.HibernateTransactionManager
    使用Hibernate3.0版本进行持久化数据时使用
  • org.springframework.orm.jpa.JpaTransactionManager 使用JPA进行持久化时使用
  • org.springframework.jdo.JdoTransactionManager 当持久化机制是Jdo时使用
  • org.springframework.transaction.jta.JtaTransactionManager
    使用一个JTA实现来管理事务,在一个事务跨越多个资源时必须使用

TransactionDefinition:事务定义

ISOLation_XXX:事务隔离级别.

ISOLATION_DEFAULT:默认级别.
Mysql repeatable_read oracle read_commited
ISOLATION_READ_UNCOMMITTED
ISOLATION_READ_COMMITTED
ISOLATION_REPEATABLE_READ
ISOLATION_SERIALIZABLE

PROPAGATION_XXX:事务的传播行为.(不是JDBC中有的,为了解决实际开发问题.)

事务的传播行为:(不是JDBC事务管理,用来解决实际开发的问题.)传播行为
解决业务层之间的调用的事务的关系.
1. PROPAGATION_REQUIRED :支持当前事务,如果不存在 就新建一个,A,B 如果A有事务,B使用A的事务,如果A没有事务,B就开启一个新的事务.(A,B是在一个事务中。)
2. PROPAGATION_SUPPORTS :支持当前事务,如果不存在,就不使用事务,A,B 如果A有事务,B使用A的事务,如果A没有事务,B就不使用事务.
PROPAGATION_MANDATORY :支持当前事务,如果不存在,抛出异常,A,B 如果A有事务,B使用A的事务,如果A没有事务,抛出异常.
3. PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务,A,B 如果A有事务,B将A的事务挂起,重新创建一个新的事务.(A,B不在一个事务中.事务互不影响.)
4. PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务,A,B 非事务的方式运行,A有事务,就会挂起当前的事务.
5. PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
6. PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行,基于SavePoint技术,A,B A有事务,A执行之后,将A事务执行之后的内容保存到SavePoint.B事务有异常的话,用户需要自己设置事务提交还是回滚.
常用:(重点)
PROPAGATION_REQUIRED
PROPAGATION_REQUIRES_NEW
PROPAGATION_NESTED

TransactionStatus:事务状态

是否有保存点
是否一个新的事务
事务是否已经提交

关系:PlatformTransactionManager通过TransactionDefinition设置事务相关信息管理事务,管理事务过程中,产生一些事务状态:状态由TransactionStatus记录.

Spring管理事物

手动编码完成事物管理(使用TransactionTemplate)

1.IOC配置dao
如果dao层使用了JdbcDaoSupport,那么可以直接注入dataSource或者jdbcTemplate
2.IOC配置service
dao(service需要调用dao层)
transactionTemplate(service需要使用transactionTemplate来管理实务)
3.IOC配置TransactionManager,根据不同的技术使用不用的类的实现
dataSource
4.IOC配置TransactionTemplate
transactionManager

transactionTemplate.execute(new TransactionCallBackWithoutResult)

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
    /** * 模拟账户1向账户2汇款 * @param money */
    public void out(double money) {

        String sql = "update account set money=money-100 where id =1 ";
        this.getJdbcTemplate().update(sql);
        int a = 1/0;
    }

    /** * 模拟账户2接收账户1的汇款 * @param money */
    public void in(double money) {
        String sql = "update account set money=money+100 where id =2 ";
        this.getJdbcTemplate().update(sql);
    }
}
public class AccountService {
    private AccountDao accountDao;

    private TransactionTemplate transactionTemplate;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

    public void transfer(final double money){
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                accountDao.out(money);
                accountDao.in(money);
            }
        });
    }
}
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/test"></property>
        <property name="username" value="root"></property>
        <property name="password" value="yzgylq"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </bean>

    <bean id="accountDao" class="com.njust.learning.spring.transaction.AccountDaoImpl">
        <property name="dataSource" ref="datasource"></property>
    </bean>

    <bean id="accountService" class="com.njust.learning.spring.transaction.AccountService">
        <property name="accountDao" ref="accountDao"></property>
        <property name="transactionTemplate" ref="transactionTemplate"></property>
    </bean>

    <!--事务管理的配置-->

    <!--因为这里使用的是jdbc的方式进行数据层的操作,所以需要使用DataSourceTransactionManager-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"></property>
    </bean>

    <!--使用自己编码的方式进行事务的处理,这里使用的是事务的处理模板-->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"></property>
    </bean>

缺点

需要在自己的代码里面添加transactionTemplate.execute,对自己的代码造成了入侵
解决:可以使用springaop的动态代理,生成源service的代理对象,在代理对象中进行事务的管理

声明式事物管理原始的方式

使用TransactionProxyFactoryBean对需要事物管理的方法的动态代理
applicationContext.xml
1. dataSource
2. dao
dataSource或者jdbcTemplate
3. service
dao
4. transactionManager
5. TransactionProxyFactoryBean

注意事项:
target即目标对象必须要有,可能eclipse不能提示这个属性
prop的key就是方法名,表示这个方法需要进行事物管理
prop内容的格式:
PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
顺序:传播行为、隔离级别、事务是否只读、发生哪些异常可以回滚事务(所有的
异常都回滚)、发生了哪些异常不回滚.
例如:
+java.lang.ArithmeticException,就表示发生了这个异常还是可以提交事物


public class AccountService {
    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void transfer(final double money){
        accountDao.out(money);
        accountDao.in(money);
    }
}
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/test"></property>
        <property name="username" value="root"></property>
        <property name="password" value="yzgylq"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </bean>

    <bean id="accountDao" class="com.njust.learning.spring.transaction.AccountDaoImpl">
        <property name="dataSource" ref="datasource"></property>
    </bean>

    <bean id="accountService" class="com.njust.learning.spring.transaction.AccountService">
        <property name="accountDao" ref="accountDao"></property>
    </bean>

    <!--基于动态代理的事务管理-->

    <bean id="serviceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager" ref="transactionManager"></property>
        <property name="target" ref="accountService"></property>
        <!--这个就相当于通知Advice-->
        <property name="transactionAttributes">
            <props>
                <prop key="transfer">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"></property>
    </bean>

原始的方式实现事物的管理的缺点:对于每一个service都需要手动配置TransactionProxyFactoryBean很麻烦

使用Aspect实现service的动态代理

tx:advice(用于配置增强,主要用于配置对于不同的方法的事物属性进行配置)
aop:config(用于配置切面,切面就是切点和增强的结合,由于是一个切点和一个切面,所以
使用advisor)

即上面的dao的代码,一模一样
 <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/test"></property>
        <property name="username" value="root"></property>
        <property name="password" value="yzgylq"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </bean>

    <bean id="accountDao" class="com.njust.learning.spring.transaction.AccountDaoImpl">
        <property name="dataSource" ref="datasource"></property>
    </bean>

    <bean id="accountService" class="com.njust.learning.spring.transaction.AccountService">
        <property name="accountDao" ref="accountDao"></property>
    </bean>


    <tx:advice id="transaction_advice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="transfer" isolation="REPEATABLE_READ"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:pointcut id="mypointcut" expression="execution(* com.njust.learning.spring.transaction.AccountService.*(..))"/>
        <aop:advisor advice-ref="transaction_advice" pointcut-ref="mypointcut"></aop:advisor>
    </aop:config>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"/>
     </bean>

你可能感兴趣的:(spring,事务)