Spring声明式事务 编程式事务

Spring声明式事务

1.事务的概念

1.1编程式事务

编程式事务是指手动编写程序来管理事务,即通过编写代码的方式直接控制事务的提交和回滚

Connection conn = ...;

try{

//开启事务:关闭事务的自动提交

conn.setAutoCommit(false);

//业务代码

...

//提交事务

conn.commit();

}catch{

//事务回滚

conn.rollBack();

}finally{

//释放数据库连接

conn.close();

}

编程式事务存在的缺陷:

细节没有被屏蔽:具体操作过程中,所有细节都需要程序员自己来完成,较为繁琐

代码复用性不高:如果没有有效抽取出来,每次实现功能都需要自己编写代码,没有复用。

1.2声明式事务

声明式事务是指使用注解或xml配置的方式来控制事务的提交和回滚。

开发者只需要添加配置即可,具体事务的实现由第三方框架实现,避免我们直接进行事务操作。

在spring中 spring-tx是专门来做声明式事务的框架

1.3事务管理器

spring的tx是对aop的再次封装

tx不会在事务增强代码中写具体的事务实现,而是通过一个接口-事务管理器(具体提供事务方法)

在增强的对应的位置调用这个接口的方法

而这个接口的常用实现类spring也为我们提供了,在实现类中重写这个事务管理器的方法

常用事务管理器实现类:DataSourceTransactionManager、HibernateTransactionManager等

我们只需要把这些实现类配置到ioc容器中即可

image-20240809091127927

2.事务操作

2.1添加事务

选择对应的事务管理器实现类加入到ioc容器

在配置类中,通过@Bean 注解加入到ioc容器,还要再配置类上使用 @EnableTransactionManagement

@Configuration

@ComponentScan("com.ztone")

@PropertySource("classpath:jdbc.properties")

@EnableTransactionManagement

public class JavaConfig {

@Value(" u r l " ) p r i v a t e S t r i n g u r l ; @ V a l u e ( " {url}") private String url; @Value(" url")privateStringurl;@Value("{driver}")

private String driver;

@Value(" u s e r n a m e 1 " ) p r i v a t e S t r i n g u s e r n a m e ; @ V a l u e ( " {username1}") private String username; @Value(" username1")privateStringusername;@Value("{password}")

private String password;

@Bean

public DataSource dataSource(){

DruidDataSource dataSource = new DruidDataSource();

dataSource.setUrl(url);

dataSource.setDriverClassName(driver);

dataSource.setUsername(username);

dataSource.setPassword(password);

return dataSource;

}

@Bean

public JdbcTemplate jdbcTemplate(DataSource dataSource){

JdbcTemplate jdbcTemplate = new JdbcTemplate();

jdbcTemplate.setDataSource(dataSource);

return jdbcTemplate;

}

@Bean

public TransactionManager transactionManager(DataSource dataSource){

DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();

//事务操作需要连接池对象

transactionManager.setDataSource(dataSource);

return transactionManager;

}

}

使用注解指定哪些方法需要添加事务

在需要添加事务的方法或类上使用 @Transactional

@Service

public class StudentService {

@Autowired

private StudentDao studentDao;

@Transactional

public void updateStudent(){

studentDao.updateNameById("zhangsan",1);

int result = 1/0;

studentDao.updateAgeById(200,1);

}

}

当事务中出现错误,就不会提交

2.2属性:只读

在 @Transactional 注解中有一个属性是 readonly 表示只读模式,可以提升查询的效率,但是开启只读模式后,不能进行修改的操作,否则会报错。默认值是false,不开启。

所以只读模式只是用在查询操作上。

应用场景:一般@Transactional 注解都用在类上,所以该类所有方法都有事务,那么我们可以在查询的方法上将readonly 属性设置为true,提升查询的效率。

2.3属性:超时时间

在@Transactional 注解中有 timeout 属性,可以设置等待的秒数,如果超过了这个秒数就会回滚事务和释放异常

这个属性如果写在类上,需要保证方法上没有这个注解,否则不会生效

2.4属性:事务异常指定

