• Spring事务相关


    Spring实现事务管理的方式

    编程式事务管理

    编程式事务管理是指在代码中显式地管理事务,通常通过Spring的TransactionTemplatePlatformTransactionManager接口来实现。
    示例代码(TransactionTemplate):

    import org.springframework.transaction.TransactionStatus;
    import org.springframework.transaction.support.TransactionCallbackWithoutResult;
    import org.springframework.transaction.support.TransactionTemplate;
    
    public class UserService {
        private TransactionTemplate transactionTemplate;
    
        public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
            this.transactionTemplate = transactionTemplate;
        }
    
        public void addUser(User user) {
            transactionTemplate.execute(new TransactionCallbackWithoutResult() {
                @Override
                protected void doInTransactionWithoutResult(TransactionStatus status) {
                    // transactional code
                    userRepository.save(user);
                }
            });
        }
    }
    

    声明式事务管理

    声明式事务管理是通过AOP(Aspect-Oriented Programming)来实现的,通常使用@Transactional注解。
    示例代码(注解方式):

    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    @Service
    public class UserService {
    
        @Autowired
        private UserRepository userRepository;
    
        @Transactional
        public void addUser(User user) {
            userRepository.save(user);
        }
    }
    
    

    示例代码(XML配置方式):
    在Spring配置文件中配置事务管理器和声明式事务管理:

    
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    bean>
    
    
    <tx:annotation-driven transaction-manager="transactionManager"/>
    
    
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true" />
            <tx:method name="*" rollback-for="Exception" />
        tx:attributes>
    tx:advice>
    
    
    <aop:config>
        <aop:pointcut id="serviceMethods" expression="execution(* com.example.service.*.*(..))" />
        <aop:advisor pointcut-ref="serviceMethods" advice-ref="txAdvice" />
    aop:config>
    

    事务传播行为

    Spring事务管理支持多种事务传播行为,这些行为定义了事务方法是如何参与到现有事务中的:

    • REQUIRED:默认传播行为,如果当前没有事务,就新建一个事务;如果已经存在一个事务中,加入到这个事务中。
    • REQUIRES_NEW:总是新建一个事务,如果当前存在事务,把当前事务挂起。
    • NESTED:如果当前存在事务,则在嵌套事务中执行。如果当前没有事务,则新建一个事务。
    • MANDATORY:必须在一个已经存在的事务中运行,否则抛出异常。
    • NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
    • NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
    • SUPPORTS:如果当前存在事务,则在事务中运行;如果当前没有事务,也可以以非事务方式运行。

    事务隔离级别

    事务隔离级别定义了一个事务与其他事务隔离的程度。Spring支持以下隔离级别:

    • DEFAULT:使用数据库默认的隔离级别。
    • READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、不可重复读和幻读问题。
    • READ_COMMITTED:允许读取并发事务已经提交的数据,可以防止脏读,但不可重复读和幻读仍然可能发生。
    • REPEATABLE_READ:对同一字段的多次读取结果是一致的,除非数据是被本事务自己所修改,可以防止脏读和不可重复读,但幻读仍然可能发生。
    • SERIALIZABLE:最高的隔离级别,完全遵循ACID原则。所有事务顺序执行,可以防止脏读、不可重复读和幻读。

    MySQL中update操作使用的是什么锁

    在MySQL的InnoDB存储引擎中,UPDATE操作主要使用行级锁,具体为排他锁(X锁),以确保数据的一致性和完整性。在较高的隔离级别(如REPEATABLE READ)下,InnoDB还会使用间隙锁或临键锁来防止幻读。这些锁机制确保了在并发环境下,事务能够安全地进行数据修改,而不会导致数据不一致或并发问题。

    InnoDB存储引擎的锁机制

    InnoDB存储引擎支持行级锁和表级锁,但在大多数情况下,它使用行级锁来处理UPDATE操作。

    行级锁
    行级锁是指锁住单独的行而不是整个表,这种锁可以提高并发性,因为它允许多个事务同时访问同一张表的不同行。InnoDB在执行UPDATE操作时通常使用行级锁,包括以下类型:

    • 共享锁(S锁):允许事务读取一行数据,但不允许修改。
    • 排他锁(X锁):允许事务读取和修改一行数据,并且防止其他事务读取和修改。

    在UPDATE操作中,InnoDB通常会使用排他锁(X锁),因为更新操作需要修改数据。

    间隙锁(Gap Lock)
    间隙锁是InnoDB的一种特殊锁类型,主要用于防止幻读现象。间隙锁锁定一个范围内的所有行,但不锁定实际的行,这对于范围查询和更新操作尤为重要。在某些隔离级别(如REPEATABLE READ)下,InnoDB会使用间隙锁。

    临键锁(Next-Key Lock)
    临键锁是行锁和间隙锁的组合,锁定一个索引记录及其前面的间隙。这样可以防止插入新的行到已经锁定的范围内,从而避免幻读。

    如何检测和优化行级锁?

    1. 检测行级锁的使用:

    • 慢查询日志: 通过分析慢查询日志,可以找到长时间运行的查询,这些查询可能是由于行级锁争用导致的。
    • 性能 Schema: MySQL的性能模式(Performance Schema)提供了关于锁的详细统计信息,包括行级锁的等待和持有时间。INFORMATION_SCHEMA: 可以查询INFORMATION_SCHEMA库中的INNODB_LOCKSINNODB_TRX表来获取当前锁的信息和事务信息。
    • 工具: 使用Percona Toolkit等第三方工具来检测和分析行级锁的问题。

    2.优化行级锁:

    • 索引优化: 确保所有涉及更新操作的列都有适当的索引。如果没有索引或者索引不当,InnoDB可能需要锁定更多的行,因为无法快速定位到特定的记录。
    • 减少事务大小: 尽量减少事务中涉及的行数。大事务会锁定更多的行,增加锁争用的可能性。
    • 避免长事务: 长时间运行的事务会持有锁,阻止其他事务对相同行的访问。尽量将事务保持在短时间范围内。
    • 使用更合适的存储引擎: 如果你的工作负载更适合MyISAM或其他存储引擎,可以考虑使用它们,尽管它们不支持行级锁。
    • 优化查询: 避免使用可能导致大量行锁的查询,例如不带索引条件的更新语句。
    • 调整事务隔离级别: 考虑使用更低的事务隔离级别,如READ COMMITTED,以减少锁的竞争。但是,这可能会影响事务的隔离性和一致性。
    • 监控和分析: 定期监控和分析数据库的性能,以便及时发现和解决行级锁的问题。

    3.减少死锁:

    • 统一访问顺序: 确保所有的事务都以相同的顺序访问和修改数据,这样可以减少死锁的发生。
    • 使用锁提示: 在适当的情况下,可以使用SELECT ... FOR UPDATESELECT ... LOCK IN SHARE MODE来明确指定锁的行为。
    • 设置超时: 设置合适的事务超时时间,以便在死锁发生时能够快速回滚一个事务。
  • 相关阅读:
    Centos7 编写开机监测gdm服务退出的脚本
    小程序分包及分包预下载
    【Java牛客刷题】入门篇(01)
    DeepSceneSeg
    flink cdc原理与使用
    【LeetCode】二分基础模板,查找左右边界
    基于蝙蝠算法的无人机航迹规划-附代码
    AI人工智能老师大模型讲师叶梓 OneLLM:开创性的多模态大型语言模型技术
    Grafana Loki查询加速:如何在不添加资源的前提下提升查询速度
    可拓展的低代码全栈框架
  • 原文地址:https://blog.csdn.net/slient_love/article/details/139653446