四个特性 acid
- 原子性
事务涉及到多个操作逻辑上缺一不可, 要成功都成功,失败都失败,都执行或者都不执行 - 一致性
数据的一致性 - 隔离性
事务之间没有影响 - 持久性
commit 之后就永久保存
编程式事务
事务的三个主要方法
connection.setAutocommit(false);//关闭自动提交,开启事务
connection.commit();
connection.rollback;// 回滚
connection.setAutocommit(true);//开启自动提交 关闭事务
AOP 声明式事务管理,将以上方法固定为横切关注点
步骤
创建环境
bean :book user
数据库 :book user
配置xml
<context:property-placeholder location="classpath:druid.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property value="${jdbc.username}" name="username"/>
<property value="${jdbc.password}" name="password"/>
<property value="${jdbc.url}" name="url"/>
<property value="${jdbc.driverClassName}" name="driverClassName"/>
<property value="${jdbc.initialSize}" name="initialSize"/>
<property value="${jdbc.maxActive}" name="maxActive"/>
<property value="${jdbc.maxWait}" name="maxWait"/>
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<context:component-scan base-package="com.spring"></context:component-scan>
编写dao 和 service 层
没有添加事务时
出现的问题
执行俩次
可以买一本书,第二本出现错误,价格40 设置的是非负数 所以报错
当用户账户余额不足时会抛出异常,但是图书的库存却会减去一本
测试类执行俩次
添加事务
- 首先导入jar包
spring-aspects-5.3.1.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar - 配置文件加入
<!--配置数据源属性-->
<!--开启事务注解支持
当事务管理器的id是transactionManager时,可以省略指定transaction-manager属性
-->
<!-- <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"></tx:annotation-driven>
测试后 书的数量不会减少
Transactional 注解
- 可以添加到类上
所有的方法自动添加事务 - 添加到 方法上
方法添加事务 - 设置事务的传播行为
一个事务运行在另一个事务方法中时。当前方法使用新的事务 (第二个事务方法中)原来的不用
没有指定时 就是使用原来的事务
隔离级别
数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。一个事务与其他事务隔离的程度称为隔离级别。SQL标准中规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。
隔离级别一共有四种:
①读未提交:READ UNCOMMITTED
允许Transaction01读取Transaction02未提交的修改。
②读已提交:READ COMMITTED、
要求Transaction01只能读取Transaction02已提交的修改。
③可重复读:REPEATABLE READ
确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其它事务对这个字段进行更新。
④串行化:SERIALIZABLE
确保Transaction01可以多次从一个表中读取到相同的行,在Transaction01执行期间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性能十分低下。
6.4.4 @Transactional注解中的其他属性
1)触发事务回滚的异常
a)默认情况下,捕获到RuntimeException或Error时回滚,而捕获到编译时异常不回滚。
b)@Transactional注解中设置回滚的属性
i.rollbackFor或rollbackForClassName属性:指定遇到时必须进行回滚的异常类型,可以为多个。
ii.noRollbackFor或noRollbackForClassName属性:指定遇到时不回滚的异常类型,可以为多个。
2)事务的超时时间
由于事务可以在行和表上获得锁,因此长事务会占用资源,并对整体性能产生影响。
timeout超时事务属性可以设置事务在强制回滚之前可以保持多久。这样可以防止长期运行的事务占用资源。
3)只读属性
如果一个事务只读取数据但不做修改,数据库引擎可以对这个事务进行优化。
readOnly只读事务属性可以设置这个事务只读取数据但不更新数据, 这样可以帮助数据库引擎优化事务。
基于XML配置
<context:component-scan base-package="com.spring"></context:component-scan>
<context:property-placeholder location="classpath:druid.properties"/>
<!--配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property value="${jdbc.username}" name="username"/>
<property value="${jdbc.password}" name="password"/>
<property value="${jdbc.url}" name="url"/>
<property value="${jdbc.driverClassName}" name="driverClassName"/>
<property value="${jdbc.initialSize}" name="initialSize"/>
<property value="${jdbc.maxActive}" name="maxActive"/>
<property value="${jdbc.maxWait}" name="maxWait"/>
</bean>
<!--配置数据源属性-->
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置事务管理器-->
-<tx:advice id="tx" transaction-manager="transactionManager">
<!--配置添加事务的方法-->
-<tx:attributes>
<!--给所有查询的方法添加事务-->
<tx:method name="get*" read-only="true" isolation="READ_COMMITTED" propagation="REQUIRED"/>
<tx:method name="find*" read-only="true" isolation="READ_COMMITTED" propagation="REQUIRED"/>
<!--给所有的方法添加事务-->
<tx:method name="*" isolation="READ_COMMITTED"/>
<!--给purchase方法添加事务-->
<tx:method name="purchase" isolation="READ_COMMITTED" propagation="REQUIRES_NEW" timeout="3"/>
</tx:attributes>
</tx:advice>
<!--AOP的配置-->
-<aop:config>
<!--配置切入点表达式-->
<aop:pointcut id="pointCut" expression="execution(* com.atguigu.spring.tx.xml.service.BookShopServiceImpl.*(..))"/>
<!--将切入点表达式和添加声明式事务的方法管理起来-->
<aop:advisor pointcut-ref="pointCut" advice-ref="tx"/>
</aop:config>