美文网首页spring
十、Spring事务编程

十、Spring事务编程

作者: I墨雨 | 来源:发表于2019-01-10 14:51 被阅读2次

环境搭建

  • 创建表
create table account(
    id int primary key auto_increment,
    name varchar(20),
    money double
);
  • 创建jdbc.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring
jdbc.username=root
jdbc.password=123456
  • 创建核心配置文件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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!--加载属性文件,context方式-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!--配置druid连接池,表达式获取属性文件参数-->
    <bean id="druid" class="com.alibaba.druid.pool.DruidDataSource">
        <!--key值不能和name一样,加前缀jdbc.-->
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <!--注入JdbcTemplate模板-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="druid"/>
    </bean>

</beans>
  • 创建测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest {
    @Resource(name = "jdbcTemplate")
    private JdbcTemplate jdbcTemplate;

    @Test
    public void test() {
        jdbcTemplate.update("insert into account value(null,?,?)", "ls", 10000d);
    }
}

如果能插入一条数据,则证明我们已经搭建好环境了!(要注意数据库名有没有写错!)

事务准备

  • 业务方法接口
package com.itlike.dao;

public interface AccountDao {
    //加钱:给谁?多少钱?
    public void addMoney(String name,Double money);
    //减钱:减谁?多少钱?
    public void minusMoney(String name,Double money);
}
  • 实现业务接口,编程业务逻辑
//继承JdbcDaoSupport
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
    @Override
    public void addMoney(String name, Double money) {
        this.getJdbcTemplate().update("update account set money=money+? where name=?",money,name);
    }

    @Override
    public void minusMoney(String name, Double money) {
        this.getJdbcTemplate().update("update account set money=money-? where name=?",money,name);
    }
}
  • Spring管理实现类AccountDaoImpl
<!--Spirng管理实现类-->
<bean id="accountDao" class="com.itlike.dao.AccountDaoImpl">
    <property name="dataSource" ref="druid"/>
</bean>

业务需求

  • 业务需求接口
public interface AccountService {
    // 转钱,谁给谁转?转多少?
    public void transferMoney(String from, String to, Double money);
}
  • 实现方法
public class AccountServiceImpl implements AccountService {
    //使用xml方式注入
    private AccountDao accountDao;
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
    //转账方法
    @Override
    public void transferMoney(String from, String to, Double money) {
        this.accountDao.minusMoney(from,money);
        this.accountDao.addMoney(to,money);
    }
}
  • applicationContext.xml
<bean id="accountService" class="com.itlike.service.AccountServiceImpl">
    <property name="accountDao" ref="accountDao"/>
</bean>

测试方法

现有两条记录:


Image 1.png
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest {
    @Resource(name = "accountService")
    private AccountService accountService;

    @Test
    public void test() {
        accountService.transferMoney("zs","ls",50d);
    }
}

转账成功!


Image 3.png

事务问题

  • 重置数据库记录为100
  • 在转账方法中添加除0异常,模拟断电情况
public void transferMoney(String from, String to, Double money) {
    this.accountDao.minusMoney(from,money);
    int i = 1/0;    //发生异常
    this.accountDao.addMoney(to,money);
}
  • 再次运行测试方法,会得到如下结果:
1.PNG

会发现,za账户的钱已经减少,但ls账户的钱却没有增加,这是为什么呢?
这就是没有添加事务机制所造成的情况,zs账户钱已经减少了,但ls账户的钱还来不及增加,系统就因为发生了异常而停止运行了!
为此,我们可以添加事务机制,让发生异常时,保证业务安全。

编程式事务

需要手动编写代码

  • 配置平台事务管理器
<!--配置事务管理器-->
  <bean id="transactionManager" 
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
  </bean>
  • Spring提供了事务管理的模板类

简化事务操作的模板

<bean id="transactionTemplate"
      class="org.springframework.transaction.support.TransactionTemplate">
    <property name="transactionManager" ref="transactionManager"/>
</bean>
  • 在业务层添加事务管理的模板
//添加事务模板
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
    this.transactionTemplate = transactionTemplate;
}

//转账方法
@Override
public void transferMoney(String from, String to, Double money) {
    this.accountDao.minusMoney(from,money);
    int i = 1/0;    //发生异常
    this.accountDao.addMoney(to,money);
}
  • 配置文件注入accountService
