mysql & spring 事务
  9mQgQl3rGtmh 2023年11月02日 86 0

# MySQL事务

对于需要保证数据一致性和完整性的操作,应该使用事务来实现。事务可以将 多个操作 看作一个 整体 ,可以保证这些操作要么全部执行成功,要么全部不执行。而不使用事务时,在多个操作之间没有原子性、一致性、隔离性和持久性的保证,容易出现数据不一致的情况。

START TRANSACTION;  -- 开始事务
UPDATE table1 SET column1 = 'value1' WHERE id = 1;
UPDATE table2 SET column2 = 'value2' WHERE id = 2;
COMMIT;  -- 提交事务
UPDATE table1 SET column1 = 'value1' WHERE id = 1;
UPDATE table2 SET column2 = 'value2' WHERE id = 2;

第一段代码开启了一个事务,执行了两个UPDATE语句,并在最后使用COMMIT提交事务,从而将事务中的操作持久性写入数据库。如果在执行期间出现异常或错误,可以使用ROLLBACK撤销所有操作。

第二段代码没有使用事务,如果两个UPDATE语句中的任何一个操作失败,则只有部分更改会被写入数据库,可能会造成数据不一致。

在MySQL中,事务的四大特性可以用ACID来表示:

  1. 原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败回滚。
  2. 一致性(Consistency):事务执行前后,数据库的完整性约束没有被破坏。
  3. 隔离性(Isolation):事务的执行不会相互影响,每个事务都好像在一个独立的世界中完成。
  4. 持久性(Durability):事务完成后,对数据库的所有更改将永久保存。

MySQL中,事务主要通过以下语句来实现

  1. BEGIN或START TRANSACTION:开始一个事务。
  2. COMMIT:提交事务,将事务中的所有操作永久写入数据库。
  3. ROLLBACK:回滚事务,撤销事务中的所有操作。

# MySQL事务隔离级别

MySQL 支持四种事务隔离级别,分别为:读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。

  1. 读未提交(Read Uncommitted) 在该隔离级别下,一个事务可以读取到另一个未提交事务的数据。当两个事务同时操作同一数据,并且事务1处于未提交状态时,事务2可以读取到事务1未提交的数据。该级别存在脏读、不可重复读和幻读等问题。
  2. 读已提交(Read Committed) 在该隔离级别下,一个事务只能读取到已经提交的事务数据。即读取到的内容都是其他事务已提交的内容。避免了脏读问题,但存在不可重复读和幻读等问题。
  3. 可重复读(Repeatable Read) 在该隔离级别下,一个事务在执行期间多次读取同一数据,读取到的内容都是相同的。即使其他事务修改了该数据,本事务也不会读取到该修改。避免了脏读和不可重复读问题,但存在幻读问题。
  4. 串行化(Serializable) 在该隔离级别下,对于同一数据的修改和读取,事务必须串行执行。即事务在读取数据之前需要先获取锁,其他事务不能修改该数据,直到当前事务提交或者回滚才释放锁。避免了脏读、不可重复读和幻读问题,但是并发性能非常低下。

需要注意的是,隔离级别越高,解决的问题就越多,但并发性能也越低。所以在设计应用程序的时候,需要根据实际情况,选取适合自己的隔离级别。在开发过程中,我们一般会默认使用 Read Committed 或者 Repeatable Read 级别,根据应用场景来选择合适的级别。

如何使用:

在 Spring 中,事务隔离级别可以通过 @Transactional 注解的 isolation 属性进行设置。

@Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
public void doSomething(){
    // 业务逻辑
}

# Spring的事务

Spring 的事务使用分为两种方式:编程式事务和声明式事务。下面将分别介绍这两种方式。

编程式事务

编程式事务是通过编写代码控制事务的边界和行为,需要手动开启、提交或回滚事务,适用于一些复杂的、需要精细控制的业务场景。使用编程式事务需要以下步骤:

(1)配置事务管理器

在 Spring 的配置文件中,需要配置事务管理器并将其与数据源绑定。例如:

Copy Code<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <!-- 数据源相关配置 -->
</bean>

<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

(2)通过编码方式进行事务控制

在需要应用事务的方法中,需要使用 TransactionTemplatePlatformTransactionManager 对象来进行事务控制。例如:

Copy Code@Autowired
private PlatformTransactionManager transactionManager;

public void transferMoney(int fromId, int toId, double amount) {
    DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
    TransactionStatus status = transactionManager.getTransaction(definition);

    try {
        // 执行业务逻辑
        // ...
        
        transactionManager.commit(status); // 提交事务
    } catch (Exception e) {
        transactionManager.rollback(status); // 回滚事务
    }
}

声明式事务

声明式事务是通过注解或 XML 配置的方式声明,在方法执行期间自动开启、提交或回滚事务,适用于简单的、重复性的业务场景。使用声明式事务需要以下步骤:

(1)配置事务管理器

同编程式事务。

(2)通过注解或 XML 文件声明事务

在需要应用事务的方法上,可以使用 @Transactional 注解来声明事务。例如:

Copy Code@Transactional
public void transferMoney(int fromId, int toId, double amount) {
    // 执行业务逻辑
    // ...
}

XML 配置方式与注解类似,只不过需要在 Spring 的配置文件中进行声明。例如:

Copy Code<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="transferMoney"/>
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.example.service.TransferService.transferMoney(..))"/>
</aop:config>

除了以上两种方式,Spring 还提供了一些高级特性,如传播行为、回滚规则等,可以根据具体业务场景进行配置。


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
9mQgQl3rGtmh
作者其他文章 更多