Spring事务(Transaction)

Spring事务(Transaction)

事务(Transaction)是面向关系型数据库(RDBMS)企业应用程序的重要组成部分,用来确保数据的完整性和一致性。

事务具有以下 4 个特性,即原子性、一致性、隔离性和持久性,这 4 个属性称为 ACID 特性。

  • 原子性(Atomicity):一个事务是一个不可分割的工作单位,事务中包括的动作要么都做要么都不做。
  • 一致性(Consistency):事务必须保证数据库从一个一致性状态变到另一个一致性状态,一致性和原子性是密切相关的。
  • 隔离性(Isolation):一个事务的执行不能被其它事务干扰,即一个事务内部的操作及使用的数据对并发的其它事务是隔离的,并发执行的各个事务之间不能互相打扰。
  • 持久性(Durability):持久性也称为永久性,指一个事务一旦提交,它对数据库中数据的改变就是永久性的,后面的其它操作和故障都不应该对其有任何影响。

编程式和声明式

Spring 的事务管理有 2 种方式:

  1. 传统的编程式事务管理,即通过编写代码实现的事务管理;
  2. 基于 AOP 技术实现的声明式事务管理。
1. 编程式事务管理

编程式事务管理是通过编写代码实现的事务管理,灵活性高,但难以维护。

2. 声明式事务管理

Spring 声明式事务管理在底层采用了 AOP 技术,其最大的优点在于无须通过编程的方式管理事务,只需要在配置文件中进行相关的规则声明,就可以将事务规则应用到业务逻辑中。

Spring 实现声明式事务管理主要有 2 种方式:

  • 基于 XML 方式的声明式事务管理。
  • 通过 Annotation 注解方式的事务管理。

显然声明式事务管理要优于编程式事务管理。

以下是隔离级别的值。

方法说明
ISOLATION_DEFAULT使用后端数据库默认的隔离级别
ISOLATION_READ_UNCOMMITTED允许读取尚未提交的更改,可能导致脏读、幻读和不可重复读
ISOLATION_READ_COMMITTED(Oracle 默认级别)允许读取已提交的并发事务,防止脏读,可能出现幻读和不可重复读
ISOLATION_REPEATABLE_READ(MySQL 默认级别),多次读取相同字段的结果是一致的,防止脏读和不可重复读,可能出现幻读
ISOLATION_SERIALIZABLE完全服从 ACID 的隔离级别,防止脏读、不可重复读和幻读

以下是传播行为的可能值,传播行为用来控制是否需要创建事务以及如何创建事务。

名称说明
PROPAGATION_MANDATORY支持当前事务,如果不存在当前事务,则引发异常
PROPAGATION_NESTED如果当前事务存在,则在嵌套事务中执行
PROPAGATION_NEVER不支持当前事务,如果当前事务存在,则引发异常
PROPAGATION_NOT_SUPPORTED不支持当前事务,始终以非事务方式执行
PROPAGATION_REQUIRED默认传播行为,支持当前事务,如果不存在,则创建一个新的
PROPAGATION_REQUIRES_NEW创建新事务,如果已经存在事务则暂停当前事务
PROPAGATION_SUPPORTS支持当前事务,如果不存在事务,则以非事务方式执行

Spring 声明式事务管理是通过 AOP 实现的,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

声明式事务最大的优点就是不需要通过编程的方式管理事务,可以将业务逻辑代码和事务管理代码很好的分开。

Spring 实现声明式事务管理主要有 2 种方式:

  • 基于 XML 方式的声明式事务管理。
  • 通过 Annotation 注解方式的事务管理。

Spring基于注解实现事务管理

在 Spring 中,声明式事务除了可以使用 XML 实现外,还可以使用 Annotation 注解。使用注解实现可以减少代码之间的耦合度。

使用 Annotation 的方式非常简单,只需要在项目中做两件事,具体如下。

1)在 Spring 容器中注册驱动,代码如下所示:
<tx:annotation-driven transaction-manager="txManager"/>
2)在需要使用事务的业务类或者方法中添加注解 @Transactional,并配置 @Transactional 的参数。

常用属性说明如下:

  • propagation:设置事务的传播行为;
  • isolation:设置事务的隔离级别;
  • readOnly:设置是读写事务还是只读事务;
  • timeout:事务超时事件(单位:s)。
实例

beans7.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:http="http://www.springframework.org/schema/c"
       xmlns:context="http://www.springframework.org/schema/context" 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
          https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--通过context:property-placeholder location="druid.properties"引入德鲁伊数据源-->
    <context:component-scan base-package="com.syf"></context:component-scan>
    <context:property-placeholder location="druid.properties"></context:property-placeholder>
    <!--通过property 配置数据源连接池  使用${xxxx}填写属性-->
    <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
        <property name="driverClassName" value="${driver}"></property>
        <property name="url" value="${url}"></property>
        <property name="username" value="${user}"></property>
        <property name="password" value="${password}"></property>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <bean id="transactionManager" class="org.springframework.jdbc.support.JdbcTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"></tx:annotation-driven>

</beans>

BookInfo.java

