Spring对事务的处理
Spring支持的7钟事务传播属性
传播属性 | 描述 |
PROPAGATION_REQUIRED | 如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务中运行 |
PROPAGATION_REQUIRES_NEW | 当前的方法必须启动新的事务,并在它自己额事务内运行,如果有事务在运行,应将它挂起 |
PROPAGATION_SUPPORTS | 如果有事务运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中 |
PROPAGATION_NOT_SUPPORTED | 当前的方法不应该运行在事务中,如果有正在运行的事务,将它挂起 |
PROPAGATION_MANDATORY | 当前的方法必须运行在事务的内部,如果没有正在运行的事务,抛出异常 |
PROPAGATION_NEVER | 当前的方法不应该运行在事务中,如果有运行的事务,抛出异常 |
PROPAGATION_NESTED | 如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则就启动一个新的事务,并在它自己的事务内运行 |
并发事务所导致的问题
当同一个应用程序或不同的应用程序中多个事务在同一个数据集上并发执行时,可能会出现意外
并发事务导致的问题分为三类,脏读,不可重复读,幻读
1)脏读:对于两个事务T1和T2。T1读取了已经被T2更新但还没有提交的字段,之后,若T2回滚,T1读取的数据就是临时且无效的
2)不可重复读:对于两个事务T1和T2。T1读取一个字段,然后T2更新该字段,之后,T1再次读取同一个字段,值就不同了
3)幻读:对于两个事务T1和T2。T1从一个表中读取一个字段,然后在该表中插入一些新的行,之后,如果T1再次读取同一个表,就会多出几行
具体可以参考此处文章:http://blog.csdn.net/hjm4702192/article/details/17277669
不多说,上代码
package com.hous.tx; public interface BookShopDao { // 查找书的价格 public double getPriceByBookIsbn(String isbn); // 更新书的库存 public void updateBookStock(String isbn); // 更新用户账户 public void updateUserAccount(String userid, double price); }
package com.hous.tx; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository public class BookShopDaoImpl implements BookShopDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public double getPriceByBookIsbn(String isbn) { String sql = "select price from book where isbn=?"; Double price = jdbcTemplate.queryForObject(sql, Double.class, isbn); return price; } @Override public void updateBookStock(String isbn) { String sql = "select total from stock where isbn=?"; int total = jdbcTemplate.queryForObject(sql, Integer.class, isbn); if(total <= 0){ throw new BookStockException("库存不足"); } sql = "update stock set total = total -1 where isbn= ? "; jdbcTemplate.update(sql, isbn); } @Override public void updateUserAccount(String userid, double price) { String sql = "select balance from account where userid=?"; Double balance = jdbcTemplate.queryForObject(sql, Double.class, userid); if(balance < price){ throw new UserAccountException("余额不足,请充值"); } sql = "update account set balance = balance - ? where userid= ? "; jdbcTemplate.update(sql, price, userid); } }
package com.hous.tx; public interface BookShopService { public void purchase(String userid, String isbn); }
package com.hous.tx; 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 public class BookShopServiceImpl implements BookShopService { @Autowired private BookShopDao bookShopDao; //添加事务注解 //1.使用propagation指定事务的传播行为,当一个事务方法被另一个事务方法调用时如何使用事务 //默认使用REQUIRED即调用方法的事务,REQUIRES_NEW表示调用自己的事务,调用方法的事务被挂起 //2.使用isolation指定事务的隔离级别,最常用取值READ_COMMITTED //3.默认情况下spring的声明式事务对所有运行时异常进行回滚,也可以通过noRollbackFor等进行设置 //4.使用readOnly指定事务是否为只读,表示这个事务只读取事务但不更新数据,可以帮助数据库引擎优化事务。 //只读方法设置readOnly=true //5.使用timeout指定强制回滚之前事务可以占用的时间(单位秒) @Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.READ_COMMITTED, // noRollbackFor={UserAccountException.class}, readOnly=false, timeout=3) public void purchase(String userid, String isbn) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } //1.获取书的单击 double price = bookShopDao.getPriceByBookIsbn(isbn); //2.更新库存量 bookShopDao.updateBookStock(isbn); //3.更新用户余额 bookShopDao.updateUserAccount(userid, price); } }
package com.hous.tx; public class BookStockException extends RuntimeException { public BookStockException() { super(); // TODO Auto-generated constructor stub } public BookStockException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); // TODO Auto-generated constructor stub } public BookStockException(String message, Throwable cause) { super(message, cause); // TODO Auto-generated constructor stub } public BookStockException(String message) { super(message); // TODO Auto-generated constructor stub } public BookStockException(Throwable cause) { super(cause); // TODO Auto-generated constructor stub } }
package com.hous.tx; public class UserAccountException extends RuntimeException { public UserAccountException() { super(); // TODO Auto-generated constructor stub } public UserAccountException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); // TODO Auto-generated constructor stub } public UserAccountException(String message, Throwable cause) { super(message, cause); // TODO Auto-generated constructor stub } public UserAccountException(String message) { super(message); // TODO Auto-generated constructor stub } public UserAccountException(Throwable cause) { super(cause); // TODO Auto-generated constructor stub } }
package com.hous.tx; import java.util.List; public interface Cashier { public void checkout(String userid, List<String> isbns); }
package com.hous.tx; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class CashierImpl implements Cashier { @Autowired private BookShopService bookShopService; @Override @Transactional public void checkout(String userid, List<String> isbns) { for(String isbn: isbns) { bookShopService.purchase(userid, isbn); } } }
<?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/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> <context:property-placeholder location="db.properties" /> <context:component-scan base-package="com.hous" /> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.user}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 配置spring的jdbcTemplate --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 开启事务注解 --> <tx:annotation-driven transaction-manager="transactionManager" /> </beans>
用到的数据库SQL
CREATE DATABASE /*!32312 IF NOT EXISTS*/`books` /*!40100 DEFAULT CHARACTER SET utf8 */; USE `books`; /*Table structure for table `account` */ DROP TABLE IF EXISTS `account`; CREATE TABLE `account` ( `userid` char(6) default NULL, `balance` double default NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*Data for the table `account` */ insert into `account`(`userid`,`balance`) values ('105002',93),('105005',20); /*Table structure for table `book` */ DROP TABLE IF EXISTS `book`; CREATE TABLE `book` ( `isbn` varchar(20) default NULL, `bookname` varchar(200) default NULL, `price` double default NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*Data for the table `book` */ insert into `book`(`isbn`,`bookname`,`price`) values ('isbn001','Spring入门到精通',25),('isbn002','shanshanbox.com网站架构',32),('isbn003','闪闪Box导航全攻略',18); /*Table structure for table `stock` */ DROP TABLE IF EXISTS `stock`; CREATE TABLE `stock` ( `isbn` varchar(20) default NULL, `total` int(6) default NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*Data for the table `stock` */ insert into `stock`(`isbn`,`total`) values ('isbn001',1),('isbn002',2),('isbn003',0);
使用Junit进行测试
package com.hous.test; import java.util.ArrayList; import java.util.List; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.hous.tx.BookShopDao; import com.hous.tx.BookShopService; import com.hous.tx.Cashier; public class TxTest { private ApplicationContext cxt; private BookShopDao bookShopDao; private BookShopService bookShopService; private Cashier cashier; { cxt = new ClassPathXmlApplicationContext("applicationContext.xml"); bookShopDao = cxt.getBean(BookShopDao.class); bookShopService = cxt.getBean(BookShopService.class); cashier = cxt.getBean(Cashier.class); } @Test public void testBookShopDaoFindPriceByIsbn(){ System.out.println(bookShopDao.getPriceByBookIsbn("isbn002")); } @Test public void testBookShopDaoUpdateBookStock(){ bookShopDao.updateBookStock("isbn003"); } @Test public void testBookShopDaoUpdateUserAccount(){ bookShopDao.updateUserAccount("105002", 15); } @Test public void testBookShopServicePurchase(){ bookShopService.purchase("105002", "isbn002"); } @Test public void testCashier() { List<String> isbns = new ArrayList<>(); isbns.add("isbn001"); isbns.add("isbn002"); cashier.checkout("105002", isbns); } }
基于配置方式配置事务
<?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/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> <context:property-placeholder location="db.properties" /> <context:component-scan base-package="com.hous" /> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.user}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 配置spring的jdbcTemplate --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事务管理器 --> <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="purchase" propagation="REQUIRES_NEW" timeout="3"/> <tx:method name="get*" read-only="true"/> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- 配置事务切入点并将事务切入点和事务属性关联 --> <aop:config> <aop:pointcut expression="execution(* com.hous.tx.service.*.*(..))" id="txPointcut"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> </aop:config> </beans>
相关推荐
PostgreSQL 事务处理技术内幕深度探索 PostgreSQL 是一种开放源代码的关系数据库管理系统(RDBMS),它具有高度的可靠性、稳定性和安全性,被广泛应用于各种企业级应用和云服务。PostgreSQL 的事务处理机制是...
事务处理广泛地应用于数据库和操作系统领域,并在现代计算机系统中监控、控制和更新信息。本书向读者展示了大型的、分布的、异构的计算机系统是如何进行可靠工作的。作者使用事务作为基本概念,说明了在有限的资金和...
### 联机事务处理系统(OLTP)深入解析 #### OLTP系统概览 联机事务处理系统(OLTP)是数据库管理的核心组件之一,主要用于处理大量的事务性操作,如银行交易、订单处理和机票预订等。这些系统旨在提供高并发、低...
在IT领域,尤其是在数据库编程中,事务处理是一个至关重要的概念,尤其在使用C#进行开发时。事务确保了数据的一致性和完整性,是数据库操作的基本单位。本篇将深入探讨C#中的事务处理,以及如何在实践中应用这些知识...
本压缩包文件"易语言学习进阶事务处理"是针对易语言使用者提供的一份进阶学习资料,主要涵盖了事务处理的相关知识。 事务处理在计算机科学中是指在数据库管理系统中执行的一系列操作,这些操作被视为一个单一的工作...
Java事务处理详解 Java事务处理是指在Java应用程序中对事务的管理和控制。事务是指一系列的操作,Either all succeed or all fail。Java事务处理的目的是为了确保数据的一致性和完整性。 Spring是Java事务处理的...
### Socket_UDP多事务处理程序框架的关键知识点 #### 第一部分:Socket通信事务处理中的常见问题描述 **1.1 Socket通信基础** Socket通信是基于互联网协议(IP)进行数据传输的标准方式,提供了网络上的进程间...
### 分布式事务处理在大规模SOA系统中的挑战与解决方案 #### 一、背景与历史:山穷水尽 在介绍分布式事务处理之前,我们首先回顾一下事务处理的历史背景及其面临的挑战。传统的事务处理通常是在单个应用系统内部...
数据库事务处理是数据库管理系统中的核心概念,用于确保数据的一致性和完整性。事务是数据库操作的基本单元,它包含一组逻辑操作,这些操作要么全部执行,要么全部不执行,以确保数据的原子性。事务处理主要关注两个...
事务处理 概念与技术
在IT领域,事务处理是数据库管理系统中的核心概念,它确保了数据的一致性和完整性。本文将深入探讨事务的原理和实现方法。 1. **什么是事务** 事务是一系列数据库操作的逻辑单元,这些操作要么全部成功执行,要么...
在易语言的学习过程中,进阶事务处理是提升技能的重要环节。事务处理通常涉及到数据库操作、多线程、错误处理和程序流程控制等复杂技术,对于软件的稳定性和效率有着至关重要的作用。 在这个“易语言学习进阶事务...
### ASP.NET中的事务处理与异常处理 在ASP.NET开发中,事务处理与异常处理是确保应用程序稳定性和数据一致性的重要组成部分。本文将详细探讨这两个概念及其具体应用方式。 #### 一、事务处理 事务处理主要用于...
数据库事务处理是数据库管理系统中的核心概念,用于确保数据的一致性和完整性。在“数据库事务处理基础——设计与实现”这个主题中,我们将深入探讨数据库事务的各个方面,包括其定义、特性、类型以及如何在实际应用...
在VB.NET 2008中,事务处理是确保数据库操作一致性的重要机制。它允许一组数据库操作要么全部成功,要么全部失败,从而避免了数据不一致性的风险。本示例涵盖了如何在VB.NET环境中利用ADO.NET进行事务管理,特别是在...
### Java事务处理详细介绍 #### 一、什么是Java事务 在软件开发领域,特别是涉及数据库操作的应用中,**事务处理**是非常关键的一个概念。通常人们认为事务处理与数据库操作紧密相关,其实事务的概念远不止于此。...
在SQL Server中,事务处理是数据库操作的核心组成部分,它确保数据的一致性和完整性。事务是一组逻辑操作,这些操作被视为单个单元,要么全部完成,要么全部回滚,以维护数据库的ACID(原子性、一致性、隔离性和持久...
### JavaBean中使用JDBC方式进行事务处理 #### 一、引言 在现代软件开发过程中,数据一致性是非常关键的一个方面,特别是在涉及到多个数据库操作时。本文将详细介绍如何在JavaBean中利用JDBC(Java Database ...
Spring框架的声明式事务处理是Java企业级应用中不可或缺的一部分,它为开发者提供了一种方便、高效的方式来管理事务。在Spring中,事务管理分为编程式和声明式两种方式,而声明式事务处理则是通过配置来控制事务的...