什么是事物?
![在这里插入图片描述](https://img-blog.csdnimg.cn/2019030512323766.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
事物管理问题
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305123758125.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
Spring中的事务管理
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305124654876.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
事务管理器
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305124712279.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
示例:进行事务控制案例
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305124832818.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
drop table book ;
drop table book_stock;
drop table account;
create table book
(
isbn int primary key,
book_name varchar(100),
price double
);
create table book_stock
(
isbn int primary key,
stock int,
check (stock > 0)
);
create table account
(
uid int primary key,
username varchar(50) ,
balance double,
check (balance > 0)
);
- Book
public class Book {
private Integer isban;
private String bookName;
private Double price;
}
- BookStock
public class BookStock {
private Integer isbn;
private Integer stock;
}
- Account
public class Account {
private Integer uid;
private String username;
private String balance;
}
package mao.shu.spring.jdbc.transaction.dao;
public interface BookShop {
public double findPriceByisban(Integer isban);
public boolean updateBookStock(Integer isbn,Integer number);
public boolean updateAccount(Integer uid,Double consumption);
}
- 定义BookShopImpl实现BookShop接口
- 使用Spring的JdbcTemplate操作对象完成
package mao.shu.spring.jdbc.transaction.dao.impl;
import mao.shu.spring.jdbc.transaction.dao.BookShop;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class BookShopImpl implements BookShop {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public double findPriceByisban(Integer isbn) {
String sql = "SELECT price FROM book WHERE isbn=?";
Double price = this.jdbcTemplate.queryForObject(sql, new Object[]{isbn}, Double.class);
return price;
}
@Override
public boolean updateBookStock(Integer isbn, Integer number) {
if (this.getStockByisbn(isbn) > 0) {
String sql = "UPDATE book_stock SET stock=stock + ? WHERE isbn=?";
return this.jdbcTemplate.update(sql, number, isbn) > 0;
} else {
try {
throw new Exception("库存不足");
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
@Override
public boolean updateAccount(Integer uid, Double consumption) {
if (this.getAccountBalance(uid)>=consumption){
String sql = "UPDATE account SET balance=balance-? WHERE uid=?";
return this.jdbcTemplate.update(sql,consumption,uid) > 0;
}
return false;
}
public Integer getStockByisbn(Integer isbn) {
String sql = "SELECT stock FROM book_stock WHERE isbn=?";
Integer stock = this.jdbcTemplate.queryForObject(sql, new Object[]{isbn}, Integer.class);
return stock;
}
public Double getAccountBalance(Integer uid) {
String sql = "SELECT balance FROM account WHERE uid=?";
Double balance = this.jdbcTemplate.queryForObject(sql, new Object[]{uid}, Double.class);
return balance;
}
}
package mao.shu.spring.jdbc.transaction.dao.impl;
import mao.shu.spring.jdbc.transaction.dao.BookShop;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import static org.junit.Assert.*;
public class BookShopImplTest {
private ApplicationContext app ;
private BookShop bookShop;
@Before
public void before(){
this.app = new ClassPathXmlApplicationContext("mao/shu/spring/jdbc/transaction/transaction.xml");
this.bookShop = this.app.getBean("bookShopImpl",BookShopImpl.class);
}
@Test
public void findPriceByisban() {
Double price = this.bookShop.findPriceByisban(3);
System.out.println(price);
}
@Test
public void updateBookStock() {
this.bookShop.updateBookStock(1,-1);
}
@Test
public void updateAccount() {
this.bookShop.updateAccount(1,-1900.5);
}
}
package mao.shu.spring.jdbc.transaction.vo;
public interface ShopService {
public boolean purchase(Integer uid,Integer isbn);
}
- 定义ShopServiceImpl类时心啊ShopService接口
package mao.shu.spring.jdbc.transaction.service;
import mao.shu.spring.jdbc.transaction.dao.BookShop;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ShopServiceImpl implements ShopService {
@Autowired
private BookShop bookShop;
@Override
public boolean purchase(Integer uid, Integer isbn) {
double price = this.bookShop.findPriceByisban(isbn);
if (this.bookShop.updateAccount(uid,price)){
return this.bookShop.updateBookStock(isbn,-1);
}
return false;
}
}
package mao.shu.spring.jdbc.transaction.service;
import mao.shu.spring.jdbc.transaction.dao.BookShop;
import mao.shu.spring.jdbc.transaction.dao.impl.BookShopImpl;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import static org.junit.Assert.*;
public class ShopServiceImplTest {
private ApplicationContext app ;
private ShopService shop;
@Before
public void before(){
this.app = new ClassPathXmlApplicationContext("mao/shu/spring/jdbc/transaction/transaction.xml");
this.shop = this.app.getBean("shopServiceImpl", ShopService.class);
}
@Test
public void purchase() {
this.shop.purchase(1,1);
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305144640347.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305144713389.png)
使用事务控制
- 声明事务控制的时候需要 aspectjweaver-1.5.2 的jar包支持
- xml文件的方式配置
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305144832736.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305144948496.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
用 @Transactional 注解声明式地管理事务
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305150524351.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<aop:config proxy-target-class="true"></aop:config>
<context:component-scan base-package="mao.shu.spring.jdbc.transaction"/>
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${user}"/>
<property name="password" value="${password}"/>
<property name="driverClass" value="${driver}"/>
<property name="jdbcUrl" value="${url}"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg type="javax.sql.DataSource" ref="dataSource"/>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
- 在ShopServiceImpl 类中的purchase()方法上声明事务管理
@Transactional
@Override
public boolean purchase(Integer uid, Integer isbn) {
double price = this.bookShop.findPriceByisban(isbn);
if (this.bookShop.updateAccount(uid,price)){
return this.bookShop.updateBookStock(isbn,-1);
}
return false;
}
package mao.shu.spring.jdbc.transaction.service;
import mao.shu.spring.jdbc.transaction.dao.BookShop;
import mao.shu.spring.jdbc.transaction.dao.impl.BookShopImpl;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import static org.junit.Assert.*;
public class ShopServiceImplTest {
private ApplicationContext app ;
private ShopService shop;
@Before
public void before(){
this.app = new ClassPathXmlApplicationContext("mao/shu/spring/jdbc/transaction/transaction.xml");
this.shop = this.app.getBean("shopServiceImpl", ShopService.class);
}
@Test
public void purchase() {
this.shop.purchase(1,1);
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305150046742.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305150150923.png)
事务的传播属性
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305170200823.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
- 事务传播属性可以在 @Transactional 注解的 propagation 属性中定义
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305172507658.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/2019030517022343.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
示例:定义事务传播属性
![在这里插入图片描述](https://img-blog.csdnimg.cn/2019030517035217.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
package mao.shu.spring.jdbc.transaction.service;
import java.util.List;
public interface Cashier {
public boolean checkout(Integer uid, List<Integer> isbns);
}
@Controller
public class CashierImpl implements Cashier {
@Autowired
private ShopService shopService;
@Transactional(propagation= Propagation.REQUIRED)
@Override
public boolean checkout(Integer uid, List<Integer> isbns) {
for (Integer isbn: isbns){
if(!this.shopService.purchase(uid,isbn)){
return false;
}
}
return true;
}
}
- 测试checkout()方法,为账户设置购买两本书的余额,在使用checkout()方法的时候让账户购买2本书,观察数据是否会变化
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305171634356.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305171650818.png)
@Test
public void checkout() {
Cashier cashier = this.app.getBean("cashierImpl",Cashier.class);
List<Integer> isbns = new ArrayList<>();
isbns.add(1);
isbns.add(1);
isbns.add(1);
cashier.checkout(1,isbns);
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305172258842.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
- 数据库中的数据没有发生变化,这是因为"REQUIRED"的事物传播属性,默认情况下多个方法公用一个事务控制,要么全部通过,要么全部失败
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305180602368.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305180740768.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
REQUIRES_NEW 传播行为
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305180817399.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public boolean purchase(Integer uid, Integer isbn) {
double price = this.bookShop.findPriceByisban(isbn);
if (this.bookShop.updateAccount(uid,price)){
return this.bookShop.updateBookStock(isbn,-1);
}
return false;
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305184126471.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305184146461.png)
事务的隔离级别
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305195101696.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305195209492.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
Spring支持的事务隔离级别
![在这里插入图片描述](https://img-blog.csdnimg.cn/2019030519542833.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
在Spring4注解中设置隔离级别
- 在使用@Transactional注解声明式管理事务时可以在注解中使用"isolattion"属性控制事务级别
@Transactional(propagation = Propagation.REQUIRES_NEW,
isolation = Isolation.READ_COMMITTED)READ_COMMITTED
@Override
public boolean purchase(Integer uid, Integer isbn) {
double price = this.bookShop.findPriceByisban(isbn);
if (this.bookShop.updateAccount(uid,price)){
return this.bookShop.updateBookStock(isbn,-1);
}
return false;
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305200352411.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
回滚事务属性
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305200524124.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
@Transactional(propagation = Propagation.REQUIRES_NEW,
isolation = Isolation.READ_COMMITTED,
rollbackFor = SQLException.class)
@Override
public boolean purchase(Integer uid, Integer isbn) {
double price = this.bookShop.findPriceByisban(isbn);
if (this.bookShop.updateAccount(uid,price)){
return this.bookShop.updateBookStock(isbn,-1);
}
return false;
}
超时和只读属性
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305201001237.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305201831288.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
- 示例:定义超时事务属性
- 超时事务属性可以在"@Transactional"标签中使用timeOut 属性定义,以秒最为单位
@Transactional(propagation = Propagation.REQUIRES_NEW,
isolation = Isolation.READ_COMMITTED,
rollbackFor = SQLException.class,
timeout = 2)
@Override
public boolean purchase(Integer uid, Integer isbn) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
double price = this.bookShop.findPriceByisban(isbn);
if (this.bookShop.updateAccount(uid,price)){
return this.bookShop.updateBookStock(isbn,-1);
}
return false;
}
@Transactional(readOnly = true)
@Override
public boolean purchase(Integer uid, Integer isbn) {
double price = this.bookShop.findPriceByisban(isbn);
if (this.bookShop.updateAccount(uid,price)){
return this.bookShop.updateBookStock(isbn,-1);
}
return false;
}
- 如果设置了只读,但是缺使用了更新语句,会出现以下的异常
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305202147713.png)
使用xml文件配置事务
- 如果使用xml文件的方式注入类的实例,需要为类中的实例设置setter()方法
- 使用xml文件的方式配置事务,步骤如下
- 配置事务管理器
- 配置事务属性:定义事务传播,隔离级别,回滚,只读等
- 配置事务切入点:以切入点表达式的方式指定哪些类中的方法需要事务控制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${user}"/>
<property name="password" value="${password}"/>
<property name="driverClass" value="${driver}"/>
<property name="jdbcUrl" value="${url}"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg type="javax.sql.DataSource" ref="dataSource"/>
</bean>
<bean id="bookShop" class="mao.shu.spring.jdbc.transactionXml.dao.impl.BookShopImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="shopService" class="mao.shu.spring.jdbc.transactionXml.service.impl.ShopServiceImpl">
<property name="bookShop" ref="bookShop"/>
</bean>
<bean id="" class="mao.shu.spring.jdbc.transactionXml.service.impl.CashierImpl">
<property name="shopService" ref="shopService"/>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="checkout" propagation="REQUIRED"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* mao.shu.spring.jdbc.transactionXml.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
</beans>
package mao.shu.spring.jdbc.transactionXml.service.impl;
import mao.shu.spring.jdbc.transactionXml.service.Cashier;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.*;
public class CashierImplTest {
private ApplicationContext app ;
@Before
public void before(){
this.app = new ClassPathXmlApplicationContext("mao/shu/spring/jdbc/transactionXml/transaction-xml.xml");
}
@Test
public void checkout() {
Cashier cashier = this.app.getBean("cashier",Cashier.class);
List<Integer> isbns = new ArrayList<>();
isbns.add(1);
isbns.add(1);
isbns.add(1);
cashier.checkout(1,isbns);
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305222808846.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzg2NzU0,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190305222832386.png)