目录架构
/**
* @Author:
* @Date:2021/3/31 16:12
* @Decription:
*
* transactional : 方法 优先级 于类
* 事务的定义:
*/
@Service
public class BuyCarsServiceImpl implements BuyCarsService {
@Autowired
private BuyCarsDao buyCarsDao;
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED,
noRollbackFor = {UserMoneyException.class}, timeout = 2)
public void buyCar(String userName, Integer carId) {
try {
System.out.println("开始:" + new Date());
Thread.sleep(3000);
System.out.println("结束:" + new Date());
} catch (Exception e){
e.printStackTrace();
}
// 查询当前购买的汽车的价格
Integer carPrice = buyCarsDao.getPriceByCarid(carId);
// 扣减库存
buyCarsDao.subCarsStock(carId);
// 扣减余额
buyCarsDao.subUserLeftMoney(userName, carPrice);
System.out.println("用户:" + userName + ", 购买汽车:" + (carId == 1 ? "AudiA4" : "Bmw325") + ", 成功!!!");
}
}
spring.xml中配置
<!-- 组件扫描 -->
<context:component-scan base-package="com.zhou.tx"/>
<!-- 数据源配置 -->
<context:property-placeholder location="jdbc-tx.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${mysql.driver}"/>
<property name="jdbcUrl" value="${mysql.url}"/>
<property name="user" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
</bean>
<!-- spring的轻量级持久层框架 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 需要关联数据源 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置数据源 事务管理器 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 开启事务注解扫描 -->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager" />
*
* 事务的特性:ACID
* 1)原子性A :原子即不可再分,表现:一个事务涉及的多个操作在业务逻辑上缺一不可,保证同一个事务中的操作要不都提交,要不都不提交
* 2)一致性C :数据的一致性,一个事务中,不管涉及到多少个操作,都必须保证数据提交的正确性(一致),即:如果在事务数据处理中,有一个或者几个操作失败,必须回退所有的数据操作,恢复到事务处理之前的统一状态
* 3)隔离性I :程序运行过程中,事务是并发执行的,要求每个事务之间都是隔离的,互不干扰
* 4)持久性D :事务处理结束,要讲数据进行持久操作,即永久保存。
*
* 事务的分类:
* 1)编程式事务-使用jdbc原生的事务处理,可以将事务处理写在业务逻辑代码中,违背aop原则,不推荐
* 2)声明式事务-使用事务注解@Transactional,可以声明在方法上,也可以声明在类上
* 优先级:声明在类上,会对当前类内的所有方式生效(所有方法都有事务处理)
* 声明在方法上,只会对当前方法生效,当类上和方法上同时存在,方法的优先级高于类
*
* 事务的属性:
* 1)事务的传播行为:propagation属性指定
* 当一个带事务的方法被另一个带事务的方法调用时,当前事务如何处理:
* propagation = Propagation.REQUIRED : 默认值,使用调用者的事务(全程就一个事务)
* propagation = Propagation.REQUIRES_NEW : 将调用者的事务直接挂起,自己重开新的事务处理,结束提交事务,失败回滚
*
* 2)事务的隔离级别:isolation属性指定隔离级别,只有InnoDB支持事务,所有这里说的事务隔离级别指的是InnoDB下的事务隔离级别。
* 1 读未提交 读取其它事务未提交的数据,了解,基本不会使用
* 2 读已提交 oracle的默认事务隔离级别,同一个事务处理中,只能读取其它事务提交后的数据(也就是说事务提交之前对其余事务不可见)
* 3 可重复读 : mysql默认事务隔离级别,同一个事务处理中,多次读取同一数据是都是一样的,不受其它事务影响
* 4 串行化 可以避免上面所有并发问题,但是执行效率最低,数据一致性最高
*
* 3)事务的指定回滚和不会滚:Spring在默认的情况下,是对所有的运行时异常会执行事务回滚
* 1 rollbackFor : 指定回滚异常,只有产生了指定的异常类型,才会回滚事务
* 2 noRollbackFor : 指定不会滚异常,产生了指定的异常类型,也不会回滚事务
*
* 4)事务的超时时长
* timeout,指定事务出现异常,没有及时回滚,单位是秒,防止事务超时,占用资源
*
* 5)事务的只读
* readOnly=false,默认,可读可写
* readOnly=true,代表该事务处理,理论上只允许读取,不能修改(只是通知spring,并不是一个强制选项)
* 目的就是:提示数据库驱动程序和数据库系统,这个事务并不包含更改数据的操作,那么JDBC驱动程序和数据库就有可能根据这种情况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。
* 但是你非要在“只读事务”里面修改数据,也并非不可以,只不过对于数据一致性的保护不像“读写事务”那样保险而已。
*
*/