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原理下的事务回滚操做。