前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >spring 学习(五):spring 事务

spring 学习(五):spring 事务

作者头像
希希里之海
发布2018-08-30 15:37:26
3980
发布2018-08-30 15:37:26
举报

spring 学习(五):spring 事务

事务概要

一个数据库事务通常包含了一个序列的对数据库的读/写操作。它的存在包含有以下两个目的:

  • 为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
  • 当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。

所以事务是用来处理异常和并发问题的。

spring 事务管理

spring 的事务管理我们一般采用声明式事务管理这种方式,有两种方式实现:

  • 基于 xml 配置文件实现
  • 基于注解实现

一般使用 PlatformTransactionManager这个事务接口来实现 spring 事务管理。

spring 针对不同的 dao 层框架,提供了接口不同的实现类。

由于现在一般使用 spring JDBC 和 iBatis ,所以我们使用

org.springframework.jdbc.datasource.DataSourceTransactionManager

这个类来实现数据的持久化操作。

spring 实例

我们还是举个栗子来进行 spring 事务操作,以转账操作为例:一人少钱,一人多钱。

1 创建数据库表 account,添加数据,如下图所示:

2 创建 OrdersDao.java 和 OrdersService.java ,实现数据操作:

OrdersDao.java:

package cn.itcast.dao;

import org.springframework.jdbc.core.JdbcTemplate;

public class OrdersDao {
    private JdbcTemplate jdbcTemplate;

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    /*
    做对数据库操作的方法,不写业务操作
     */

    //少钱的方法
    public void lessMoney(){
        String sql = "update account set salary=salary+? where username=?";
        jdbcTemplate.update(sql, -1000, "小王");
    }

    //多钱的方法
    public void moreMoney(){
        String sql = "update account set salary=salary+? where username=?";
        jdbcTemplate.update(sql, 1000, "小马");
    }
}

OrdersService:

package cn.itcast.service;

import cn.itcast.dao.OrdersDao;
import org.springframework.transaction.annotation.Transactional;

// @Transactional 使用注解时的操作
public class OrdersService {

    private OrdersDao ordersDao;

    public void setOrdersDao(OrdersDao ordersDao) {
        this.ordersDao = ordersDao;
    }

    /*
    业务逻辑层,写转账业务
    调用 dao 方法
     */

    public void accountMoney(){
        //小王少1000
        ordersDao.lessMoney();

        int i = 10/0;   //抛出异常操作
        //小马多1000
        ordersDao.moreMoney();
    }
}
  • service 层又叫业务逻辑层
  • dao 层,单纯对数据库操作层,在 dao 层不添加业务

我们在编写程序的时候最好按照这种规范操作。

3 创建 applicationContext.xml 文件,完成注入关系,并添加事务模块,出现异常进行回滚操作,配置文件使用 aop 思想配置:

<?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"
       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/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">

    <!-- 配置c3p0连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!-- 注入属性值 -->
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql:///sampledb"></property>
        <property name="user" value="root"></property>
        <property name="password" value=""></property>
    </bean>

    <!-- 第一步 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 注入 dataSource -->
        <property name="dataSource" ref="dataSource"> </property>
    </bean>
    <!-- 第二步 配置事务增强 -->
    <tx:advice id="txadvice" transaction-manager="transactionManager">
        <!-- 做事务操作 -->
        <tx:attributes>
            <tx:method name="account*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!-- 第三步 配置切面 -->
    <aop:config>
        <!-- 切入点 -->
        <aop:pointcut id="pointcut1" expression="execution(* cn.itcast.service.OrdersService.*(..))"/>
        <!-- 切面 -->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pointcut1"/>
    </aop:config>

    <bean id="ordersService" class="cn.itcast.service.OrdersService">
        <property name="ordersDao" ref="ordersDao"></property>
    </bean>
    <bean id="ordersDao" class="cn.itcast.dao.OrdersDao">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

</beans>

当然我们还可以采用注解的方式进行事务管理,只需修改配置文件:

<?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"
       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/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">

    <!-- 配置c3p0连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!-- 注入属性值 -->
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql:///sampledb"></property>
        <property name="user" value="root"></property>
        <property name="password" value=""></property>
    </bean>

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

    <!-- 第二步 开启事务注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>


    <bean id="ordersService" class="cn.itcast.service.OrdersService">
        <property name="ordersDao" ref="ordersDao"></property>
    </bean>
    <bean id="ordersDao" class="cn.itcast.dao.OrdersDao">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

</beans>

然后在要使用事务的方法所在类上面添加注解 @tTransactional

4 我们编写一个测试类来查看当抛出异常时数据库能不能进行回滚操作。

创建 TestService.java:

package cn.itcast.service;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestService {
    @Test
    public void testDemo(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        OrdersService ordersService = (OrdersService) context.getBean("ordersService");
        ordersService.accountMoney();
    }
}

运行测试文件,可以看到在控制台抛出异常:

是因为我们在 OrdersService.java 的 accountMoney() 方法下加入了下面这行:

int i = 10/0;

这是不允许的。查看我们数据库中的数据,可以看到内容没有变,所以是进行了回滚操作的,不然按业务逻辑会出现一方少1000,而另一方内容不变。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-08-20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • spring 学习(五):spring 事务
    • 事务概要
      • spring 事务管理
        • spring 实例
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档