声明式事物管理

声明式事物管理

什么是事物管理

事物的概念

事务管理是指对数据库操作的一系列相关操作进行统一管理,保证这些操作要么全部成功执行,要么全部失败回滚,从而确保数据的完整性和一致性。

在数据库操作中,一个事务通常包括一系列的数据库操作(如增、删、改),这些操作要么全部执行成功并提交到数据库中,要么出现错误时进行回滚,使得数据库状态可以回到事务开始前的状态。

事务的ACID原则

事务具有4个基本特性:原子性、一致性、隔离性、持久性。也就是我们常说的ACID原则。

1.原子性:一个事务已经是一个不可再分割的工作单位。

2.一致性: 指事务执行前后,数据库的完整性约束没有被破坏。

3.隔离性: 指多个事务并发执行时,事务之间应该相互隔离,一个事务的执行不应该影响其他事务的执行。

4.持久性: 指一旦事务提交,其所做的修改将会永久保存在数据库中,即使系统发生故障,这些修改的数据也不 会丢失。

Spring 中的事物隔离级别

隔离级别由低到高【读未提交】=>【读已提交】=>【可重复读】=>【序列化操作】

隔离级别说明脏读不可重复读幻读
ISOLATION_DEFAULTspring默认数据库的隔离级别
ISOLATION_READ_UNCOMMITTED读未提交
ISOLATION_READ_COMMITTED读已提交×
ISOLATION_REPEATABLE_READ可重复读××
ISOLATION_SERIALIZABLE序列化操作×××

如果没有事物隔离级别就会产生以下问题

1.脏读: 是数据库事务隔离级别中可能出现的问题之一,指的是一个事务读取了另一个事务未提交的数据。

2.不可重复读: 是指在数据库事务隔离级别中,同一事务中多次查询同一条数据,但在这个过程中却得到了不同 的结果。

3.幻读: 是指在数据库事务隔离级别中,一个事务在读取某个范围的记录时,另一个事务在该范围内插入了新的 记录,导致第一个事务在接下来的读取中出现了之前不存在的记录,就好像发生了幻觉一样。

声明式事物概念

编程式事物

在提及声明式事物是我们需要了解另一项事物,编程式事物: 编程式事务是指手动编写程序来管理事务,即通过编写代码的方式直接控制事务的提交和回滚。在 Java 中,通常使用事务管理器来实现编程式事务 。

优点:灵活性高 可以按照自己的需求来控制事务的粒度、模式等 。

缺点:细节都需要程序员自己来完成,繁琐;复用性不高,事物控制代码多了以后,会影响大妈的可读性和可维护性。

声明式事物

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

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

使用声明式事务可以将事务的控制和业务逻辑分离开来,提高代码的可读性和可维护性。

声明式事物的实现(注解方式)

创建数据库studb,在数据库中新建students表

#
# Structure for table "students"
#

DROP TABLE IF EXISTS `students`;
CREATE TABLE `students` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `gender` varchar(10) NOT NULL,
  `age` int(11) DEFAULT NULL,
  `class` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;

#
# Data for table "students"
#

INSERT INTO `students` VALUES (1,'张三','男',99,'高中一班'),(2,'李四','男',19,'高中二班'),(3,'王五','女',18,'高中一班'),(4,'赵六','女',20,'高中三班'),(5,'刘七','男',19,'高中二班'),(6,'陈八','女',18,'高中一班'),(7,'杨九','男',20,'高中三班'),(8,'吴十','男',19,'高中二班');

导入依赖

<dependencies>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>6.0.6</version>
  </dependency>

  <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>5.3.1</version>
  </dependency>


  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>6.0.6</version>
      <scope>test</scope>
  </dependency>

  <dependency>
      <groupId>jakarta.annotation</groupId>
      <artifactId>jakarta.annotation-api</artifactId>
      <version>2.1.1</version>
  </dependency>

  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.25</version>
  </dependency>

  <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.2.8</version>
  </dependency>

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>6.0.6</version>
  </dependency>

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>6.0.6</version>
  </dependency>


  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>6.0.6</version>
  </dependency>

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>6.0.6</version>
  </dependency>
</dependencies>

外部配置文件(jdbc.properties)

jdbc.url=jdbc:mysql://localhost:3306/studb
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.username=root
jdbc.password=root

配置文件

@Configuration
@ComponentScan("org.example")
@PropertySource("classpath:jdbc.properties")
@EnableTransactionManagement
public class JavaConfig {

    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    @Bean
    public DataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        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){
        return new DataSourceTransactionManager(dataSource);
    }
}

dao和service层(注:@Transactional(readOnly=true)表示只读模式,不能进行数据的更改 )

​ @Transactional(timeout=3)表示在提交后3秒后没能提交成功,事物将回滚

​ @Transactional( rollbackFor = 异常类.class )表示遇到此异常类将发生回滚)

@Repository
public class StudentDao {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    public void updateNameById(String name,Integer id){
        String sql = "update students set name = ? where id = ? ;";
        int rows = jdbcTemplate.update(sql, name, id);
    }
}
@Service
public class StudentService {
    
    @Autowired
    private StudentDao studentDao;
    
    @Transactional
    public void updateNameById(){
        studentDao.updateAgeById(100,1);
        System.out.println("-----------");
        studentDao.updateNameById("张三",1);
    }
}

测试

@SpringJUnitConfig(classes = DataSourceConfig.class)
public class TxTest {

    @Autowired
    private StudentService studentService;

    @Test
    public void  test(){
        studentService.updateNameById();
    }
}

参考于尚硅谷新版SSM框架全套视频教程,Spring6+SpringBoot3最新SSM企业级开发

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值