持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情
Spring声明式事务管理属性
@Transactional注解属性
事务传播行为【Propagation】
-
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。
-
Propagation常用属性:
REQUIRED传播行为:当 bookService 的 purchase()方法被另一个事务方法 checkout()调用时,它默认会在现有的事务内运行。因此在 checkout()方法的开始和终止边界内只有一个事务。
如果余额不足,就一本书也买不了。
REQUIRES_NEW传播行为:表示该方法必须启动一个新事务,并在自己的事务内运行。如果有事务在运行,就应该先挂起它。
事务隔离级别【Isolation】
假设现在有两个并发的事务:Transaction01和Transaction02。
脏读【读取到了未提交的事务】:
①Transaction01 将某条记录的 AGE 值从 20 修改为 30,但是没有提交。
②Transaction02 读取了 Transaction01 更新后的值:30。
③随后Transaction01 回滚,AGE 值恢复到了 20。
④Transaction02 读取到的 30 就是一个无效的值。
不可重复读 【多次从一个字段中读取到的数据不相同】
①Transaction01 读取了 AGE 值为 20。
②Transaction02 将 AGE 值修改为 30,并且提交数据。
③Transaction01 再次读取 AGE 值为 30,和第一次读取不一致。
幻读【多次从一个表中读取的行不相同】
①Transaction01 读取了 STUDENT 表中的一部分数据。
②Transaction02 向 STUDENT 表中插入了新的行。
③Transaction01 读取了 STUDENT 表时,多出了一些行。
数据库系统必须具有隔离并发运行各个事务的能力,使它们不会互相影响。
隔离级别越高,数据一致性就越好,但并发性越弱。一个事务与其他事务之间的隔离等级【1,2,4,8】
隔离等级
-
读未提交【1】:READ UNCOMMITED
- 事务1可以读取事务2未提交的数据。存在问题:脏读。
-
读已提交【2】:READ COMMITTED
- 存在问题:可能出现不可重复读
-
可重读【4】:REPEATABLE READ(字段锁)
- 存在问题:可能出现幻读
-
串行化【8】SERIALIZABLE(表的锁)
其他属性
- 事务超时【timeout】
类型:int,单位:second。
默认值:-1【未设置强制回滚】
设置超时时间,到达指定时间后,会强制事务回滚。
-
事务只读【readonly】
一般事务方法中,只有查询操作时,才将事务设置为只读。
-
事务回滚【rollbackFor/noRollbackFor】
遇见回滚/不回滚的异常类。
示例代码:
//当前事务传播行为是自己属于一个事务。
@Transactional(propagation = Propagation.REQUIRES_NEW,
timeout = 1,
noRollbackFor = ArithmeticException.class)
public void purchase(String username, String isbn) {
//查询book价格
Integer price = bookshopDao.findBookPriceByIsbn(isbn);
//测试事务超时
// try {
// Thread.sleep(5000);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
//修改库存
bookshopDao.updateBookStock(isbn);
//修改余额
bookshopDao.updateUserAccount(username, price);
//演示遇到算数异常时,事务不回滚
int i = 1/0;
}
基于XML方式配置声明式事务管理
<!-- 配置事务切面 -->
<aop:config>
<aop:pointcut expression="execution(* com.atguigu.tx.component.service.BookShopServiceImpl.purchase(..))" id="txPointCut"/> <!-- 将切入点表达式和事务属性配置关联到一起 -->
<aop:advisor advice-ref="myTx" pointcut-ref="txPointCut"/>
</aop:config>
<!-- 配置基于 XML 的声明式事务 -->
<tx:advice id="myTx" transaction-manager="transactionManager">
<tx:attributes>
<!-- 设置具体方法的事务属性 -->
<tx:method name="find*" read-only="true"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="purchase"
isolation="READ_COMMITTED"
no-rollback-for="java.lang.ArithmeticException,java.lang.NullPointerException" propagation="REQUIRES_NEW"
read-only="false"
timeout="10"/>
</tx:attributes>
</tx:advice>
Spring5新特性
添加了新注解
-
以@Nullable 为例
位置:可以书写在方法&属性&参数前面。
作用:表示当前方法或属性可以为空,消除了空指针异常。
Spring5整合Log4j2
-
导入jar包
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.11.2</version> <scope>test</scope> </dependency> -
编写配置文件(不需要自己编写)
-
log4j2.xml
日志级别以及优先级排序:OFF > FATAL > WHAR > INFO > DEBUG > TRACE > ALL
高级别会打印低级别的内容。
-
Spring5整合Junit5
-
导入jar包【注意:将Junit4的jar包删除】
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.7.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.3.1</version> </dependency> -
使用注解进行整合。
//方式一: @ContextConfiguration(locations = "classpath:applicationContext.xml") @ExtendWith(SpringExtension.class) //方式二: @SpringJUnitConfig(locations = "classpath:applicationContext.xml")