Spring事务

1)定义

事务是指多个操作单元组成的集合,多个操作单元是整体不可分割的,要么都成功,要么都不成功。必须遵守四个原则(ACID)

●原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做;

●一致性(Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是应该处于正确的状态,即数据完整性约束没有被破坏;如银行转帐,A转帐给B,必须保证A的钱一定转给B,一定不会出现A的钱转了但B没收到,否则数据库的数据就处于不一致(不正确)的状态。

●隔离性(Isolation):并发事务执行之间互不影响,在一个事务内部的操作对其他事务是不产生影响,这需要事务隔离级别来指定隔离性;

●持久性(Durability):事务一旦执行成功,它对数据库的数据的改变必须是永久的,不会因比如遇到系统故障或断电造成数据不一致或丢失。

2)Spring事务隔离级别

spring有五大隔离级别,其在TransactionDefinition接口中定义。看源码可知,其默isolation_default(底层数据库默认级别),其他四个隔离级别跟数据库隔离级别一致。

●ISOLATION_DEFAULT:用底层数据库的默认隔离级别,数据库管理员设置什么就是什么

●ISOLATION_READ_UNCOMMITTED(未提交读):最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读)

●ISOLATION_READ_COMMITTED(提交读):一个事务提交后才能被其他事务读取到(该隔离级别禁止其他事务读取到未提交事务的数据、所以还是会造成幻读、不可重复读)、sql server默认级别

●ISOLATION_REPEATABLE_READ(可重复读):可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(该隔离基本可防止脏读,不可重复读(重点在修改),但会出现幻读(重点在增加与删除))(MySql默认级别,更改可通过set transaction isolation level 级别)

●ISOLATION_SERIALIZABLE(序列化):代价最高最可靠的隔离级别(该隔离级别能防止脏读、不可重复读、幻读)

丢失更新:两个事务同时更新一行数据,最后一个事务的更新会覆盖掉第一个事务的更新,从而导致第一个事务更新的数据丢失,这是由于没有加锁造成的;

幻读:同样的事务操作过程中,不同时间段多次(不同事务)读取同一数据,读取到的内容不一致(一般是行数变多或变少)。

脏读:一个事务读取到另外一个未提及事务的内容,即为脏读。

不可重复读:同一事务中,多次读取内容不一致(一般行数不变,而内容变了)。

幻读与不可重复读的区别:幻读的重点在于插入与删除,即第二次查询会发现比第一次查询数据变少或者变多了,以至于给人一种幻象一样,而不可重复读重点在于修改,即第二次查询会发现查询结果比第一次查询结果不一致,即第一次结果已经不可重现了。

数据库隔离级别越高,执行代价越高,并发执行能力越差,因此在实际项目开发使用时要综合考虑,为了考虑并发性能一般使用提交读隔离级别,它能避免丢失更新和脏读,尽管不可重复读和幻读不能避免,但可以在可能出现的场合使用悲观锁或乐观锁来解决这些问题。

3)Spring事务管理

(1)编程式事务管理

Spring 提供的事务模版类:org.springframework.transaction.support.TransactionTemplate

事务管理器:org.springframework.jdbc.datasource.DataSourceTransactionManager

<?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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <context:property-placeholder location="jdbc.properties"/>
<!-- 数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<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="dataSource"></property>
</bean>
<!-- jdbc 事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- TransactionTemplate -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"></property>
</bean> <!-- dao -->
<bean id="userDao" class="top.ruandb.dao.impl.UserDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<bean id="userService" class="top.ruandb.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
<property name="transactionTemplate" ref="transactionTemplate"></property>
</bean> </beans>
public class UserServiceImpl implements UserServiceI {
private TransactionTemplate transactionTemplate;
private UserDaoI userDao;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public void setUserDao(UserDaoI userDao) {
this.userDao = userDao;
}
//addUser()和updateUser()在同一个事务中
@Override
public void addUser() {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
userDao.addUser();
userDao.updateUser();
}
});
}
}

(2)声明式事务管理

使用 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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <context:property-placeholder location="jdbc.properties"/>
<!-- 数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<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="dataSource"></property>
</bean>
<!-- jdbc 事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="edit*" propagation="REQUIRED" />
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="new*" propagation="REQUIRED" />
<tx:method name="set*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="change*" propagation="REQUIRED" />
<tx:method name="get*" propagation="REQUIRED" read-only="true" />
<tx:method name="find*" propagation="REQUIRED" read-only="true" />
<tx:method name="load*" propagation="REQUIRED" read-only="true" />
<tx:method name="*" propagation="REQUIRED" read-only="true" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* top.ruandb.service.*.*(..))" id="serviceMethod"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"/>
</aop:config> <!-- dao -->
<bean id="userDao" class="top.ruandb.dao.impl.UserDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<bean id="userService" class="top.ruandb.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean> </beans>
使用注解配置声明式事务( @Transactional); <?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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <context:property-placeholder location="jdbc.properties"/>
<!-- 数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<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="dataSource"></property>
</bean>
<!-- jdbc 事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 注解声明式事务,织入事务管理器 -->
<tx:annotation-driven transaction-manager="transactionManager"/> <!-- dao -->
<bean id="userDao" class="top.ruandb.dao.impl.UserDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<bean id="userService" class="top.ruandb.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean> </beans>
@Transactional
public class UserServiceImpl implements UserServiceI {
private UserDaoI userDao;
public void setUserDao(UserDaoI userDao) {
this.userDao = userDao;
}
@Override
public void addUser() {
userDao.addUser();
userDao.updateUser();
}
}