package com.syf.bean;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class BookInfo {
    private Integer bookid;
    private String bookname;
    private Integer booknum;
    private Integer bookprice;
    private String bookauthor;
    private String bookpublish;
    private Integer typeid;

    public BookInfo(String bookname, Integer booknum, Integer bookprice, String bookauthor, String bookpublish, Integer typeid) {
        this.bookname = bookname;
        this.booknum = booknum;
        this.bookprice = bookprice;
        this.bookauthor = bookauthor;
        this.bookpublish = bookpublish;
        this.typeid = typeid;
    }

    public BookInfo(Integer bookid, String bookname, Integer booknum, Integer bookprice) {
        this.bookid = bookid;
        this.bookname = bookname;
        this.booknum = booknum;
        this.bookprice = bookprice;
    }
}

BookInfoDao接口 和实现类

package com.syf.dao;

import com.syf.bean.BookInfo;
public interface BookInfoDao {
    public int save(BookInfo bookInfo);
    public int save2(BookInfo bookInfo);
}

package com.syf.dao.impl;

import com.syf.bean.BookInfo;
import com.syf.dao.BookInfoDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class BookInfoDaoImpl implements BookInfoDao {
    @Autowired
    private JdbcTemplate jdbcTemplate ;
    @Override
    public int save(BookInfo bookInfo) {
        return jdbcTemplate.update("INSERT into bookinfo VALUES(null,?,?,?,?,?,?)",bookInfo.getBookname(),bookInfo.getBooknum(),bookInfo.getBookprice(),
                bookInfo.getBookauthor(),bookInfo.getBookpublish(),bookInfo.getTypeid());
    }

    @Override
    public int save2(BookInfo bookInfo) {
        return jdbcTemplate.update("INSERT into bookinfo VALUES(?,?,?,?,?,?,?)",bookInfo.getBookid(),bookInfo.getBookname(),bookInfo.getBooknum(),bookInfo.getBookprice(),
                bookInfo.getBookauthor(),bookInfo.getBookpublish(),bookInfo.getTypeid());
    }
}

BookInfoService及其实现类

package com.syf.service;

import org.springframework.stereotype.Service;

@Service
public interface BookInfoService {
    public void testsw();
}

package com.syf.service.impl;

import com.syf.bean.BookInfo;
import com.syf.dao.BookInfoDao;
import com.syf.dao.impl.BookInfoDaoImpl;
import com.syf.service.BookInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional//开启事务
public class BookInfoServiceImpl implements BookInfoService {
    @Autowired
   private BookInfoDao bookInfoDao;
    @Override
    public void testsw() {
        BookInfo bookInfo=new BookInfo("遮天",10,1000,"红毛","2015-09-01",2);
        bookInfoDao.save(bookInfo);
        BookInfo bookInfo1=new BookInfo("遮天",10,1000,"红毛","2015-09-01",2);
        bookInfo1.setBookid(100);
        bookInfoDao.save2(bookInfo1);
    }
}

测试

@org.junit.Test
    public void test(){
        ApplicationContext context=new ClassPathXmlApplicationContext("beans7.xml");
        BookInfoServiceImpl bookInfoService = context.getBean(BookInfoServiceImpl.class);
        bookInfoService.testsw();
    }

save()和save2()方法有一个失败都失败,两个都成功才成功

Spring基于XML实现事务管理

实例

在上面Spring基于注解实现事务管理实例基础上更改

bean8.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:http="http://www.springframework.org/schema/c"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context
          https://www.springframework.org/schema/context/spring-context.xsd 
          http://www.springframework.org/schema/tx 
          http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--通过context:property-placeholder location="druid.properties"引入德鲁伊数据源-->
    <context:component-scan base-package="com.syf"></context:component-scan>
    <context:property-placeholder location="druid.properties"></context:property-placeholder>
    <!--通过property 配置数据源连接池  使用${xxxx}填写属性-->
    <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
        <property name="driverClassName" value="${driver}"></property>
        <property name="url" value="${url}"></property>
        <property name="username" value="${user}"></property>
        <property name="password" value="${password}"></property>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <bean id="transactionManager" class="org.springframework.jdbc.support.JdbcTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
<!--    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>-->
    <tx:advice id="txAdrvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
    </tx:advice>
    <aop:config proxy-target-class="true">
        <aop:pointcut id="point" expression="execution(*
com.syf.service.*.*(..))"/>
        <aop:advisor advice-ref="txAdrvice" pointcut-ref="point"></aop:advisor>
    </aop:config>

</beans>
package com.syf.service.impl;

import com.syf.bean.BookInfo;
import com.syf.dao.BookInfoDao;
import com.syf.service.BookInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
//@Transactional//开启事务  去掉
public class BookInfoServiceImpl2 implements BookInfoService {
    @Autowired
   private BookInfoDao bookInfoDao;
    @Override
    public void testsw() {
        BookInfo bookInfo=new BookInfo("遮天",10,1000,"红毛","2015-09-01",2);
        bookInfoDao.save(bookInfo);
        BookInfo bookInfo1=new BookInfo("遮天",10,1000,"红毛","2015-09-01",2);
        bookInfo1.setBookid(101);
        bookInfoDao.save2(bookInfo1);
    }
}
@org.junit.Test
public void test1(){
    ApplicationContext context=new ClassPathXmlApplicationContext("beans8.xml");
    BookInfoServiceImpl2 bookInfoService = context.getBean(BookInfoServiceImpl2.class);
    bookInfoService.testsw();
}

save()和save2()方法有一个失败都失败,两个都成功才成功.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值