Spring-04 声明式事务
1、事务的定义
事务就是由一组逻辑上紧密关联的多个工作单元(数据库操作)而合并成一个整体,这些操作要么都执行,要么都不执行。
2、事务的特性:ACID
1)原子性A :原子即不可再分,表现:一个事务涉及的多个操作在业务逻辑上缺一不可,保证同一个事务中的操作要不都提交,要不都不提交;
2)一致性C :数据的一致性,一个事务中,不管涉及到多少个操作,都必须保证数据提交的正确性(一致);即:如果在事务数据处理中,有一个或者几个操作失败,必须回退所有的数据操作,恢复到事务处理之前的统一状态;
3)隔离性I :程序运行过程中,事务是并发执行的,要求每个事务之间都是隔离的,互不干扰;
4)持久性D :事务处理结束,要将数据进行持久操作,即永久保存。
3、事务的分类:
1)编程式事务-使用jdbc原生的事务处理,可以将事务处理写在业务逻辑代码中,违背aop原则,不推荐;
2)声明式事务-使用事务注解 @Transactional,可以声明在方法上,也可以声明在类上;
- **优先级**:
- * <mark>声明在**类上**,会对**当前类内的所有方式生效**(所有方法都有事务处理);</mark>
- * <mark>声明在**方法上**,只会**对当前方法生效**,当类上和方法上同时存在,**方法的优先级高于类**(有些方法,对声明式事务做特殊属性配置);</mark>
复制代码 4、事务的属性:
4.1 事务的传播行为:propagation属性
事务的传播行为:propagation 属性指定;
当一个带事务的方法被另一个带事务的方法调用时(事务嵌套),当前事务如何处理:
- propagation = Propagation.REQUIRED :
- 默认值,使用调用者的事务(全程就一个事务,如果有事务嵌套,以外部事务为主);
- propagation = Propagation.REQUIRES_NEW :
- 将调用者的事务直接挂起,自己重开新的事务处理,结束提交事务,失败回滚;(当事务嵌套时,内层事务,会重新开启新事务的处理,不受外部事务的管理);
4.2 事务的隔离级别:isolation属性
事务的隔离级别:isolation属性指定隔离级别,只有InnoDB支持事务,所有这里说的事务隔离级别指的是InnoDB下的事务隔离级别。
1、读未提交 : 读取其它事务未提交的数据,了解,基本不会使用;
2、读已提交 : oracle的默认事务隔离级别,同一个事务处理中,只能读取其它事务提交后的数据(也就是说事务提交之前对其余事务不可见);
3、可重复读 : mysql默认事务隔离级别,同一个事务处理中,多次读取同一数据是都是一样的,不受其它事务影响;
4、串行化 : 可以避免上面所有并发问题,但是执行效率最低,数据一致性最高;
4.3 事务的指定回滚和不会滚
事务的指定回滚和不会滚:Spring在默认的情况下,是对所有的运行时异常会执行事务回滚
1、 rollbackFor : 指定回滚异常,只有产生了指定的异常类型,才会回滚事务;
2、 noRollbackFor : 指定不会滚异常,产生了指定的异常类型,也不会回滚事务;
4.4 事务的超时时长-了解
1、timeout,指定事务出现异常,没有及时回滚,单位是秒,防止事务超时,占用资源;
4.5 事务的只读-了解
1、readOnly=false,默认,可读可写‘;
2、readOnly=true,代表该事务处理,理论上只允许读取,不能修改(只是通知spring,并不是一个强制选项)
目的就是:提示数据库驱动程序和数据库系统,这个事务并不包含更改数据的操作,那么JDBC驱动程序和数据库就有可能根据这种情况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。
但是你非要在“只读事务”里面修改数据,也并非不可以,只不过对于数据一致性的保护不像“读写事务”那样保险而已。
5、 环境搭建
5.1主要 jar包
- <spring.version>4.3.18.RELEASE</spring.version>
- <mysql.version>5.1.47</mysql.version>
- <c3p0.version>0.9.5.2</c3p0.version>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-jdbc</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-orm</artifactId>
- <version>${spring.version}</version>
- </dependency>
-
- <dependency>
- <groupId>com.mchange</groupId>
- <artifactId>c3p0</artifactId>
- <version>${c3p0.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-tx</artifactId>
- <version>${spring.version}</version>
- </dependency>
-
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>${mysql.version}</version>
- </dependency>
复制代码 5.2 配置文件
- <?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 http://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.kgc.spring"></context:component-scan>
-
-
- <bean >
-
- <property name="location" value="classpath:jdbc.properties"></property>
- </bean>
-
- <bean id="dataSource" >
- <property name="driverClass" value="${driver}"></property>
- <property name="jdbcUrl" value="${url}"></property>
- <property name="user" value="${username}"></property>
- <property name="password" value="${password}"></property>
- </bean>
-
- <bean id="jdbcTemplate" >
- <property name="dataSource" ref="dataSource"></property>
- </bean>
-
- <bean id="dataSourceTransactionManager" >
- <property name="dataSource" ref="dataSource"></property>
- </bean>
-
- <tx:annotation-driven transaction-manager="dataSourceTransactionManager"></tx:annotation-driven>
复制代码 6、测试
5.1 购买一辆车(没有事务嵌套)
TES 购买一辆 AudiQ5;
模拟购买一辆车,主要流程:(1,2,3 整体是一个事务)
1、据买家购买汽车编号,获取汽车详情;
2、扣汽车的库存
3、扣买家的余额
5.1.2 主要业务代码
5.1.2.1 扣用户余额业务
BuyerServiceImpl
如果买家余额不足,直接返回;- @Service
- public class BuyerServiceImpl implements BuyerService {
- @Autowired
- private BuyerDao buyerDao;
- @Override
- public void subBuyerMoneyByName(String buyerName, Car car) {
- // 根据买家姓名,查询买家详情
- Buyer buyer = buyerDao.selectBuyerByName(buyerName);
- // 判断买家余额是否充足,如果不足,不能继续扣减金额
- if(buyer.getMoney() < car.getPrice()){
- System.out.println(String.format("****** 买家:%s,余额不足! ------", buyerName));
- return; //直接return
- }
- // 余额充足,执行扣减余额
- int row = buyerDao.updateBuyerMoneyById(buyer.getId(), car.getPrice());
- System.out.println(String.format("****** 买家:%s,余额扣减成功,影响行数:%s ------", buyerName, row));
- }
- }
复制代码 5.1.2.2 扣库存业务
CarsStockServiceImpl
如果库存不足,直接返回;
[code]@Servicepublic class CarsStockServiceImpl implements CarsStockService { @Autowired private CarsStockDao carsStockDao; @Override public void subCarsStockBuyId(Car car) { //根据汽车编号,插叙汽车详情 CarsStock carsStock = carsStockDao.selectCarsStockByCid(car.getId()); //判断库存是否充足,如果不足,不能购买 if(carsStock.getStock() |