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来明确指定锁的行为。
  • 设置超时: 设置合适的事务超时时间,以便在死锁发生时能够快速回滚一个事务。

相关推荐

  1. Spring事务相关

    2024-06-14 08:24:03       6 阅读
  2. Spring事务

    2024-06-14 08:24:03       16 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-14 08:24:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-14 08:24:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-14 08:24:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-14 08:24:03       20 阅读

热门阅读

  1. 深入理解MyBatis XML配置文件

    2024-06-14 08:24:03       8 阅读
  2. 深入解析Web通信 HTTP、HTTPS 和 WebSocket

    2024-06-14 08:24:03       11 阅读
  3. 阿里云aliyun cli的作用以及安装步骤

    2024-06-14 08:24:03       9 阅读
  4. ffmpeg把视频文件转码为MP4格式

    2024-06-14 08:24:03       6 阅读
  5. 「C系列」C 函数指针/回调函数

    2024-06-14 08:24:03       8 阅读
  6. Linux 如何查看磁盘空间占用

    2024-06-14 08:24:03       5 阅读
  7. 探索微软Edge:新时代的浏览器先锋

    2024-06-14 08:24:03       7 阅读
  8. 浅谈GNU LIBC的版本间的变化

    2024-06-14 08:24:03       9 阅读