javascript
Spring4 学习系列之——jdbc事务的基本实现和了解
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
Spring的事務(wù)管理 ?
事務(wù)管理是企業(yè)級(jí)應(yīng)用程序開發(fā)中必不可少的技術(shù),用來確保數(shù)據(jù)的完整性和一致性,在開發(fā)中,我們是經(jīng)常遇到的兩個(gè)字,而且在安卓開發(fā)中也是頻繁出現(xiàn)的。
那么在Spring中,對(duì)于jdbc的支持是怎樣的呢?在這里暫且先拋棄Hibernate,Mybatis框架的使用,看看傳統(tǒng)的Spring中對(duì)數(shù)據(jù)庫(kù)的操作,其實(shí),后面的框架也是一樣的邏輯道理的。
業(yè)務(wù)需求:一個(gè)數(shù)據(jù)庫(kù)中,有三張表,分別是:
用戶資料表:表內(nèi)包含 id, username , price(用戶的賬戶余額)三個(gè)字段
書籍表:表內(nèi)包含 id , bookname , bookprice 三個(gè)字段
書店表:表內(nèi)包含 bookid , count(對(duì)應(yīng)bookid書籍的剩余數(shù)量)
需求:
- 根據(jù)書的編號(hào)查找書的價(jià)格
- 更新書的庫(kù)存
- 更新用戶的賬戶余額
那么先根據(jù)需求寫一個(gè)接口 ?BookShopI
public interface BookShopI {
?? ?/**
?? ? * 根據(jù)書的編號(hào)查找書的價(jià)格
?? ? * @param id 書的編號(hào)
?? ? * @return
?? ? */
?? ?int findBookPriceById(String id);
?? ?
?? ?/**
?? ? * 更新書的庫(kù)存
?? ? * @param id 書的編號(hào)
?? ? */
?? ?void updateBookStore(String id);
?? ?
?? ?/**
?? ? * 更新用戶的賬戶余額
?? ? * @param userName 用戶名
?? ? * @param price?? ??? ?余額
?? ? */
?? ?void updateUserAccount(String userName,int price);
}
?
有了接口那么我們就寫個(gè)基于此接口的實(shí)現(xiàn)類
@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) {
?? ??? ?// 先查找數(shù)據(jù)庫(kù)的的剩余的庫(kù)存,若等于0則拋出庫(kù)存不足的異常(前提是用戶每次購(gòu)買一本的情況下)
?? ??? ?String checkSql = "select count from book_store where bookid = ?";
?? ??? ?Integer count = jdbcTemplate.queryForObject(checkSql, Integer.class, id);
?? ??? ?if (count == 0) {
?? ??? ??? ?throw new BookStoreException("庫(kù)存不足");
?? ??? ?}
?? ??? ?String sql = "update book_store set count = count - 1 where bookid = ?";
?? ??? ?jdbcTemplate.update(sql, id);
?? ?}
?? ?@Override
?? ?public void updateUserAccount(String userName, int price) {
?? ??? ?//先查找數(shù)據(jù)庫(kù)的的用戶剩余的余額,若小于所要支付的金錢則拋出余額不足的異常
?? ??? ?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);
?? ?}
}
其中實(shí)現(xiàn)類中的兩個(gè)異常類?BookStoreException 和?UserPriceException 都是一個(gè)繼承RuntimeException的java類,然后實(shí)現(xiàn)父類的構(gòu)造方法,在這就不貼出來了。
?
一個(gè)服務(wù)接口:?UserByBookServiceI
public interface UserByBookServiceI {
?? ?
?? ?/**
?? ? * 用戶買書
?? ? * @param UserName 用戶名
?? ? * @param bookId 書的編號(hào)
?? ? */
?? ?void byBook(String UserName,String bookId);
}
?
對(duì)應(yīng)接口的實(shí)現(xiàn) UserByBookServiceI :
@Service("userByBookService")
public class UserByBookServiceImpl implements UserByBookServiceI {
?? ?
?? ?@Autowired
?? ?private BookShopI bookShopI;
?? ?
?? ?@Override
?? ?public void byBook(String UserName, String bookId) {
?? ??? ?//1.獲取書的單價(jià)
?? ??? ?int bookPrice = bookShopI.findBookPriceById(bookId);
?? ??? ?//2.更新書的庫(kù)存
?? ??? ?bookShopI.updateBookStore(bookId);
?? ??? ?//3.更新用戶的余額
?? ??? ?bookShopI.updateUserAccount(UserName, bookPrice);
?? ?}
?? ?
}
?
?
最后是Spring的配置文件
<!-- 導(dǎo)入資源文件 -->
?? ?<context:property-placeholder location="classpath:db.properties"/>
?? ?
?? ?<!-- 自動(dòng)掃描 -->
?? ?<context:component-scan base-package="com.spring.trans"></context:component-scan>
?? ?
?? ?<!-- 配置c3p0數(shù)據(jù)源 -->
?? ?<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>
對(duì)應(yīng)的數(shù)據(jù)庫(kù)連接信息文件
jdbc.user=root
jdbc.password=
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///testspring
jdbc.initPoolSize=5
jdbc.maxPoolSize=10
?
最后測(cè)試的結(jié)果是可以對(duì)數(shù)據(jù)庫(kù)進(jìn)行對(duì)應(yīng)的接口操作的,即能修改數(shù)據(jù)庫(kù)的信息,并且異常也會(huì)捕獲,以上都是最基本的Spring對(duì)于數(shù)據(jù)庫(kù)的操作。
那么問題來了,我們上面為了防止書籍的庫(kù)存不足或者用于余額不足的情況進(jìn)行了異常捕獲,但實(shí)際的操作中,是有問題的,比如當(dāng)book_store 表當(dāng)中的某一個(gè)書籍的數(shù)量不等于0,當(dāng)一個(gè)用戶進(jìn)行購(gòu)買的時(shí)候,數(shù)量會(huì)自動(dòng)減1,但是。。。。用戶的余額卻不足以支付這本書的費(fèi)用,那么。上面的代碼就會(huì)造成數(shù)據(jù)庫(kù)中書的庫(kù)存數(shù)量減1,用戶余額沒有減,用戶沒有購(gòu)買成功,庫(kù)存卻減少了,顯然這是不合理的,這是數(shù)據(jù)不同步,數(shù)據(jù)不一致造成的。
因此,在Spring中,Spring的事務(wù)JdbcTemplate對(duì)此有相應(yīng)的支持,提供解決辦法。
首先在配置文件中添加事務(wù)的支持和啟用事務(wù)的注解(因?yàn)槭腔谧⒔獾牟僮?
<!-- 配置事務(wù)管理器-->
?? ?<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
?? ??? ?<property name="dataSource" ref="dataSource"></property>
?? ?</bean>
?? ?
?? ?<!-- 啟用事務(wù)注解 -->
?? ?<tx:annotation-driven transaction-manager="transactionManager"/>
最后在 UserByBookServiceImpl 中添加一個(gè)注解
測(cè)試觀察數(shù)據(jù)庫(kù),即使余額不足,也不會(huì)庫(kù)存減少,當(dāng)然余額更不會(huì)去減少,這就實(shí)現(xiàn)了數(shù)據(jù)的一致和同步性,也體現(xiàn)了事務(wù)的作用。關(guān)于其內(nèi)部的實(shí)現(xiàn),還沒有去研究,但大概也能知道是aop原理下的事務(wù)回滾操作。
轉(zhuǎn)載于:https://my.oschina.net/u/2509896/blog/782845
總結(jié)
以上是生活随笔為你收集整理的Spring4 学习系列之——jdbc事务的基本实现和了解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android--Retrofit+Rx
- 下一篇: oracle 用函数返回对象集合