事物管理是企业级应用程序开发中必不可少技术,用来保证数据的完整性和一致性
Spring 在不同的事物管理Api之间定义了一个抽象层
声明式的事务管理
将事物管理代码从业务方法中分离出来 , 以声明的方式来实现事物的管理
事物管理作为一个横切关注点;可以通过AOP方法模块化
Spring将通过SpringAOP框架支持声明式事物管理
在程序中 要处理一个数据元 而且通过JDBC存取 DateSource TransactionManager
在JavaEE 应用服务其上 用JTA进行事物的管理
一、完成买书的事物 将 1 书的价格/2、 书的库存/3 、账户余额/ 封装为事物
确保事物的完整性和一致性 要不全部成功要不全部失败回滚
<context:component-scan base-package="com.Greatest.Spring"></context:component-scan>
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${user}"></property>
<property name="password" value="${password}"></property>
<property name="jdbcUrl" value="${jdbcUrl}"></property>
<property name="driverClass" value="${driverClass}"></property>
<property name="initialPoolSize" value="${initialPoolSize}"></property>
<property name="maxPoolSize" value="${maxPoolSize}"></property>
</bean>
<bean id="Jdbctempldate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="datasource"></constructor-arg>
</bean>
<!--配置事务管理器 需要插入数据源 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="datasource"></constructor-arg>
</bean>
<!--开启组件管理 与AOP相结合 取代@Transaction 被事务管理-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<tx:advice id="bookShopTxadvice" transaction-manager="transactionManager" >
<tx:attributes>
<tx:method name="checkout" read-only="true"/>
<tx:method name="byBook" no-rollback-for="com.Greatest.Spring.Exception.StockException" read-only="true"
propagation="REQUIRES_NEW"/>
</tx:attributes>
</tx:advice>
<!--配置事物切点 并把切点和事物属性关联起来 -->
<aop:config>
<aop:pointcut expression="execution(* com.Greatest.Spring.*.*(..))" id="point"/>
<aop:advisor advice-ref="bookShopTxadvice" pointcut-ref="point" />
</aop:config>
(1)类
@Service 使其可以被管理
@Transaction事务管理 可以加属性(propagation=propagation-REQUIRES_NEW 当前方法必须启动新的事物 尤其他事物则挂起 。。。isolation=读已提交,noRllbackFor=跳过的异常StockException.class ,readonly=true(只读) timeout=3(超时属性 单位 秒 )
@Transactional(//propagation=Propagation.REQUIRES_NEW,
isolation=Isolation.READ_COMMITTED,
//noRollbackFor=StockException.class,
// readOnly=true,//.超时属性以秒为单位来计算.
timeout=30))
@Autowried
private BookServlet bookServlet //实现具体的三各方法
public void byBook(String username ,String isbn){
double price=bookServlet.FinbookPrice(isbn);//根据书号获书数的价格
bookServlet.updateStock(isbn);//获取书的库存
bookServlet.updatebalance(username,isbn)//获取账户余额
}
买跟多的书 把上述方法封装进一个事务
@Autowried
private byBookServlet bybookservlet;
@Transaction
public void checkout(String username ,List<String> isbns){
for(Stirng isbn:isbns){
bybookServlet.Bybook(username,isbn);}
}
(2)具体方法
Mysql中没有check约束 在代码中加异常防止负数
int stock = jdbctemplate.queryForObjrct("select stock from Stocks where isbn=?",Integer.calss,isbn);
if(stock==0){
throw new StockException("库存数不足!!!");
判断余额 balance < price
具体:
@Autowired
private JdbcTemplate jdbctemplate;
@Override
public double finbookPrice(String isbn) {
String sql="select price from books where isbn=?";
return jdbctemplate.queryForObject( sql, Double.class, isbn);
}
@Override
public void updateStock(String isbn) {
int stock=jdbctemplate.queryForObject("select Stock from stocks where isbn=?", Integer.class, isbn);
if(stock==0 ){
throw new StockException();
}
String sql="update stocks set Stock=Stock-? where isbn=?";
jdbctemplate.update(sql, 1,isbn);
}
@Override
public void updatebalance(String username,double price) {
double balance=jdbctemplate.queryForObject("select balance from userbalance where username=?", Double.class, username);
if(balance<price){
throw new UserPriceexception();
}
String sql="update userbalance set balance=balance-? where username=?";
jdbctemplate.update(sql, price ,username);
}