Spring 声明式事务
事务的特性/概念
- 原子性(atomicity):“原子”的本意是“不可再分”,事务的原子性表现为一个事务中涉及到的多个操作在逻辑上缺一不可。事务的原子性要求事务中的所有操作要么都执行,要么都不执行。
- 一致性(consistency):“一致”指的是数据的一致,具体是指:所有数据都处于满足业务规则的一致性状态。一致性原则要求:一个事务中不管涉及到多少个操作,都必须保证事务执行之前数据是正确的,事务执行之后数据仍然是正确的。如果一个事务在执行的过程中,其中某一个或某几个操作失败了,则必须将其他所有操作撤销,将数据恢复到事务执行之前的状态,这就是回滚。
- 隔离性(isolation):在应用程序实际运行过程中,事务往往是并发执行的,所以很有可能有许多事务同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。隔离性原则要求多个事务在并发执行过程中不会互相干扰。
- 持久性(durability):持久性原则要求事务执行完成后,对数据的修改永久的保存下来,不会因各种系统错误或其他意外情况而受到影响。通常情况下,事务对数据的修改应该被写入到持久化存储器中。
jar包
<!--1、配置连接池 -->
<bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/tx"></property>
</bean>
<!--2、数据库的增删改查 JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="comboPooledDataSource"></property>
</bean>
<!--配置事务切面;控制住连接池 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="comboPooledDataSource"></property>
</bean> <!--开启基于注解的事务功能;依赖tx名称空间
transaction-manager:指定事务管理器是哪个
-->
<tx:annotation-driven/>
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository; /**
* [1]根据isbn的值查询书的价格,
public int getPrice(String isbn);
[2]根据isbn的值减少书的库存,假设每次都只买1本书,
public void updateStock(String isbn);
[3]根据用户名减少用户账户中的余额,减少的额度就是书的价格
public void updateBalance(int price,String user);
* @author lfy
*
*/
@Repository
public class BookDao { @Autowired
JdbcTemplate jdbcTemplate; /**
* [1]根据isbn的值查询书的价格,
* public int getPrice(String isbn);
* 操作:book
*/
public int getPrice(String isbn){
String sql = "select price from book where isbn=?";
Integer price = jdbcTemplate.queryForObject(sql, Integer.class, isbn);
return price;
}; /**
* [2]根据isbn的值减少书的库存,假设每次都只买1本书,
* public void updateStock(String isbn);
* 操作:book_stock
*/
public void updateStock(String isbn){
String sql = "UPDATE book_stock SET stock=stock-1 WHERE isbn=?";
jdbcTemplate.update(sql, isbn);
} /**
* [3]根据用户名减少用户账户中的余额,减少的额度就是书的价格
* public void updateBalance(int price,String user);
* 给用户减余额;account
* String user:要减余额的用户名
* int price:要减掉多少(减少的额度就是书的价格)
*/
public void updateBalance(int price,String user){
String sql = "update account set balance = balance-? where username=?";
jdbcTemplate.update(sql, price,user); } public void updatePrice(String isbn){
String sql = "update book set price = 999 WHERE isbn=?";
jdbcTemplate.update(sql, isbn);
}
}
事务注解主要添加在Service层,通过Aop来实现事务操作:
import java.io.FileInputStream;
import java.io.FileNotFoundException; 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; import com.atguigu.dao.BookDao; @Service
public class BookService { @Autowired
BookDao bookDao; @Transactional(noRollbackFor=ArithmeticException.class,
timeout=3,propagation=Propagation.REQUIRES_NEW)
public void checkout(String username,String isbn){
//0、查出图书价格
int price = bookDao.getPrice(isbn);
//1、减用户余额
bookDao.updateBalance(price, username);
//2、减图书的库存
bookDao.updateStock(isbn); //Thread.sleep(3000);
//new FileInputStream("D://ahahahah//aa.txt");
System.out.println("结账完成....");
} @Transactional(propagation=Propagation.REQUIRED,timeout=3)
public void updatePrice(String isbn){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
bookDao.updatePrice(isbn);
} }
Spring事务管理器
事务控制的属性:
propagation:事务的传播行为;我们可以通过控制指定大事务和小事务的关系;
传播(共用一个事务的情况下大事务的属性配置会传播给小事务)+行为(是否共用一个事务)。
- 脏读:同一事务期间,数据还没提交就给回滚了。
- 不可重复读:同一事务期间,多次读取数据内容不一样。
- 幻读:同一事务期间,多次读取数据,发现记录变少或者变多了。
本质上一个再读,一个在改;
数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。一个事务与其他事务隔离的程度称为隔离级别。SQL标准中规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。
①读未提交:READ UNCOMMITTED
允许Transaction01读取Transaction02未提交的修改。
②读已提交:READ COMMITTED
要求Transaction01只能读取Transaction02已提交的修改。
③可重复读:REPEATABLE READ
确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其它事务对这个字段进行更新。
④串行化:SERIALIZABLE
确保Transaction01可以多次从一个表中读取到相同的行,在Transaction01执行期间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性能十分低下。
⑤各个隔离级别解决并发问题的能力见下表
⑥各种数据库产品对事务隔离级别的支持程度
在Spring中指定事务隔离级别
注解
用@Transactional注解声明式地管理事务时可以在@Transactional的isolation属性中设置隔离级别
XML
在Spring 2.x事务通知中,可以在<tx:method>元素中指定隔离级别
触发事务回滚的异常
默认情况
捕获到RuntimeException或Error时回滚,而捕获到编译时异常不回滚。
设置途经
注解
@Transactional 注解
- rollbackFor属性:指定遇到时必须进行回滚的异常类型,可以为多个
- noRollbackFor属性:指定遇到时不回滚的异常类型,可以为多个
XML
在Spring 2.x事务通知中,可以在<tx:method>元素中指定回滚规则。如果有不止一种异常则用逗号分隔。
事务的超时和只读属性
简介
由于事务可以在行和表上获得锁,因此长事务会占用资源,并对整体性能产生影响。
如果一个事物只读取数据但不做修改,数据库引擎可以对这个事务进行优化。
超时事务属性:事务在强制回滚之前可以保持多久。这样可以防止长期运行的事务占用资源。
只读事务属性: 表示这个事务只读取数据但不更新数据, 这样可以帮助数据库引擎优化事务。
设置
注解
@Transaction注解
XML
在Spring 2.x事务通知中,超时和只读属性可以在<tx:method>元素中进行指定
举个比较完整的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: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 http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <context:component-scan base-package="com.atguigu"></context:component-scan> <!--1、配置连接池 -->
<bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/tx"></property>
</bean> <!--2、数据库的增删改查 JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="comboPooledDataSource"></property>
</bean> <!--3、配置事务切面;控制住连接池 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="comboPooledDataSource"></property>
</bean> <!--4、开启基于注解的事务功能;依赖tx名称空间
transaction-manager:指定事务管理器是哪个
-->
<!-- <tx:annotation-driven/> --> <!--基于xml的事务配置;需要aop和tx名称空间 -->
<!-- transactionManager事务切面 -->
<aop:config>
<!--指定事务管理器要切入哪些方法进行事务控制 -->
<aop:pointcut expression="execution(* com.soyoungboy.service.*.*(..))" id="txPoint"/>
<!-- aop:advisor:建议; pointcut-ref:使用指定的切入点表达式切入事务 -->
<aop:advisor advice-ref="myTxAdvice" pointcut-ref="txPoint"/>
</aop:config> <!-- 使用tx名称空间和配置(事务建议、事务属性、事务增强);事务方法怎么执行
id="myTxAdvice":随便起,别人要引用<aop:advisor advice-ref="myTxAdvice"
transaction-manager="transactionManager":指定配置哪个事务管理器
-->
<tx:advice id="myTxAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 指定事务方法:代表所有方法是事务方法 -->
<tx:method name="*"/>
<tx:method name="checkout" rollback-for="java.lang.Exception"/>
<tx:method name="updatePrice" propagation="REQUIRES_NEW"/>
<!--以get开头的,通过只读来进行优化-->
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice> <!-- 基于xml配置的事务控制更多一点 --> </beans>
Spring 声明式事务的更多相关文章
- spring声明式事务管理总结
事务配置 首先在/WEB-INF/applicationContext.xml添加以下内容: <!-- 配置事务管理器 --> <bean id="transactionM ...
- spring 声明式事务管理
简单理解事务: 比如你去ATM机取5000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉5000元钱:然后ATM出5000元钱.这两个步骤必须是要么都执行要么都不执行.如果银行卡扣除了5000块但 ...
- Spring声明式事务管理基于@Transactional注解
概述:我们已知道Spring声明式事务管理有两种常用的方式,一种是基于tx/aop命名空间的xml配置文件,另一种则是基于@Transactional 注解. 第一种方式我已在上文为大 ...
- Spring声明式事务管理基于tx/aop命名空间
目的:通过Spring AOP 实现Spring声明式事务管理; Spring支持编程式事务管理和声明式事务管理两种方式. 而声明式事务管理也有两种常用的方式,一种是基于tx/aop命名空间的xml配 ...
- Spring声明式事务配置管理方法
环境配置 项目使用SSH架构,现在要添加Spring事务管理功能,针对当前环境,只需要添加Spring 2.0 AOP类库即可.添加方法: 点击项目右键->Build Path->Add ...
- 161117、使用spring声明式事务抛出 identifier of an instance of
今天项目组有成员使用spring声明式事务出现下面异常,这里跟大家分享学习下. 异常信息: org.springframework.orm.hibernate3.HibernateSystemExce ...
- Spring声明式事务管理与配置详解
转载:http://www.cnblogs.com/hellojava/archive/2012/11/21/2780694.html 1.Spring声明式事务配置的五种方式 前段时间对Spring ...
- Spring声明式事务配置管理方法(转)
项目使用SSH架构,现在要添加Spring事务管理功能,针对当前环境,只需要添加Spring 2.0 AOP类库即可.添加方法: 点击项目右键->Build Path->Add libra ...
- Spring声明式事务的配置~~~
/*2011年8月28日 10:03:30 by Rush */ 环境配置 项目使用SSH架构,现在要添加Spring事务管理功能,针对当前环境,只需要添加Spring 2.0 AOP类库即可.添加 ...
- Spring 声明式事务,propagation属性列表及isolation(隔离级别)
Spring 声明式事务,propagation属性列表 TransactionDefinition接口中定义,共有7种选项可用: PROPAGATION_REQUIRED:支持当前事务,如果当前没有 ...
随机推荐
- [转帖]tar高级教程:增量备份、定时备份、网络备份
tar高级教程:增量备份.定时备份.网络备份 作者: lesca 分类: Tutorials, Ubuntu 发布时间: 2012-03-01 11:42 ė浏览 27,065 次 61条评论 一.概 ...
- CentOS7 网络NAT模式
问题:安装完毕ping命令不能用,然后改为桥接模式,ping可以用. 先了解桥接,NAT 的含义. 桥接:在bridged模式下,VMWare虚拟出来的操作系统就像是局域网中的一台独立的主机,它可以访 ...
- snv的使用
1.搭建SVN服务器 (1)直接安装 (2)创建工号,分组,分配权限(图形化界面的直接操作,非图形界面的需要改配置文件conf文件夹下) (3)创建仓库,D:\Repositories\OA:cmd命 ...
- python之路--基础数据类型的补充与深浅copy
一 . join的用法 lst =['吴彦祖','谢霆锋','刘德华'] s = '_'.join(lst) print(s) # 吴彦祖_谢霆锋_刘德华 # join() "*" ...
- WPF当属性值改变时利用PropertyChanged事件来加载动画
在我们的程序中,有时我们需要当绑定到UI界面上的属性值发生变化从而引起数据更新的时候能够加载一些动画,从而使数据更新的效果更佳绚丽,在我们的程序中尽量将动画作为一种资源放在xaml中,而不是在后台中通 ...
- 织梦后台如何生成站点地图sitemap.xml
第一步在网站根目录建立sitemap.php文件 内容如下: 写一个计划任务文件命名为generate_sitemap.php,放在/plus/task目录里,文件内容如下: <?php//定时 ...
- Armstrong公理
从已知的一些函数依赖,可以推导出另外一些函数依赖,这就需要一系列推理规则,这些规则常被称作“Armstrong 公理”. 设U 是关系模式R 的属性集,F 是R 上成立的只涉及U 中属性的函数依赖集. ...
- Lodop生成文档式模版
Lodop模版有两种方法,一种是传统的JS语句,可以用JS方法里的eval来执行,一种是文档式模版,是特殊格式的base64码,此篇博文介绍文档式模版的生成方法.两种模版都可以存入一下地方进行调用,比 ...
- Tomcat配置Https环境
windows环境下:http://blog.csdn.net/supersky07/article/details/7407523 linux环境下:http://blog.csdn.net/cuk ...
- ES 6 系列 - 对于常用对象的拓展 api
本篇中学习并记录可能会比较常用的 api ,详细请自行查找相关资料. 一.字符串的拓展 es 6 加强了对于 Unicode 的支持.javascript 允许采用 \uxxxxx 的方式表示一个字符 ...