之前的博客讲述了,为什么要有事务?https://blog.csdn.net/qq_37591637/article/details/85207922
现在呢?就在原有的基础上怎么添加事务,使得整个过程只要有一个地方出问题就失败,整个过程的成功才叫成功!
换句话说,如果书的库存够,账户余额不够的话,这个过程就失败,数据库里面的库存和余额都不会减少!
1.在xml文件中配置
红笔标注的颜色都是不可以更改的!固定的模板
<!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"></property>
</bean>
<!-- 使得事务注解生效 -->
<tx:annotation-driven transaction-manager="transactionManager" />
在原来的方法上面只要申明 @Transactional就可以了
package cn.com.day04;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service("bookShopService")
public class BookShopServiceImpl implements BookShopService{
@Autowired
private BookShopDaoImpl bookShopDaoImpl;
@Transactional
public void purchase(String username, String isbn) {
//1.根据书的编号来查询价格
int price=bookShopDaoImpl.findBookPriceByIsbn(isbn);
//2.更新书的库存
bookShopDaoImpl.updateBookStock(isbn);
//2.根据用户名查询余额,扣除书的价格
bookShopDaoImpl.updateUserAccount(username, price);
}
}
可是新的问题又来了,如果一个客户去买两本书,或者是更多的书籍呢?
如果一本是是80元,一本书是30元,可是账户余额里面只有100元的话,还能买成么》
这个就涉及到了事务的传播行为......
代码如下
一个接口类(根据用户名,书的编号的集合来模拟实现买书的时候库存和账户余额的变化)
package cn.com.day04;
import java.util.List;
public interface BookShopList {
public void purchare(String name,List<String> isbns);
}
实现类
package cn.com.day04;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service("bookShopList")
public class BookShopListImpl implements BookShopList {
@Autowired
private BookShopService BookShopServiceImpl;
@Transactional
public void purchare(String name, List<String> isbns) {
//一个事务里面包含多个同样运行流程的事务,是继续使用之前的事务还是创建一个新的事务
for (String isbn : isbns) {
BookShopServiceImpl.purchase(name, isbn);
}
}
}
测试类
package cn.com.day04;
import java.util.Arrays;
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;
private static BookShopService bookShopServiceImpl=null;
private static BookShopList bookShop=null;
static {
ioc = new ClassPathXmlApplicationContext("bean-jdbc.xml");
/* bookShopDaoImpl = ioc.getBean(BookShopDaoImpl.class);
bookShopServiceImpl=ioc.getBean(BookShopService.class);*/
bookShop=ioc.getBean(BookShopList.class);
}
public void test1() {
System.out.println(bookShopDaoImpl.findBookPriceByIsbn("1002"));
}
public void test2() {
bookShopDaoImpl.updateBookStock("1001");
}
public void test3() {
bookShopDaoImpl.updateUserAccount("杨枫述", 28);
}
public void test4(){
bookShopServiceImpl.purchase("杨枫述", "1003");
}
@Test
public void test5(){
bookShop.purchare("杨枫述", Arrays.asList("1002","1001"));
}
}
默认的情况下,@Transactional(propagation=Propagation.REQUIRES)
条件:
账户余额:100元
第一本书:40元;
第二本书:70元;
结果就是,结果就是,库存都不会变化,余额是100;
默认的情况下,@Transactional(propagation=Propagation.REQUIRES)
条件:
账户余额:100元
第一本书:70元;
第二本书:40元;
结果就是,结果就是,库存都不会变化,余额是100;
如果给设置 @Transactional(propagation=Propagation.REQUIRES_NEW)
条件:
账户余额:100元
第一本书:40元;
第二本书:70元;
结果就是,第一本书的库存减少1,余额是60;
如果给设置 @Transactional(propagation=Propagation.REQUIRES_NEW)
条件:
账户余额:100元
第一本书:70元;
第二本书:40元;
结果就是,库存都不会变化,余额是100;
@Transactional(propagation=Propagation.REQUIRES_NEW)的好处就是
当你执行第一个小的事务的时候,如果成功了,执行第二个,如果第二个失败了,就会返回到第二个的最开始的地方;
但是如果你执行第一个小的事务都失败了,就直接回滚到事务最开始的时候