SpringAop的事务及其实例
事务的特性(ACID)
(1)原子性(Atomicity): 事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
(2)一致性(Consistency): 事务开始前和结束后,数据库的完整性约束没有被破坏。比如A向B转账,不可能A扣了钱,B却没收到。
(3)隔离性(Isolation): 同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
(4) 持久性(Durability): 事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。
(1)配置pom.xml
引入spring-aspects依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!--切面依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.18</version>
</dependency>
</dependencies>
(2)application.xml
默认为transactionManager,以下是事务的配置
<!--默认为transactionManager-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
以下是application.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: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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 包扫描-->
<context:component-scan base-package="com.zz.service"/>
<!-- -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/book_manager"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" >
<property name="basePackage" value="com.zz.dao"/>
</bean>
<!--默认为transactionManager-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
(3)BookShopDao
public interface BookShopDao {
// 跟isbn查询图书的价格
int findPriceByIsdn(String isbn);
// 修改库存
int updateStock(String isbn);
// 根据用户姓名修改个人金额
int updateAccountBanlan(@Param("username")String username, @Param("balance")int balance);
// 查询个人的余额醋
int selectBalance(String username);
// 根据图书编号查询图书的库存
int selectStock(String isbn);
}
(4)BookService
public interface BookService {
//下订单
void purchase(String username,String isbn);
}
(5)BookServiceImpl
注意事项
@Transactional 注解必须添加在public方法上,private、protected方法上是无效的
以下案例有关下订单,
①先查询图书的价格
②修改库存
③修改金额
@Service
public class BookServiceImpl implements BookService{
@Autowired
private BookShopDao bookShopDao;
@Override
@Transactional//事务注解
public void purchase(String username, String isbn) {
// 先查询图书的价格
int price = bookShopDao.findPriceByIsdn(isbn);
// 先判断库存是否不足
int i = bookShopDao.selectStock(isbn);
if (i>0){
// 修改库存
bookShopDao.updateStock(isbn);
}else {
throw new RuntimeException("库存不足");
}
//先查询金额是否充足 看金额是否大于图书价格
int balance = bookShopDao.selectBalance(username);
if (balance>price){
// 修改金额
bookShopDao.updateAccountBanlan(username,balance);
}else {
throw new RuntimeException("账户金额不足,请充值");
}
}
}
(5)Demo
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
BookService bookServiceImpl = (BookService) context.getBean("bookServiceImpl");
bookServiceImpl.purchase("ykq", "1002");
}
(6)实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book_stock implements Serializable {
private String isbn;
private int stock;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book implements Serializable {
private String isbn;
private String book_name;
private String price;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Account implements Serializable {
private String username;
private Integer balance;
}