Spring的事務管理
事務管理是企業級應用程序開發中必不可少的技術,用來確保數據的完整性和一致性,在開發中,咱們是常常遇到的兩個字,並且在安卓開發中也是頻繁出現的。java
那麼在Spring中,對於jdbc的支持是怎樣的呢?在這裏暫且先拋棄Hibernate,Mybatis框架的使用,看看傳統的Spring中對數據庫的操做,其實,後面的框架也是同樣的邏輯道理的。mysql
業務需求:一個數據庫中,有三張表,分別是:spring
用戶資料表:表內包含 id, username , price(用戶的帳戶餘額)三個字段sql
書籍表:表內包含 id , bookname , bookprice 三個字段數據庫
書店表:表內包含 bookid , count(對應bookid書籍的剩餘數量)框架
需求:ide
那麼先根據需求寫一個接口 BookShopI測試
public interface BookShopI {spa
/**
* 根據書的編號查找書的價格
* @param id 書的編號
* @return
*/
int findBookPriceById(String id);
/**
* 更新書的庫存
* @param id 書的編號
*/
void updateBookStore(String id);
/**
* 更新用戶的帳戶餘額
* @param userName 用戶名
* @param price 餘額
*/
void updateUserAccount(String userName,int price);
}
.net
有了接口那麼咱們就寫個基於此接口的實現類
@Repository("bookShop")
public class BookShopImpl implements BookShopI {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public int findBookPriceById(String id) {
String sql = "select bookprice from book where id = ? ";
return jdbcTemplate.queryForObject(sql, Integer.class, id);
}
@Override
public void updateBookStore(String id) {
// 先查找數據庫的的剩餘的庫存,若等於0則拋出庫存不足的異常(前提是用戶每次購買一本的狀況下)
String checkSql = "select count from book_store where bookid = ?";
Integer count = jdbcTemplate.queryForObject(checkSql, Integer.class, id);
if (count == 0) {
throw new BookStoreException("庫存不足");
}
String sql = "update book_store set count = count - 1 where bookid = ?";
jdbcTemplate.update(sql, id);
}
@Override
public void updateUserAccount(String userName, int price) {
//先查找數據庫的的用戶剩餘的餘額,若小於所要支付的金錢則拋出餘額不足的異常
String checkSql = "select price from account where username = ?";
Integer userPrice = jdbcTemplate.queryForObject(checkSql, Integer.class, userName);
if (userPrice < price) {
throw new UserPriceException("餘額不足");
}
String sql = "update account set price = price - ? where username = ?";
jdbcTemplate.update(sql, price, userName);
}
}
其中實現類中的兩個異常類 BookStoreException 和 UserPriceException 都是一個繼承RuntimeException的java類,而後實現父類的構造方法,在這就不貼出來了。
一個服務接口: UserByBookServiceI
public interface UserByBookServiceI {
/**
* 用戶買書
* @param UserName 用戶名
* @param bookId 書的編號
*/
void byBook(String UserName,String bookId);
}
對應接口的實現 UserByBookServiceI :
@Service("userByBookService")
public class UserByBookServiceImpl implements UserByBookServiceI {
@Autowired
private BookShopI bookShopI;
@Override
public void byBook(String UserName, String bookId) {
//1.獲取書的單價
int bookPrice = bookShopI.findBookPriceById(bookId);
//2.更新書的庫存
bookShopI.updateBookStore(bookId);
//3.更新用戶的餘額
bookShopI.updateUserAccount(UserName, bookPrice);
}
}
最後是Spring的配置文件
<!-- 導入資源文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 自動掃描 -->
<context:component-scan base-package="com.spring.trans"></context:component-scan>
<!-- 配置c3p0數據源 -->
<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>
對應的數據庫鏈接信息文件
jdbc.user=root
jdbc.password=
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///testspring
jdbc.initPoolSize=5
jdbc.maxPoolSize=10
最後測試的結果是能夠對數據庫進行對應的接口操做的,即能修改數據庫的信息,而且異常也會捕獲,以上都是最基本的Spring對於數據庫的操做。
那麼問題來了,咱們上面爲了防止書籍的庫存不足或者用於餘額不足的狀況進行了異常捕獲,但實際的操做中,是有問題的,好比當book_store 表當中的某一個書籍的數量不等於0,當一個用戶進行購買的時候,數量會自動減1,可是。。。。用戶的餘額卻不足以支付這本書的費用,那麼。上面的代碼就會形成數據庫中書的庫存數量減1,用戶餘額沒有減,用戶沒有購買成功,庫存卻減小了,顯然這是不合理的,這是數據不一樣步,數據不一致形成的。
所以,在Spring中,Spring的事務JdbcTemplate對此有相應的支持,提供解決辦法。
首先在配置文件中添加事務的支持和啓用事務的註解(由於是基於註解的操做)
<!-- 配置事務管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 啓用事務註解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
最後在 UserByBookServiceImpl 中添加一個註解
測試觀察數據庫,即便餘額不足,也不會庫存減小,固然餘額更不會去減小,這就實現了數據的一致和同步性,也體現了事務的做用。關於其內部的實現,尚未去研究,但大概也能知道是aop原理下的事務回滾操做。