spring学习笔记十八 事务

一、事务简介
          a.事务管理是企业级应用程序开发中必不可少的技术,用来保存数据的完整性和一致性。
        b.事务就是一系列的动作,它被当做一个单独的工作单元,这些动作要么全部完成,要么全部都不起作用。
        c.事务的四大关键属性:原子性、一致性、隔离性、持久性.
Spring中的事务管理
作为企业级应用程序框架,Spring在不同的事务管理API之上定义了一个抽象层。而应用程序开发人员不必了解底层的事务管理API,就可以使用Spring的事务管理机制。
Spring既支持编程式事务管理,也支持声明式的事务管理
编程式事务管理:将事务管理代码嵌入到业务方法中来控制事务的提交和回滚,在编程式事务中,必须在每个业务操作中包含额外的事务管理代码
声明式事务管理:大多数情况下比编程式事务管理更好用。它将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。事务管理作为一种横切关注点,可以通过AOP方法模块化。Spring通过Spring AOP框架支持声明式事务管理。


二、实例

      (1)数据库

       数据库目录

account表

book表:

book_stock表:


       (2)工程目录

 

工程所需的jar包:


BookShopDao.java接口

package spring.tx;

public interface BookShopDao {
	//根据书号获取书的单价
	public int findBookPriceByIsbn(String isbn);
	
	//更新书的书库,使书号对应的库存-1
	public void updateBookStock(String isbn);
	
    //更新用户的账户余额:使username的balance-price
	public void updataUserAccount(String username,int price);
}

BookShopDaoImpl.java实现这个接口

package 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 findBookPriceByIsbn(String isbn) {
		String sql="select price from book where isbn=?";
		return jdbcTemplate.queryForObject(sql, Integer.class, isbn);
	}

	@Override
	public void updateBookStock(String isbn) {
		//检查书的库存是否不足,若不足,抛出异常
		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 updataUserAccount(String username, int price) {
	    //验证余额不足,若不足,则抛出异常
		String sql2="select balance from account where username=?";
		int balace=jdbcTemplate.queryForObject(sql2, Integer.class,username);
		if(balace<price){
			throw new UserAccountException("余额不足");
		}
		
		String sql="update account set balance=balance-? where username=?";
		jdbcTemplate.update(sql,price,username);
	}

}
BookShopService.java接口

package spring.tx;

public interface BookShopService {
	//买书
	public void purchase(String username,String isbn);
}
BookShopServiceImpl.java实现这个接口
package 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) {
		//1.获取书的价格
		int price=bookShopDao.findBookPriceByIsbn(isbn);
		//2.更新书的库存
		bookShopDao.updateBookStock(isbn);
		//3.更新用户余额
        bookShopDao.updataUserAccount(username, price);
	}

}
BookStockException.java 定义一个异常类,当书的库存为0时,抛出异常

package spring.tx;

public class BookStockException extends RuntimeException{

	
	/**
	 * 
	 */
	private static final long serialVersionUID = 8190751601471645251L;

	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
	}

}

UserAccountException.java  定义一个异常类,当余额不足时抛出异常

package spring.tx;

public class UserAccountException extends RuntimeException{

	/**
	 * 
	 */
	private static final long serialVersionUID = 7503993654590841863L;

	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
	}

}


db.properties 存放连接数据库的信息

jdbc.user=root
jdbc.password=123
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///spriing_book
jdbc.initPoolSize=5
jdbc.maxPoolSize=10

ApplicationContext.java定义一个配置文件

<?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:aop="http://www.springframework.org/schema/aop"
	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.0.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">
	
	<context:component-scan base-package="spring_test spring.tx"></context:component-scan>
	
	<!-- 导入资源文件 -->
	<context:property-placeholder location="classpath:db.properties"/>
	
	<!-- 配置C3P0数据源
	    Spring对数据库的操作在jdbc上面做了深层次的封装,使用spring的注入功能,
	    可以把DataSource注册到JdbcTemplate之中。同时,为了支持对properties文件的支持,
	    spring提供了类似于EL表达式的方式,把db.properties的文件参数引入到参数配置之中,
	    <context:property-placeholder location="classpath:db.properties" />。
	 -->
	<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>
   
   <!-- 
         添加事务,只要添加一个事务管理器,启动事务注解,在对应的方法上添加一个注解,
    -->
    <!-- 配置事务管理器 -->
    <bean id="transactionManager" 
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    	<property name="dataSource" ref="datasource"></property>
    </bean>
    
    <!-- 启动事物注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
SpringTransactionTest.java定义一个测试类

package spring.tx;

import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.*;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTransactionTest {

	private ApplicationContext ctx=null;
	private BookShopDao bookShopDao=null;
	private BookShopService bookShopService=null;
	{
		ctx=new ClassPathXmlApplicationContext("ApplicationContext.xml");
		bookShopDao=ctx.getBean(BookShopDao.class);
		bookShopService=ctx.getBean(BookShopService.class);
	}
	//购买商品
	@Test
	public void testBookShopService(){
		bookShopService.purchase("AA", "1001");
	}
	//更新账户
	@Test
	public void testBookShopDaoUpdateUserAccount(){
		bookShopDao.updataUserAccount("AA", 200);
	}
	//根据书号更新书的库存
	@Test
	public void testBookShopDaoUpdateBookStock(){
		bookShopDao.updateBookStock("1001");
	}
	//根据书号查询
	@Test
	public void testBookShopDaoFindPriceByIsbn() {
		System.out.println(bookShopDao.findBookPriceByIsbn("1001"));
	}

}












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不染心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值