Sptring声明式事务

Spring声明式事务

环境搭建

数据表生成

/*
SQLyog Ultimate v9.20 
MySQL - 5.1.37-community : Database - tx
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`tx` /*!40100 DEFAULT CHARACTER SET gb2312 */;

USE `tx`;

/*Table structure for table `account` */

DROP TABLE IF EXISTS `account`;

CREATE TABLE `account` (
  `username` varchar(50) NOT NULL,
  `balance` int(11) DEFAULT NULL,
  PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312;

/*Data for the table `account` */

insert  into `account`(`username`,`balance`) values ('Jerry',800),('Tom',100000);

/*Table structure for table `book` */

DROP TABLE IF EXISTS `book`;

CREATE TABLE `book` (
  `isbn` varchar(50) NOT NULL,
  `book_name` varchar(100) DEFAULT NULL,
  `price` int(11) DEFAULT NULL,
  PRIMARY KEY (`isbn`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312;

/*Data for the table `book` */

insert  into `book`(`isbn`,`book_name`,`price`) values ('ISBN-001','book01',100),('ISBN-002','book02',200),('ISBN-003','book03',300),('ISBN-004','book04',400),('ISBN-005','book05',500);

/*Table structure for table `book_stock` */

DROP TABLE IF EXISTS `book_stock`;

CREATE TABLE `book_stock` (
  `isbn` varchar(50) NOT NULL,
  `stock` int(11) DEFAULT NULL,
  PRIMARY KEY (`isbn`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312;

/*Data for the table `book_stock` */

insert  into `book_stock`(`isbn`,`stock`) values ('ISBN-001',1000),('ISBN-002',2000),('ISBN-003',3000),('ISBN-004',4000),('ISBN-005',5000);

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

account:
在这里插入图片描述
book:

在这里插入图片描述
book_stock:
在这里插入图片描述

java代码构建

  1. 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"
    	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">
    
    	<!-- 开启组件扫描 -->
    	<context:component-scan base-package="com.atguigu"></context:component-scan>
    	
    	<!-- 读取配置文件 -->
    	<context:property-placeholder location="classpath:c3p0.properties"/>
    <!-- 创建连接池对象 -->
    	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    		<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
    		<property name="driverClass" value="${jdbc.driverClass}"></property>
    		<property name="user" value="${jdbc.user}"></property>
    		<property name="password" value="${jdbc.password}"></property>
    	</bean>
    	
    	<!-- 创建JdbcTemplate对象 -->
    	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    		<constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    	</bean>
    </beans>
    
    
  2. 导入相关jar包,创建BookDao层

package com.atguigu.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class BookDap {

	@Autowired
	JdbcTemplate jdbcTemplate;
	
	/**
	 *减去某个用户余额 
	 */
	public void updateBalance(String userName,int price){
		String sql = "update account set balance = balance - ? where username = ?";
		jdbcTemplate.update(sql,price,userName);
	}
	
	/**
	 * 获取某本图书的价格
	 */
	public double getPrice(String isbn){
		String sql = "select price from book where isdn = ?";
		Integer price = jdbcTemplate.queryForObject(sql, Integer.class,isbn);
		return price;
	}
	
	/**
	 * 减某本书的库存,为了简单起见每次减1
	 */
	public void updateStock(String isbn){
		String sql = "update book_stock set stock = stock - 1 where isbn = ?";
		jdbcTemplate.update(sql,isbn);
	}
}

  1. 创建BookServicel层

    package com.atguigu.bookService;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import com.atguigu.dao.BookDao;
    
    @Service
    public class bookService {
    
    	@Autowired
    	BookDao bookDao;
    	
    	/**
    	 * 结账:对指定用户扣除买书费用
    	 * @param username 用户
    	 * @param isbn 图书编号
    	 */
    	public void checkout(String username,String isbn){
    		//减库存
    		bookDao.updateStock(isbn);
    		//查询书本价格
    		Integer price = bookDao.getPrice(isbn);
    		//减余额
    		bookDao.updateBalance(username, price);
    	}
    	
    }
    
    
  2. 测试

    package com.atguigu.test;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.atguigu.bookService.bookService;
    
    public class bookServiceTest {
    
    	ApplicationContext context = new ClassPathXmlApplicationContext("tx.xml");
    	
    	@Test
    	public void test() {
    		bookService bookService = context.getBean(bookService.class);
    		bookService.checkout("Tom", "ISBN-001");
    	}
    
    }
    
    

    此时测试一切正常,数据库中的数据会相应改变。

模拟在程序执行中发生错误

修改BookSevice

package com.atguigu.bookService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.atguigu.dao.BookDao;

@Service
public class bookService {

	@Autowired
	BookDao bookDao;
	
	/**
	 * 结账:对指定用户扣除买书费用
	 * @param username 用户
	 * @param isbn 图书编号
	 */
	public void checkout(String username,String isbn){
		//减库存
		bookDao.updateStock(isbn);
		//手动设置异常模拟错误
		int a = 1/0;
		//查询书本价格
		Integer price = bookDao.getPrice(isbn);
		//减余额
		bookDao.updateBalance(username, price);
	}
	
}

此时再次测试结果只是减了库存,但是并没有减去Tom的余额。

解决数据不统一的问题

编程式事务

TransictionFilter{
	try{
		//获取连接
		//设置非自动提交
		chain.dofIlter();
		//提交事务
	}catch{
		//回滚
	}
}

声明式事务

以前通过复杂的编程来编写一个事务,只需要告诉Spring哪个方法是事务方法即可,Spring自动进行事务控制。原理就是AOP的环绕通知,最终效果如下

class BookSerive{
     @Thransaction
     public void checkout(){
     }
}

在这里插入图片描述

这个事务管理器可以在目标方法运行前后进行事务控制(事务切面),目前使用的是DataSourceTransactionManager。

声明式事务实例

  1. 配置出这个事务管理器让他工作

    <?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"
    	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">
    
    	<!-- 开启组件扫描 -->
    	<context:component-scan base-package="com.atguigu"></context:component-scan>
    	
    	<!-- 读取配置文件 -->
    	<context:property-placeholder location="classpath:c3p0.properties"/>
    	<!-- 创建连接池对象 -->
    	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    		<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
    		<property name="driverClass" value="${jdbc.driverClass}"></property>
    		<property name="user" value="${jdbc.user}"></property>
    		<property name="password" value="${jdbc.password}"></property>
    	</bean>
    	
    	<!-- 创建JdbcTemplate对象 -->
    	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    		<constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    	</bean>
    
    	<!-- 1、创建事务管理器对象让其进行事务控制 -->
    	<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<!-- 控制住数据源 -->
    		<property name="dataSource" ref="dataSource"></property>
    	</bean>
    	<!-- 2、开启基于注解的事务控制模式,依赖名称空间tx,导入面向切面的jar包
    		com.springsource.net.sf.cglib-2.2.0.jar
    		com.springsource.org.aopalliance-1.0.0.jar
    		com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
    		spring-aspects-4.0.0.RELEASE.jar
    	 -->
    	<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
    </beans>
    
    
  2. 给事务方法加注解@Transactional

     package com.atguigu.bookService;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    import com.atguigu.dao.BookDao;
    
    @Service
    public class bookService {
    	
    	@Autowired
    	BookDao bookDao;
    	
    	/**
    	 * 结账:对指定用户扣除买书费用
    	 * @param username 用户
    	 * @param isbn 图书编号
    	 */
    	@Transactional//给事务方法加注解
    	public void checkout(String username,String isbn){
    		//减库存
    		bookDao.updateStock(isbn);
    		//手动设置异常模拟错误
    		int a = 1/0;
    		//查询书本价格
    		Integer price = bookDao.getPrice(isbn);
    		//减余额
    		bookDao.updateBalance(username, price);
    	}
    	
    }
    
    
  3. 测试

    package com.atguigu.test;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.atguigu.bookService.bookService;
    
    public class bookServiceTest {
    
    	ApplicationContext context = new ClassPathXmlApplicationContext("tx.xml");
    	
    	@Test
    	public void test() {
    		bookService bookService = context.getBean(bookService.class);
    		bookService.checkout("Tom", "ISBN-001");
    	}
    
    }
    

    此时错误依旧存在,但是数据库中的数据并没有发生改变,说明事务进行了回滚。

    import com.atguigu.bookService.bookService;

    public class bookServiceTest {

    ApplicationContext context = new ClassPathXmlApplicationContext(“tx.xml”);

    @Test
    public void test() {
    bookService bookService = context.getBean(bookService.class);
    bookService.checkout(“Tom”, “ISBN-001”);
    }

    }

    
    此时错误依旧存在,但是数据库中的数据并没有发生改变,说明事务进行了回滚。
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值