在默认情况下,只有发生运行时异常时事务才会回滚。

我们可以通过 指定 rollbackFor的值 来控制什么异常进行回滚,通常指定rollbackFor 的值为 Exception,所有异常都回滚。

与之对应的是 noRollbackFor ,指定某个异常不回滚

@Transactional(rollbackFor = Exception.class)

public void updateStudent(){

studentDao.updateNameById("zs",1);

int result = 1/0;

studentDao.updateAgeById(1000,1);

}

2.5属性:事务隔离级别

数据库事务的隔离级别是指在多个事务并发执行时,数据库系统为了保证数据一致性所遵循的规定。常见的隔离级别包括:

读未提交:事务可以读取未被提交的数据,容易产生脏读、不可重复度、幻读等,实现简单但不太安全,一般不用。

读已提交:事务只能读取已经提交的的数据,可以避免脏读的问题,但可能引发不可重复读和幻读

可重复读:在一个事务中,相同的查询将返回相同的结果集,不管其他事务对数据做了什么修改。可以避免脏读和不可重复读,但仍有幻读问题。

串行化:最高的隔离级别,完全禁止了并发,只允许一个事务执行完毕后才执行另一个事务,可以避免以上所有问题,但效率较低。不适用于高并发。

属性名 isolation

给该属性设置不同的枚举类型 以设置不同的隔离级别

读已提交--READ_COMMITTED

读未提交--READ_UNCOMMITTED

串行化--SERIALIZABLE

可重复读--REPEATABLE_READ

在mysql中 Isolation.DEFAULT 是 可重复读

2.6属性:事务的传播行为

现在有两个业务方法,每个业务方法都添加了事务,当在业务方法1中调用了业务方法2,那么业务方法2的事务会加入到业务方法1的事务中还是会独立出来,就是由事物的传播行为来指定

事务传播行为的属性需要设置到子事务上

属性:propagation

REQUIRED:如果父方法中有事务,子方法就加入到父方法的事务中,如果没有就自己创建一个事务,最终只有一个事务

REQUIRES_NEW:不管父方法是否有事务,子方法都创建自己的事务,都是独立的事务。

NESTED:如果当前存在事务,则在该事务中嵌套一个新事务,吴国没有则与 REQUIRED 一样

SUPPORTS:如果当前存在事务,则加入该事务,否则以非事务方式运行

NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,挂起该事务

MANDATORY:必须在一个已有的事务中执行,否则会抛异常

NEVER:必须在没有事务的情况下执行,否则抛异常

在同一个类中,对于@Transactional注解的方法的调用,事务传播行为不会生效,因为Spring框架中使用代理模式实现事务机制,在同一个类没办法生成代理对象,所以不会产生事务传播行为。

相关推荐
zzzzzz31010 分钟前
别让大模型直接碰业务:我在 Spring Boot 里给 AI 操作加了一道“可拒绝的闸门”
人工智能·spring boot·spring
xqqxqxxq20 分钟前
MySQL 数据类型笔记
数据库·笔记·mysql
数聚天成DeepSData21 分钟前
数聚天成 DeepSData 数据价值落地实战指南
java·maven·devops
小小小米粒31 分钟前
阿姆达尔定律(Amdahl‘s Law)
java·开发语言
知彼解己31 分钟前
Java 版本演进
java·开发语言·spring boot
Logintern0943 分钟前
理解MySQL数据库的“事务与锁”
数据库·mysql
极客先躯1 小时前
高级java每日一道面试题-2026年05月11日-实战篇[Docker]-如何容器化金融产品推荐系统?
java·运维·docker·容器·金融·高级面试·金融产品推荐系统
朱容zr3331331 小时前
为什么推荐使用自增主键?使用UUID作为主键的优缺点是什么?
java·运维·数据库·后端·mysql·面试·性能优化
麻瓜code1 小时前
【Redis 】数据类型、持久化与过期删除
数据库·redis·缓存
空杆推不起1 小时前
穿透 Flink CDC 表层用法:数据库日志捕获机制、Flink Source 运行时、端到端一致性底层原理详解
大数据·数据库·flink