4)事务的传播行为

事务传播行为:Spring 中,当一个 service 方法调用另外一个 service 方法的时候,因为每个 service 方法都有事

务,这时候就出现了事务的嵌套;由此,就产生了事务传播行为;

在 Spring 中,通过配置 Propagation,来定义事务传播行为;

PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。

Spring总结之事务的更多相关文章

  1. spring声明式事务管理总结

    事务配置 首先在/WEB-INF/applicationContext.xml添加以下内容: <!-- 配置事务管理器 --> <bean id="transactionM ...

  2. spring 声明式事务管理

    简单理解事务: 比如你去ATM机取5000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉5000元钱:然后ATM出5000元钱.这两个步骤必须是要么都执行要么都不执行.如果银行卡扣除了5000块但 ...

  3. Spring声明式事务管理基于@Transactional注解

    概述:我们已知道Spring声明式事务管理有两种常用的方式,一种是基于tx/aop命名空间的xml配置文件,另一种则是基于@Transactional 注解.         第一种方式我已在上文为大 ...

  4. Spring声明式事务管理基于tx/aop命名空间

    目的:通过Spring AOP 实现Spring声明式事务管理; Spring支持编程式事务管理和声明式事务管理两种方式. 而声明式事务管理也有两种常用的方式,一种是基于tx/aop命名空间的xml配 ...

  5. Spring学习8-Spring事务管理(编程式事务管理)

    一.Spring事务的相关知识   1.事务是指一系列独立的操作,但在概念上具有原子性. 比如转账:A账号-100, B账号+100,完成.这两个操作独立是没问题的. 但在逻辑上,要么全部完成,要么一 ...

  6. Spring声明式事务配置管理方法

    环境配置 项目使用SSH架构,现在要添加Spring事务管理功能,针对当前环境,只需要添加Spring 2.0 AOP类库即可.添加方法: 点击项目右键->Build Path->Add ...

  7. 161117、使用spring声明式事务抛出 identifier of an instance of

    今天项目组有成员使用spring声明式事务出现下面异常,这里跟大家分享学习下. 异常信息: org.springframework.orm.hibernate3.HibernateSystemExce ...

  8. Spring声明式事务管理与配置详解

    转载:http://www.cnblogs.com/hellojava/archive/2012/11/21/2780694.html 1.Spring声明式事务配置的五种方式 前段时间对Spring ...

  9. Spring对Hibernate事务管理

    谈Spring事务管理之前我们想一下在我们不用Spring的时候,在Hibernate中我们是怎么进行数据操作的.在Hibernate中 我们每次进行一个操作的的时候我们都是要先开启事务,然后进行数据 ...

  10. spring 编程式事务管理和声明式事务管理

    编程式事务管理 Spring 的编程式事务管理概述 在 Spring 出现以前,编程式事务管理对基于 POJO 的应用来说是唯一选择.用过 Hibernate 的人都知道,我们需要在代码中显式调用be ...

随机推荐

  1. 旷视MegEngine核心技术升级

    旷视MegEngine核心技术升级 7 月 11 日,旷视研究院在 2020 WAIC · 开发者日「深度学习框架与技术生态论坛」上围绕 6 月底发布的天元深度学习框架(MegEngine)Beta ...

  2. JVM--你常见的jvm 异常有哪些? 代码演示:StackOverflowError , utOfMemoryError: Java heap space , OutOfMemoryError: GC overhead limit exceeded, Direct buffer memory, Unable_to_create_new_native_Thread, Metaspace

    直接上代码: public class Test001 { public static void main(String[] args) { //java.lang.StackOverflowErro ...

  3. 狂神说redis笔记(三)

    八.Redis.conf 容量单位不区分大小写,G和GB有区别 可以使用 include 组合多个配置问题 网络配置 日志 # 日志 # Specify the server verbosity le ...

  4. MySQL必知必会复习笔记(1)

    MySQL必知必会笔记(一) MySQL必知必会是一本很优秀的MySQL教程书,并且相当精简,在日常中甚至能当成一本工作手册来查看.本系列笔记记录的是:1.自己记得不够牢的代码:2.自己觉得很重要的代 ...

  5. Java线程池底层源码分享和相关面试题(持续更新)

    线程池各个参数讲解 public ThreadPoolExecutor(int corePoolSize, //线程池核心工作线程数量,比如newFixedThreadPool中可以自定义的线程数量就 ...

  6. UNREFERENCED_PARAMETER的用处

    UNREFERENCED_PARAMETER的用处 作用:告诉编译器,已经使用了该变量,不必检测警告! 在VC编译器下,如果您用最高级别进行编译,编译器就会很苛刻地指出您的非常细小的警告.当你生命了一 ...

  7. 大数据初级sy

    1.spark 是用以下哪种编程语言实现的? A.C             B  C++       C   JAVA               D.Scala (正确答案) 2.FusionIn ...

  8. 整合Spring Cloud Stream Binder与RabbitMQ进行消息发送与接收

    我最新最全的文章都在南瓜慢说 www.pkslow.com,欢迎大家来喝茶! 1 前言 Spring Cloud Stream专门用于事件驱动的微服务系统,使用消息中间件来收发信息.使用Spring ...

  9. 6. QT国际化 translate QT语言家 翻译

    main. QTranslator *qtTranslator = new QTranslator(); if (IsChinese()) { qtTranslator->load(" ...

  10. 编译x86_64 Linux内核并基于QEMU运行

    编译并运行内核镜像 安装包准备 $ sudo apt install git $ sudo apt install build-essential kernel-package fakeroot li ...