`

事务处理

 
阅读更多

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>

 

  • 大小: 8.1 KB
分享到:
评论

相关推荐

    PostgreSQL技术内幕:事务处理深度探索.docx

    PostgreSQL 事务处理技术内幕深度探索 PostgreSQL 是一种开放源代码的关系数据库管理系统(RDBMS),它具有高度的可靠性、稳定性和安全性,被广泛应用于各种企业级应用和云服务。PostgreSQL 的事务处理机制是...

    PHP事务处理实例 mysql事务处理的意义

    mysql事务处理的意义 事务处理机制在程序开发过程中有着非常重要的作用,它可以使整个系统更加安全,例如在银行处理转账业务时,如果A账户中的金额刚被发出,而B账户还没来得及接收就发生停电,这会给银行和个人带来...

    C#中的事务处理,数据库编程中常用

    在IT领域,尤其是在数据库编程中,事务处理是一个至关重要的概念,尤其在使用C#进行开发时。事务确保了数据的一致性和完整性,是数据库操作的基本单位。本篇将深入探讨C#中的事务处理,以及如何在实践中应用这些知识...

    易语言学习进阶事务处理

    本压缩包文件"易语言学习进阶事务处理"是针对易语言使用者提供的一份进阶学习资料,主要涵盖了事务处理的相关知识。 事务处理在计算机科学中是指在数据库管理系统中执行的一系列操作,这些操作被视为一个单一的工作...

    java事务处理详解

    Java事务处理详解 Java事务处理是指在Java应用程序中对事务的管理和控制。事务是指一系列的操作,Either all succeed or all fail。Java事务处理的目的是为了确保数据的一致性和完整性。 Spring是Java事务处理的...

    事务处理--介绍事务原理和事务实现.docx

    在IT领域,事务处理是数据库管理系统中的核心概念,它确保了数据的一致性和完整性。本文将深入探讨事务的原理和实现方法。 1. **什么是事务** 事务是一系列数据库操作的逻辑单元,这些操作要么全部成功执行,要么...

    数据库事务处理基础——设计与实现

    数据库事务处理是数据库管理系统中的核心概念,用于确保数据的一致性和完整性。在“数据库事务处理基础——设计与实现”这个主题中,我们将深入探讨数据库事务的各个方面,包括其定义、特性、类型以及如何在实际应用...

    VB.NET 2008事务处理示例

    在VB.NET 2008中,事务处理是确保数据库操作一致性的重要机制。它允许一组数据库操作要么全部成功,要么全部失败,从而避免了数据不一致性的风险。本示例涵盖了如何在VB.NET环境中利用ADO.NET进行事务管理,特别是在...

    sql server 事务处理

    在SQL Server中,事务处理是数据库操作的核心组成部分,它确保数据的一致性和完整性。事务是一组逻辑操作,这些操作被视为单个单元,要么全部完成,要么全部回滚,以维护数据库的ACID(原子性、一致性、隔离性和持久...

    联机事务处理系统

    联机事务处理系统,OLTP介绍

    事务处理:概念与技术

    事务处理广泛地应用于数据库和操作系统领域,并在现代计算机系统中监控、控制和更新信息。本书向读者展示了大型的、分布的、异构的计算机系统是如何进行可靠工作的。作者使用事务作为基本概念,说明了在有限的资金和...

    Spring声明式事务处理

    Spring框架的声明式事务处理是Java企业级应用中不可或缺的一部分,它为开发者提供了一种方便、高效的方式来管理事务。在Spring中,事务管理分为编程式和声明式两种方式,而声明式事务处理则是通过配置来控制事务的...

    Java中的事务处理

    在Java编程领域,事务处理是确保数据一致性与完整性的关键机制。它主要用于数据库操作,确保一组操作要么全部成功,要么全部失败,遵循ACID(原子性、一致性、隔离性和持久性)原则。以下是对Java中事务处理的详细...

    mySQL事务处理

    关于mysql的事务处理 public static void StartTransaction(Connection con, String[] sqls) throws Exception { if (sqls == null) { return; } Statement sm = null; try { // 事务开始 System....

    JSP运用事务处理

    本篇文章将深入探讨如何在JSP中应用事务处理,以及相关的重要概念和技术。 首先,我们需要了解事务的基本概念。事务是一组数据库操作,这些操作被视为一个逻辑单元,要么全部执行,要么全部不执行。事务的四大特性...

    数据库与事务处理

    事务处理是数据库系统中的关键概念,它是确保数据一致性、完整性和可靠性的重要机制。 首先,我们需要了解什么是数据库。数据库是一个结构化的数据集合,它可以存储各种类型的信息,如文本、数字、图像等。常见的...

    JAVA设计模式之事务处理

    当涉及事务处理时,设计模式可以帮助我们构建健壮、可维护的应用程序。"JAVA设计模式之事务处理"主要关注如何在业务逻辑中有效地管理和控制事务。 事务处理在企业级应用中至关重要,因为它确保数据的一致性和完整性...

    事务处理能力部分(TCAP).ppt事务处理能力部分(TCAP).ppt

    事务处理能力部分(TCAP).ppt事务处理能力部分(TCAP).ppt事务处理能力部分(TCAP).ppt事务处理能力部分(TCAP).ppt事务处理能力部分(TCAP).ppt事务处理能力部分(TCAP).ppt事务处理能力部分(TCAP).ppt事务处理能力部分...

    分布式数据库事务处理(COM+实现)

    分布式数据库事务处理是数据库系统中的一个重要概念,尤其是在大型企业级应用和互联网服务中,它能够保证数据的一致性和完整性,即使在多台计算机之间进行数据操作。COM+(Component Object Model Plus)是微软提出...

    ORCLE事务处理的基本操作

    Oracle数据库在事务处理方面提供了强大的支持,这对于保持数据的一致性和完整性至关重要。事务是一组数据库操作,这些操作被视为单个逻辑工作单元,要么全部成功,要么全部失败。本篇文章将详细探讨Oracle中事务处理...

Global site tag (gtag.js) - Google Analytics