Spring事务管理方式实现

一、前言

Spring对于事务有下面几种实现方式:

1. 编程式事务

2. 声明式事务

2.1 基于TransactionProxyFactoryBean生成对象的代理类,从而实现事务操作的增强操作

2.2 基于AspectJ的XML配置方式

2.3 基于注解方式


以转账功能来搭建项目环境


二、准备

* Oracle数据库表

create table account (accountNO VARCHAR(32) PRIMARY KEY NOT NULL, money Number(5,2) default 0.00);

插入相关数据:

insert into account(accountNO, money) values('zhangsan', 100.00);
insert into account(accountNO, money) values('lisi', 100.00);
insert into account(accountNO, money) values('wangwu', 100.00);


* 准备项目jar包环境

Oracle数据库驱动包:

ojdbc6.jar

Spring基本包及相应依赖包:

spring-beans-4.0.4.RELEASE.jar

spring-context-4.0.4.RELEASE.jar

spring-expression-4.0.4.RELEASE.jar

commons-logging-1.1.3.jar

spring-core-4.0.4.RELEASE.jar

Spring AOP功能依赖包:

spring-aop-4.0.4.RELEASE.jar -- Spring aop功能包

aopalliance-1.0.jar  -- aop联盟包(aop标准包)

Spring AspectJ支持包:

spring-aspects-4.0.4.RELEASE.jar  -- Spring 针对AspectJ的支持扩展包

aspectjweaver-1.6.11.jar -- AspectJ实现包

Spring jdbc包:

spring-jdbc-4.0.4.RELEASE.jar       --支持jdbc   

Spring事务支持包:  

spring-tx-4.0.4.RELEASE.jar -- Spring事务功能包

Junit测试包:

spring-test-4.0.4.RELEASE.jar -- Spring测试相关包

junit-4.11.jar   -- Junit4包

数据库连接实现包:

commons-dbcp2-2.0.jar -- apache连接池包

commons-pool2-2.2.jar          -- dbcp2依赖包


* 编写转账业务层接口:AccountService

public interface AccountService {

    /**
     * 账户转账操作
     * @param out 转出账户
     * @param in 转入账户
     * @param money 转账金额
     */
    void transfer(String out, String in, double money);

}
* 编写转账DAO层接口: AccountDao

public interface AccountDao {

    /**
      * 账户转入
   * @param in 转入账户
   * @param money 转入金额
   */
    void inMoney(String in, double money);


    /**
      * 账户转出
   * @param out 转出账户
   * @param money 转出金额
   */
    void outMoney(String out, double money);
}


* 配置datasources.properties数据库文件

oracle.driverClassName=oracle.jdbc.driver.OracleDriver
oracle.userName=heng
oracle.password=ping1126
oracle.url=jdbc:oracle:thin:@//127.0.0.1:1521/orcl

* 配置applicationContext.xml文件

<?xml version="1.0" encoding="utf-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
            ">
    <context:property-placeholder location="classpath:datasources.properties" />

    <!-- 数据库连接 -->
    <bean id="datasource" class="org.apache.commons.dbcp2.BasicDataSource">
        <property name="driverClassName" value="${oracle.driverClassName}" />
        <property name="username" value="${oracle.userName}" />
        <property name="password" value="${oracle.password}" />
        <property name="url" value="${oracle.url}" />
    </bean>

    <bean id="accountDao" class="codes.ebo.study.spring.transaction.demo1.AccountDaoImpl">
        <property name="dataSource" ref="datasource" />
    </bean>

    <bean id="accountService" class="codes.ebo.study.spring.transaction.demo1.AccountServiceImpl">
        <property name="accountDao" ref="accountDao" />
    </bean>


</beans>
其中涉及到业务层接口和DAO接口的实现类:

业务层接口实现类: AccountServiceImpl

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

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

    @Override
    public void transfer(String out, String in, double money) {
        accountDao.outMoney(out, money);
        accountDao.inMoney(in, money);
    }

}
DAO层接口实现类: AccountDaoImpl

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

    /**
      * 账户转入
   *
      * @param in    转入账户
   * @param money 转入金额
   */
    @Override
    public void inMoney(String in, double money) {
        this.getJdbcTemplate().update("update account set money = money + ? where accountNO = ?", new Object[] {
                money, in
        }, new int[] {Types.DOUBLE, Types.VARCHAR});
    }

    /**
      * 账户转出
   *
      * @param out   转出账户
   * @param money 转出金额
   */
    @Override
    public void outMoney(String out, double money) {
        this.getJdbcTemplate().update("update account set money = money - ? where accountNO = ?", new Object[] {
                money, out
        }, new int[] {Types.DOUBLE, Types.VARCHAR});
    }
}

三、 Spring事务管理实现

3.1. 编程式事务实现