<bean id="accountService" class="com.itlike.service.AccountServiceImpl">
    <property name="accountDao" ref="accountDao"/>
    <!-- ref映射事务管理模板transactionTemplate -->
    <property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
  • 修改转账方法

事务配置中有回调方法

@Override
public void transferMoney(String from, String to, Double money) {
    //这是回调方法(匿名内部类)
    this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
            //在这里添加业务代码
        }
    });

}
  • 修改后的转账方法
//转账方法
@Override
public void transferMoney(String from, String to, Double money) {
    this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
            //匿名内部类中不能使用this
            accountDao.minusMoney(from,money);
            int i = 1/0;    //发生异常
            accountDao.addMoney(to,money);
        }
    });
}
  • 再次运行测试方法,如果在发生异常后,表记录不被修改,则证明事务设置成功!
1.PNG

声明式事务XML方式声明事务管理

把代码重置到使用编程式事务之前。

  • 引入Aop的开发包
  • 配置事务管理器
<!--配置事务管理器-->
<bean id="transactionManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="druid"/>
</bean>
  • AOP增强事务功能

若tx报红,有两个原因:jar包没导入名称空间

<!--AOP增强事务配置-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>
  • 织入增强方法
<!--把AOP增强添加到方法里-->
<aop:config>
    <!--第一个*是任意返回值,第二个*是指给该类里所有方法都织入Aop方法,..代表任意参数-->
    <aop:pointcut id="pointcut" expression="execution(* com.itlike.service.AccountServiceImpl.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>

运行测试方法,可以看到,当发生除0异常时,表记录不会发生改变!

声明式事务注解方式声明事务管理

把代码重置到使用编程式事务之前。

  • 配置事务管理器
<!--配置事务管理器-->
<bean id="transactionManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="druid"/>
</bean>
  • 开启注解事务
<!--开启注解事务-->
<tx:annotation-driven transaction-manager="transactionManager"/>
  • 在转账方法上添加@Transactional注解
@Transactional
//@Transactional(isolation= ,propagation= ) 设置隔离级别、传播行为 
public class AccountServiceImpl implements AccountService {
    //使用xml方式注入
    private AccountDao accountDao;
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    //转账方法
    @Override
    public void transferMoney(String from, String to, Double money) {

        this.accountDao.minusMoney(from,money);
        //int i = 1/0;    //发生异常
        this.accountDao.addMoney(to,money);

    }
}

运行测试方法,可以看到,当发生除0异常时,表记录不会发生改变!

相关文章

  • Spring事务

    Spring 事务 分类 Spring可以支持编程式事务和声明式事务。 编程式事务 实现 Spring使用事务管理...

  • 分布式事务(2)Spring事务

    2.1 Spring事务原理 Spring支持编程式事务和声明式事务。编程式事务就是用个事务类Transactio...

  • Spring事务总结

    1. 编程式事务和声明式事务 spring支持编程式事务管理和声明式事务管理两种方式。 编程式事务Spring推荐...

  • spring事务(一) 编程式事务

    spring事务(一) 编程式事务 知识导读 本地事务(autocommit=false)-----编程式事务--...

  • 十、Spring事务编程

    环境搭建 创建表 创建jdbc.properties 创建核心配置文件applicationContext.xml...

  • 116、【JavaEE】【Spring】Spring 事务

    1、Spring 事务控制方式 Spring 的事务控制可以分为编程式事务控制和声明式事务控制。 编程式,即编写有...

  • Spring 事务

    Spring可以支持编程式事务和声明式事务。 编程式事务 实现 Spring使用事务管理器,每个不同平台的事务管理...

  • Spring-事务机制

    一、Spring事务 事务管理概述 Spring事务管理分为编程式事务管理和声明式事务管理两种 编程式事务:允许用...

  • Spring事务的种类

    Spring事务的种类: spring支持编程式事务管理和声明式事务管理两种方式: ①编程式事务管理使用Trans...

  • Spring声明式事务管理之一:五大属性分析

    1.Spring事务管理概述 Spring事务管理分为编程式事务管理和声明式事务管理两种。编程式事务允许用户在实现...

网友评论

    本文标题:十、Spring事务编程

    本文链接:https://www.haomeiwen.com/subject/nrnnrqtx.html