学习笔记——Spring(6)事务

我们通过一个实际的例子来了解Spring的事物管理。

场景:要记录某个人的总支出和所剩余额的信息,总支出增加多少,余额就会相应的减少多少。假设初始时余额为1000,总支出为0。对此在数据库中建立:总支出表—pay,包含字段【id(主键)、money(总支出)】;余额表—balance,包含字段【id(主键)、money(余额)】。正常情况下pay.money增加n时balance.money减少n。

建表:

CREATE TABLE `balance` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `money` double(6,2) NOT NULL,
  PRIMARY KEY (`id`)
);

CREATE TABLE `pay` (
  `id` int(10) NOT NULL,
  `money` double(6,2) NOT NULL,
  PRIMARY KEY (`id`)
);

INSERT into pay(id,money) VALUES(1,0);
INSERT into balance(id,money) VALUES(1,1000);

 接下来在spring项目中进行文件配置和测试类的创建,来模拟场景。

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:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--配置注解扫描包-->
    <context:component-scan base-package="controller"></context:component-scan>

    <!--引入jdbc配置文件-->
    <context:property-placeholder location="jdbc.properties"></context:property-placeholder>
    <!--配置数据库连接-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driverClassName}"></property>
        <property name="jdbcUrl" value="${jdbc.url}"></property>
        <property name="user" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    <!--配置jdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
</beans>

测试类:

package controller;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class TestController {

    /**
     * 测试方法
     * @param jdbcTemplate
     */
    public void test(JdbcTemplate jdbcTemplate) {
//        pay.money增加100
        jdbcTemplate.update("UPDATE pay SET money=money+100 WHERE id=1");

//        balance.money减少100
        jdbcTemplate.update("UPDATE balance SET money=money-100 WHERE id=1");
    }
}

主函数类:

package controller;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;

public class Main {

    public static void main(String[] args){
//        读取配置文件
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-bean.xml");
        TestController testController = (TestController)ctx.getBean("testController");
        JdbcTemplate jdbcTemplate = (JdbcTemplate)ctx.getBean("jdbcTemplate");

        testController.test(jdbcTemplate);
    }
}

 

 运行程序发现,每次运行后pay.money增加100,balance.money减少100。

现在,假设在pay.money增加100和balance.money减少100这两次数据库操作中间,由于某些原因出现了异常,将会导致什么结果呢?

针对这种情况,我们调整测试类如下:使两次数据库操作中间出现运行时异常

package controller;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class TestController {

    /**
     * 测试方法
     * @param jdbcTemplate
     */
    public void test(JdbcTemplate jdbcTemplate) {
//        pay.money增加100
        jdbcTemplate.update("UPDATE pay SET money=money+100 WHERE id=1");
//       两次数据库操作中间出现运行时异常
        int x = 5/0;

//        balance.money减少100
        jdbcTemplate.update("UPDATE balance SET money=money-100 WHERE id=1");
    }
}

运行程序发现,pay.money增加100成功,但是由于程序出现异常导致balance.money减少100的操作没有执行到。这在实际情况中意味着,没有从余额中取钱,就完成了支出操作,这显然是不符合实际情况的。实际情况应该是想要完成支出必须要从余额中取出钱,对应带到程序中为:pay.money增加100如果成功,balance.money也必须减少100。如果由于某些原因导致balance.money没有减少,那么pay.money也不能增加。这时,Spring的事物管理就起到作用了。

 使用Spring事物管理步骤:

1、配置事务管理器
2、配置启动事务
3、在事物方法上或类上加@Transactional注解,并设置合适的属性信息

接下来,我们按步骤进行配置:

 xml文件中增加:配置事务管理器、配置启动事务:

<!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!--开启事务-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

测试方法上增加注解:@Transactional

 配置完成后,运行程序,目的达到!!

注意事项

注意:
1、在添加了@Transactional注解的方法内部不能使用try{}catch{}。
因为@Transactional注解实际上就是一个拦截器,当@Transactional代理具体方法并执行,
你在方法体内部使用了try{}catch{},是拿不到异常信息的,拿不到异常自然就无法回滚了
2、只有@Transactional 注解应用到 public 方法,才有效,才能进行事务管理
3、@Transactional 注解也可以添加到类级别上。当把@Transactional 注解放在类级别时,
表示所有该类的公共方法(public修饰的方法)都配置相同的事务属性信息。
当类级别配置了@Transactional,方法级别也配置了@Transactional,
应用程序会以方法级别的事务属性信息来管理事务,换言之,方法级别的事务属性信息会覆盖类级别的相关配置信息。

@Transactional 注解的属性信息: 

属性名说明
name当在配置文件中有多个 TransactionManager , 可以用该属性指定选择哪个事务管理器。
propagation事务的传播行为,默认值为 REQUIRED。
isolation事务的隔离度(隔离级别),默认值采用 DEFAULT。
timeout事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
read-only指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。只读事务不存在数据的修改,因此数据库将会为只读事务提供一些优化手段,例如Oracle对于只读事务,不启动回滚段,不记录回滚log。
rollback-for用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔。
no-rollback- for抛出 no-rollback-for 指定的异常类型,不回滚事务。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值