1. 程式人生 > >Spring 為什麼要用到事務的準備?

Spring 為什麼要用到事務的準備?

事務就是一個整個的過程,過程只有兩個結果,成功和失敗!

為什麼用到事務呢?


以下是例項

需求:這個模擬一個書店的銷售過程,當客戶買走書以後,書的庫存減少,而且客戶的賬戶餘額會減少

 書的編號   名稱   價格

 書的編號    庫存

 

 使用者名稱  賬戶餘額

 

總共涉及七個類,一個xml檔案

 

首先是一個介面類

package cn.com.day04;

public interface BookShopDao {
     //根據書號獲取書的單價
	public int findBookPriceByIsbn(String isbn);
	//更新書的庫存,使得書號對應的庫存-1
	public void updateBookStock(String isbn);
	//更新使用者的賬戶餘額,使得username的balance-price
	public void updateUserAccount(String username,int price);
}

 

實現類

package cn.com.day04;

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 = new JdbcTemplate();

	// 根據貨號查詢價格
	public int findBookPriceByIsbn(String isbn) {
		String sql = "select price from bookinfo where isbn=?";
		int price = jdbcTemplate.queryForObject(sql, Integer.class, isbn);
		return price;
	}

	// 根據貨號更新庫存
	public void updateBookStock(String isbn) {
		// 資料庫沒有約束,如果庫存不足的話就需要手動的新增約束
		String sql0 = "select stock from bookstock where isbn=?";
		int stock = jdbcTemplate.queryForObject(sql0, Integer.class, isbn);
		if (stock == 0) {
			throw new BookStockException("庫存不足....");

		}
		String sql = "update bookstock set stock=stock-1 where isbn=? ";
		jdbcTemplate.update(sql, isbn);
	}

	// 根據使用者名稱和價格更新使用者賬戶餘額
	public void updateUserAccount(String username, int price) {
		// 資料庫沒有約束,如果庫存不足的話就需要手動的新增約束
		String sql0 = "select count from usercount where username=?";
		int count = jdbcTemplate.queryForObject(sql0, Integer.class, username);
		if (count < price) {
			throw new BookCountException("餘額不足....");
		}
		String sql1 = "update usercount set count=count-? where username=? ";
		jdbcTemplate.update(sql1, price, username);
	}

}

手動定義異常1

package cn.com.day04;

public class BookCountException extends RuntimeException {

	public BookCountException() {
		super();
		// TODO Auto-generated constructor stub
	}

	public BookCountException(String message, Throwable cause,
			boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
		// TODO Auto-generated constructor stub
	}

	public BookCountException(String message, Throwable cause) {
		super(message, cause);
		// TODO Auto-generated constructor stub
	}

	public BookCountException(String message) {
		super(message);
		// TODO Auto-generated constructor stub
	}

	public BookCountException(Throwable cause) {
		super(cause);
		// TODO Auto-generated constructor stub
	}

}

手動定義異常2

package cn.com.day04;

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 cn.com.day04;

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

public class TestFact {
	private static ApplicationContext ioc = null;
	private static BookShopDaoImpl bookShopDaoImpl = null;
	static {
		ioc = new ClassPathXmlApplicationContext("bean-jdbc.xml");
		bookShopDaoImpl = ioc.getBean(BookShopDaoImpl.class);

	}

	public void test1() {
		System.out.println(bookShopDaoImpl.findBookPriceByIsbn("1002"));
	}

	public void test2() {
		bookShopDaoImpl.updateBookStock("1001");
	}

	@Test
	public void test3() {
		bookShopDaoImpl.updateUserAccount("楊楓述", 28);
	}
}

到這裡都是測試沒有問題的!

但是買書,書的庫存減少,賬戶餘額減少,是一個整個過程,

於是乎

整合了一下程式碼

介面類

package cn.com.day04;

public interface BookShopService {
public void purchase(String username,String isbn);
}

實現類

package cn.com.day04;

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

@Service("bookShopService")
public class BookShopServiceImpl implements BookShopService{
	@Autowired
	private BookShopDaoImpl bookShopDaoImpl;
	@Override
	public void purchase(String username, String isbn) {
		//1.根據書的編號來查詢價格
		int price=bookShopDaoImpl.findBookPriceByIsbn(isbn);
		//2.更新書的庫存
		bookShopDaoImpl.updateBookStock(isbn);
		//2.根據使用者名稱查詢餘額,扣除書的價格
		bookShopDaoImpl.updateUserAccount(username, price);
	}

}

在測試的時候,就發現一個問題,如果一個人的餘額不夠付這個書的價格的話,整個過程雖然會丟擲我們剛才手動定義的異常

提示餘額不足,但是書的庫存還是減少了;

這個過程最後的結果明明沒有交易成功,但是庫存還是減少了!

這個就是我們需要用到事務的原因了