Spring入门第二十九课
事务的隔离级别,回滚,只读,过期
当同一个应用程序或者不同应用程序中的多个事务在同一个数据集上并发执行时,可能会出现许多意外的问题。
并发事务所导致的问题可以分为下面三种类型:
-脏读
-不可重复读
-幻读
看代码:
db.properties
jdbc.user=root
jdbc.password=logan123
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/spring jdbc.initPoolSize=5
jdbc.maxPoolSize=10
applicationContext.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"
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.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"> <context:component-scan base-package="logan.study.spring.tx"></context:component-scan> <!-- 导入资源文件 -->
<context:property-placeholder location="classpath:db.properties"/> <!-- 配置C3P0数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property> <property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean> <!-- 配置Spring的JDBCTemplate -->
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- 配置NamedParameterJdbcTemplate,该对象可以使用具名参数,其没有无参的构造器,所以必须为其构造器指定参数 -->
<bean id="namedParameterJdbcTemplate"
class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="dataSource"></constructor-arg>
</bean> <!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- 启用事务注解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
package logan.study.spring.tx;
public interface BookShopDao {
//根据书号获取书的单价
public int findBookPriceIsbn(String isbn);
//更新书的库存,使书号对应的库存-1
public void updateBookStock(String isbn);
public void updateUserAccount(String username,int price);
}
package logan.study.spring.tx; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository; @Repository("bookShopDao")
public class BookShopDaoImpl implements BookShopDao { @Autowired
private JdbcTemplate jdbcTemplate; @Override
public int findBookPriceIsbn(String isbn) {
// TODO Auto-generated method stub
String sql = "SELECT price FROM book WHERE isbn=?";
return jdbcTemplate.queryForObject(sql, Integer.class, isbn);
} @Override
public void updateBookStock(String isbn) {
// TODO Auto-generated method stub
//检查书的库存是否足够,若不够,则抛出异常
String sql2 = "SELECT stock FROM book_stock WHERE isbn = ?";
int stock = jdbcTemplate.queryForObject(sql2, Integer.class, isbn);
if(stock == 0){
throw new BookStockException("库存不足!");
}
String sql = "UPDATE book_stock SET stock = stock -1 WHERE isbn = ?";
jdbcTemplate.update(sql, isbn); } @Override
public void updateUserAccount(String username, int price) {
// TODO Auto-generated method stub
//检查书的库存是否足够,若不够,则抛出异常
String sql2 = "SELECT balance FROM account WHERE username = ?";
int balance = jdbcTemplate.queryForObject(sql2, Integer.class, username);
if(balance < price){
throw new UserAccountException("余额不足!");
}
String sql = "UPDATE account SET balance = balance - ? WHERE username = ?";
jdbcTemplate.update(sql, price, username); } }
package logan.study.spring.tx;
public interface BookShopService {
public void purchase(String username, String isbn);
}
package logan.study.spring.tx; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; @Service("bookShopService")
public class BookShopServiceImpl implements BookShopService { @Autowired
private BookShopDao bookShopDao; //添加事务注解
@Transactional
@Override
public void purchase(String username, String isbn) {
// TODO Auto-generated method stub
//1.获取书的单价
int price = bookShopDao.findBookPriceIsbn(isbn);
//2.更新书的库存
bookShopDao.updateBookStock(isbn);
//3.更新用户余额
bookShopDao.updateUserAccount(username, price); } }
package logan.study.spring.tx;
import java.util.List;
public interface Cashier {
public void checkout(String username,List<String> isbns);
}
package logan.study.spring.tx; import java.util.List; 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("cashier")
public class CashierImpl implements Cashier{ @Autowired
private BookShopService bookShopService; /**
* 使用propagation指定事务的传播行为,即当前的事务方法被另外一个事务方法调用时
* 如何使用事务,默认取值为REQUIRED,即使用调用方法的事务
* REQUIRES_NEW事务自己的事务,调用事务方法的事务被挂起
* 使用isolation指定事务的隔离级别,最常用取值为READ_COMMITTED
* 默认情况下,Spring的声明式事务对所有的运行时异常进行回滚,也可以通过对应的属性进行设置
* 使用readonly 指定事务为只读,表示这个事务只读取数据单不更新数据,
* 这样可以帮助数据库引擎优化事务。若真的是一个只读数据库值的方法,应该设置readOnly=true
* 使用timeout指定强制回滚之前事务可以占用的时间。
*/
@Transactional(propagation=Propagation.REQUIRES_NEW,
isolation=Isolation.READ_COMMITTED,
noRollbackFor={UserAccountException.class})
@Override
public void checkout(String username, List<String> isbns) {
// TODO Auto-generated method stub
for(String isbn:isbns){
bookShopService.purchase(username, isbn);
} } }
|
当同一个应用程序或者不同应用程序中的多个事务在同一 个数据集上并发执行时,可能会出现许多意外的问题 -脏读:对于两个事物T1,T2,T1读取了已经被T2更新但还没有被 提交的字段.之后,若T2回滚,T1读取的内容就是临时且无效的. -幻读:对于两个事物T1,T2,T1从一个表中读取了一个字段,然后 T2在该表中插入了一些新的行.之后,如果T1再次读取同一个表, 就会多出几行. |
Spring入门第二十九课的更多相关文章
- Spring入门第二十八课
事务的传播行为 当事务方法被另一个事务方法调用时,必须指定事务应该如何传播,例如:方法可能继续在现有事务中运行,也可能开启一个新的事务,并在自己的事务中运行. 事务的传播行为可以由传播属性指定.Spr ...
- Spring入门第二十六课
Spring中的事务管理 事务简介 事务管理是企业级应用程序开发中必不可少的技术,用来确保数据的完整性和一致性. 事务就是一系列的动作,他们被当做一个单独的工作单元,这些动作要么全部完成,要么全部不起 ...
- Spring入门第二十五课
使用具名参数 直接看代码: db.properties jdbc.user=root jdbc.password=logan123 jdbc.driverClass=com.mysql.jdbc.Dr ...
- Spring入门第二十四课
Spring对JDBC的支持 直接看代码: db.properties jdbc.user=root jdbc.password=logan123 jdbc.driverClass=com.mysql ...
- Spring入门第二十二课
重用切面表达式 我们有的时候在切面里面有多个函数,大部分函数的切入点都是一样的,所以我们可以声明切入点表达式,来重用. package logan.study.aop.impl; public int ...
- NeHe OpenGL教程 第二十九课:Blt函数
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- python第二十九课——文件读写(复制文件)
自定义函数:实现文件复制操作有形参(2个) 没有返回值相似版(不用) def copyFile(src,dest): #1.打开两个文件:1个关联读操作,1个关联写操作 fr=open(src,'rb ...
- python第二十九课——文件读写(读取读取中文字符)
演示:读取中文字符 结论: 1).如果不设置encoding,默认使用gbk进行编解码 2).如果编码和解码不一致,最终导致报错,但是一旦设置了errors='ingore',那么就不会报错,而采取乱 ...
- Spring入门第二十课
返回通知,异常通知,环绕通知 看代码: package logan.study.aop.impl; public interface ArithmeticCalculator { int add(in ...
随机推荐
- jQuery悬浮焦点图宽屏
在线演示 本地下载
- PE.微PE
1.老毛桃,大白菜(20180227) ZC:我记得以前 "老毛桃"."大白菜" 之前的版本,在安装好系统之后,是没有捆绑软件的,.现在,老毛桃 安装完系统之后 ...
- 英语发音规则---字母组合ou的发音规律
英语发音规则---字母组合ou的发音规律 一.总结 一句话总结: 1.先练习一下题,单词enough划线部分与下列那个单词划线部分读音相同:A. touch B. mouth C. soul D ...
- java: jdk1.8以后就不支持桥接的方式
java: jdk1.8以后就不支持桥接的方式 如果想继续使用桥接的方式,请使用jdk1.7及以下版本.
- 【python】关于函数递归使用 return 后,收到数据为 None。
在写一个辗转相除求最小公因数的程序的时候,突然发现自己不管怎么写(除了两数恰巧可以整除),return 返回的值恒为 none. 代码为此: def gcd(a,b): if a%b==0: retu ...
- 大数据_学习_01_Hadoop 2.x及hbase常用端口及查看方法
二.参考资料 1.Hadoop 2.x常用端口及查看方法
- Javascript-- jQuery动画篇(1)
jQuery中隐藏元素的hide方法 让页面上的元素不可见,一般可以通过设置css的display为none属性.但是通过css直接修改是静态的布局,如果在代码执行的时候,一般是通过js控制元素的st ...
- kettle文件以邮件附件的形式发送报告
将从表中导出的excel文件以邮件附件的形式发送报告 step1: 导出文件file1.xls step2: add filename to result将文件添加到结果 step3: 发送邮件
- Linux-安装ssh服务
问题描述: 有些版本的linux系统,如Ubuntn 16 ,安装完成后缺少ssh服务, 所以putty链接会出现访问失败的情况. 解决办法: 在linux中安装ssh服务,并启动 1.安装 sudo ...
- tornado 获取参数
self.get_argument('name') 没有传递name就报400错误了 tornado.web.MissingArgumentError: HTTP 400: Bad Request ( ...