Spring中声明式事务xml配置 & 改造成纯注解

1. 本文概述

本文以A给B转账100元为例子 , 使用Spring中声明事务进行设置.
重点在记录配置文件的写法 .

2. 环境搭建
2.1 导包
  • spring基础包 : spring-context
  • jdbc包 : spring-jdbc
  • SpringAOP部分的包 : spring-tx
  • aspectjweaver
  • MySQL数据库驱动包 : mysql-connector-java
  • 单元测试包 : junit
2.2 准备数据库 / 相关类 / 接口 / 方法
2.2.1 准备数据库

要求包含数据 : 用户名称 , 账号金额

idusernamemoney
1A1000
2B1000
2.2.2 准备相关类和接口
  1. 准备表的实体类 Account

  2. 在Service层和Dao层准备接口和实现类

名称类型说明
AccountDao接口Dao层接口
AccountDaoImpl实现类Dao层接口实现类
AccountService接口Service层接口
AccountServiceImpl实现类Service层接口实现类
2.2.3 实现类中的方法说明
  1. Dao层实现类 (AccountDaoImpl) 准备2个方法 :
    * 查询账号信息的方法 : queryByName (Account account)
    * 修改账号信息的方法 : update (Account account)
  2. Service层实现类 (AccountServiceImpl) 准备1个方法 : transfer(String AName , String BName , float money )
    * 转账的完整逻辑 :
    * 查询A/B账号信息 ----- 给A账号减少钱 ----- 给B账号加钱 (不用考虑事务问题)
3. 配置Spring.xml文件
3.1 用bean配置实例业务对象

<bean>配置创建AccountServiceImpl , AccountDaoImpl , JdbcTemplate对象

	<!--创建JdbcTemplate对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!--创建Dao层实现类对象-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate" />
    </bean>

    <!--创建Service层实现类对象-->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao" />
    </bean>

	<!-- 配置数据源 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClass}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
3.2 配置事务
3.2.1 配置事务管理器

谁来执行事务

<bean id="transactionManager" class="org.springframework.jdbc.datasourceManager">
  <property name="datasource" ref="datasource"></property>
</bean>
3.2.2 配置AOP声明式事务

通知事务管理器 需要事务的方法所在位置

<aop:config>
	<!--配置事务通知 -->
	<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.service.impl.*.*(..))" />
</aop:config>
3.2.2 配置事务的规则

一般不会设置里面的属性 , 均采用默认的设置

<!--配置事务规则-->
<tx:advice id="txAdvice" transaction-manager="txtManager">
    <tx:attributes>
        <tx:method name="transfer" rollback-for="java.lang.Exception"/>
    </tx:attributes>
</tx:advice>

rollback-for : 表示发生异常事务回滚
name : 指定参与事务管理的方法 , 即 哪个方法需要事务

复杂版本的配置:

<!--配置事务规则-->
<tx:advice id="txAdvice" transaction-manager="txtManager">
    <tx:attributes>
        <tx:method name="transfer"
                   timeout="300"
                   isolation="DEFAULT"
                   propagation="REQUIRED"
                   rollback-for="java.lang.Exception"/>

        <tx:method name="add*"
                   timeout="40"
                   isolation="DEFAULT"
                   propagation="REQUIRED"
                   rollback-for="java.lang.Exception"/>
                   
        <!--如果方法以save开始,隔离级别为default,该方法必须在事务下执行 -->
        <tx:method name="save*"
                   isolation="DEFAULT"
                   propagation="REQUIRED"/>

        <!--如果方法以get开始,则只能读取数据库数据,不能修改-->
        <tx:method name="get*" read-only="true" />
    </tx:attributes>
</tx:advice>

参数含义 :
no-rollback-for = "java.lang.ArithmeticException"
rollback-for = "java.lang.Exception" : 表示发生异常事务回滚
name : 指定参与事务管理的方法
timeout : 表示当前事务执行,SQL语句响应时间
isolation : 事务隔离级别 , READ_UNCOMMITTED会产生脏读
read-only="true" : 表示只能读取数据库数据 , 没有修改权限(增删改)
propagation : REQUIRED : 表示当前方法必须在事务下执行
timeout : 持有数据库连接的最大时间 , 超过该时间 , 操作数据库的连接会被回收 , 事务回滚

4. 功能测试
    @Test
public void testTransfer(){
    ApplicationContext act = new ClassPathXmlApplicationContext("spring.xml");
    accountService = (AccountService) act.getBean("accountService");
    
    accountService.transfer("A","B",100f);
}
5. 纯注解改造
5.1 改造bean配置的实例业务对象

以Service层的实例对象做例子 :

@Service(value = "accountService")
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;
    ------略写后面内容-------
}
5.2 指出要使用事务的类 / 方法

@Transactional写在类或者方法上

@Transactional
@Service(value = "accountService")
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;

   	//转账方法
    @Transactional(readOnly = true)
    @Override
    public void transfer(String targetName, String sourceName, Float money) {
        Account targetAccount = accountDao.getByName(targetName);
        Account sourceAccount = accountDao.getByName(sourceName);
        targetAccount.setMoney(targetAccount.getMoney()-money);
        sourceAccount.setMoney(sourceAccount.getMoney()+money);
        int count = accountDao.update(targetAccount);
        System.out.println("受影响行数:"+count);
        accountDao.update(sourceAccount);
    }
}

该注解里可以设置参数 , 不过一般不会设置
@Transactional (
propagation= Propagation.REQUIRED, //当前方法必须在事务下执行
isolation = Isolation.DEFAULT, //事务的隔离级别
timeout = -1 //超时配置
)`

5.3 将剩下的配置放入配置类SpringConfig.java
@Configuration  //将该类指认为配置类
@ComponentScan(basePackages = "com.itheima") //设置注解扫描范围
@EnableTransactionManagement  //开启注解事务
public class SpringConfig {

	//创建事务管理器
    @Bean
    public DataSourceTransactionManager transactionManager(DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }

	//创建数据源对象
    @Bean
    public DataSource dataSource(){
        try {
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setDriverClass("com.mysql.jdbc.Driver");
            dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/spring5");
            dataSource.setUser("root");
            dataSource.setPassword("itcast");

            return dataSource;
        } catch (PropertyVetoException e) {
            throw new RuntimeException(e);
        }
    }

	//创建JdbcTemplate
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource){
        return new JdbcTemplate(dataSource);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值