Spring不直接管理事务,它提供很多可供选择的事务管理器,将事务管理的责任委托给由JTA或相应的持久性机制所提供的某个特定平台事务实现。针对mybatis和JDBC,我们可以使用org.springframework.jdbc.datasource.DataSourceTransactionManager进行管理。

在applicationContext.xml的accountDao的bean定义之上加上transactionManager配置, 修改后改成applicationContext_demo1.xml:

<!-- Spring事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="datasource" />
</bean>

另外, Spring为了方便,使用org.springframework.transaction.support.TransactionTemplate来对事务相关代码进行优化,所以加上TransactionTemplate模板对象配置并加入到业务层实现类AccountServiceImpl上去:

<!-- 编程式事务模板 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
    <property name="transactionManager" ref="transactionManager" />
</bean>

<bean id="userService" class="codes.ebo.study.spring.transaction.demo1.AccountServiceImpl">
    <property name="accountDao" ref="accountDao" />
    <property name="transactionTemplate" ref="transactionTemplate" />
</bean>

业务层实现类AccountServiceImpl代码修改如下:

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    private TransactionTemplate transactionTemplate;

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

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

    @Override
    public void transfer(String out, String in, double money) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                accountDao.outMoney(out, money);
                accountDao.inMoney(in, money);
            }
        });
    }

}
编写相关测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext_demo1.xml"})
public class AccountTest {

    @Resource(name="accountService")
    private AccountService accountService;

    @Test
    public void testTransfer() {
        accountService.transfer("zhangsan", "lisi", 20d);
    }
}


3.2. 声明式事务实现

a. 基于TransactionProxyFactoryBean生成对象的代理类

在准备环境上的applicationContext.xml配置上Spring事务管理器和TransactionProxyFactoryBean, 修改后改成applicationContext_demo2.xml

<!-- Spring事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="datasource" />
</bean>

<bean id="accountDao" class="codes.ebo.study.spring.transaction.demo2.AccountDaoImpl">
    <property name="dataSource" ref="datasource" />
</bean>

<bean id="accountService" class="codes.ebo.study.spring.transaction.demo2.AccountServiceImpl">
    <property name="accountDao" ref="accountDao" />
</bean>

<bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="target" ref="accountService" />
    <property name="proxyInterfaces" value="codes.ebo.study.spring.transaction.demo2.AccountService" />
    <property name="transactionManager" ref="transactionManager" />
    <property name="transactionAttributes">
        <props>
            <prop key="transfer">PROPAGATION_REQUIRED</prop>
        </props>
    </property>
</bean>
相关测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext_demo2.xml"})
public class AccountTest {

    @Resource(name="accountServiceProxy")
    private AccountService accountService;

    @Test
    public void testTransfer() {
        accountService.transfer("zhangsan", "lisi", 20d);
    }
}

b. 基于AspectJ的XML配置方式

在准备环境上的applicationContext.xml配置上事务管理器、事务增强和切面信息, 修改后改成applicationContext_demo3.xml:

<!-- Spring事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="datasource" />
</bean>

<!-- 事务的通知:(事务增强) -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="transfer" propagation="REQUIRED" />
    </tx:attributes>
</tx:advice>

<!-- 配置切面 -->
<aop:config>
    <aop:pointcut id="txPointcut" expression="execution(* codes.ebo.study.spring.transaction.demo3.AccountServiceImpl.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
</aop:config>

c. 基于注解(Transactional)方式

在准备环境上的applicationContext.xml配置上事务管理器、相关事务注解配置,, 修改后改成applicationContext_demo4.xml

<!-- Spring事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="datasource" />
</bean>

<!-- 开启Spring事务注解功能 -->
<tx:annotation-driven transaction-manager="transactionManager" />

同时在业务层实现类AccountServiceImpl类层面或者方法层面上加上Transactional注解信息

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

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

    @Override
    @Transactional(propagation= Propagation.REQUIRED)
    public void transfer(String out, String in, double money) {
        accountDao.outMoney(out, money);
        accountDao.inMoney(in, money);
    }

}


四、总结

1. 2.2 和 2.3 这两种方式在项目中比较常用, 编程式和通过TransactionProxyFactoryBean这两种方式的使用场景比较少

2. 针对事务的属性

a: readOnly: 表示以读方式进行事务操作,当设置为true时但操作又涉及到对表数据进行更新(包含新增和删除),方法调用就会出现异常

b: rollbackFor或者rollback-for, 其值为异常集合,表示执行事务方法的时候出现集合中的异常时,会进行整个事务回滚

c: noRollbackFor或者no-rollback-for,其值为异常集合,表示执行事务方法的时候出现集合中的异常时,不会进行整个事务回滚,可能会造成数据不一致后果

d: timeout事务执行事件,默认为-1,表示无时间限制,配置一定数值单位为秒,超时后事务回滚


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值