基于注解的声明式事务实现事务功能
在没有使用Spring框架之前,通过编程式事务实现事务的管理即自己写代码实现功能。而使用框架我们可以通过配置让框架实现功能即声明式事务管理
1.编程式事务的概念
事务功能的相关操作全部通过自己编写代码来实现。存在的缺陷:细节没有被屏蔽:具体操作过程中,所有细节都需要程序员自己来完成,比较繁琐;代码复用性不高:如果没有有效抽取出来,每次实现功能都需要自己编写代码,代码就没有得到复用。
1.声明式事务的概念
既然事务控制的代码有规律可循,代码的结构基本是确定的,所以框架就可以将固定模式的代码抽取出来,进行相关的封装。封装起来后,我们只需要在配置文件中进行简单的配置即可完成操作。
它的优点:提高开发效率;消除了冗余的代码;框架会综合考虑相关领域中在实际开发环境下有可能遇到的各种问题,进行了健壮性、性能等各个方面的优化
3.声明式事务的配置步骤;
1.在spring的配置文件中配置事务管理器
2.开启事务的注解驱动
在需要被事务管理的方法上添加@Transactional注解,该方法就会被事务管理
@Transactional注解标识的位置:
1、标识在方法上
2、标识在类上,该类中所有的方法都会被事务管理
代码流程如下:
我们构建一个买书的场景,来体现功能
@Controller
public class BookController {
@Autowired
private BookService bookService;
@Autowired
private CheckoutService checkoutService;
public void buyBook(Integer userId, Integer bookId){
bookService.buyBook(userId,bookId);
}
public interface BookService {
//买书方法
void buyBook(Integer userId, Integer bookId);
}
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
@Override
@Transactional(
//readOnly = true
//timeout = 3
//noRollbackFor = ArithmeticException.class
//noRollbackForClassName = "java.lang.ArithmeticException"
//isolation = Isolation.DEFAULT
propagation = Propagation.REQUIRES_NEW
)
public void buyBook(Integer userId, Integer bookId) {
//查询图书的价格
Integer price = bookDao.getPriceByBookId(bookId);
//更新图书的库存
bookDao.updateStock(bookId);
//更新用户的余额
bookDao.updateBalance(userId,price);
//System.out.println(1/0);
}
}
public interface BookDao {
//根据图书的id查询图书的价格
Integer getPriceByBookId(Integer bookId);
//更新图书的库存
void updateStock(Integer bookId);
//更新用户的余额
void updateBalance(Integer userId, Integer price);
}
@Repository
public class BookDaoImpl implements BookDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public Integer getPriceByBookId(Integer bookId) {
String sql = "select price from t_book where book_id = ?";
return jdbcTemplate.queryForObject(sql,Integer.class,bookId);
}
@Override
public void updateStock(Integer bookId) {
String sql = "update t_book set stock = stock - 1 where book_id = ?";
jdbcTemplate.update(sql,bookId);
}
@Override
public void updateBalance(Integer userId, Integer price) {
String sql = "update t_user set balance = balance - ? where user_id = ?";
jdbcTemplate.update(sql,price,userId);
}
}
<?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.qcw.spring"></context:component-scan>
<!--引入jdbc.properties-->
<context:property-placeholder location="jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--
开启事务的注解驱动,将使用@Transactional注解所标识的方法或类中所有的方法使用事务进行管理
transaction-manager属性设置事务管理器的id
若事务管理器的bean的id默认为transactionManager,则该属性可以省略不写
-->
<!--开启事务的注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
package com.qcw.spring.test;
import com.qcw.spring.controller.BookController;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
*声明式事务的配置步骤;
* 1.在spring的配置文件中配置事务管理器
* 2.开启事务的注解驱动
* 在需要被事务管理的方法上添加@Transactional注解,该方法就会被事务管理
* @Transactional注解标识的位置:
* 1、标识在方法上
* 2、标识在类上,该类中所有的方法都会被事务管理
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:tx-annotation.xml")
public class TxByAnnotationTest {
@Autowired
private BookController bookController;
@Test
public void testBuyBook(){
bookController.buyBook(1,1);
}
}