• class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="2">
  • class="hljs-ln-code"> class="hljs-ln-line">CREATE TABLE accounts (
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="3"> class="hljs-ln-code"> class="hljs-ln-line"> id INT PRIMARY KEY,
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="4"> class="hljs-ln-code"> class="hljs-ln-line"> balance DECIMAL(10, 2) NOT NULL
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="5"> class="hljs-ln-code"> class="hljs-ln-line">);
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="6"> class="hljs-ln-code"> class="hljs-ln-line">
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="7"> class="hljs-ln-code"> class="hljs-ln-line">-- 插入示例账户
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="8"> class="hljs-ln-code"> class="hljs-ln-line">INSERT INTO accounts (id, balance) VALUES (1, 1000.00), (2, 500.00);
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="9"> class="hljs-ln-code"> class="hljs-ln-line">
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="10"> class="hljs-ln-code"> class="hljs-ln-line">-- 开始事务
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="11"> class="hljs-ln-code"> class="hljs-ln-line">START TRANSACTION;
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="12"> class="hljs-ln-code"> class="hljs-ln-line">
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="13"> class="hljs-ln-code"> class="hljs-ln-line">-- 从账户A(id = 1)扣款100
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="14"> class="hljs-ln-code"> class="hljs-ln-line">UPDATE accounts SET balance = balance - 100 WHERE id = 1;
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="15"> class="hljs-ln-code"> class="hljs-ln-line">
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="16"> class="hljs-ln-code"> class="hljs-ln-line">-- 将100元存入账户B(id = 2)
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="17"> class="hljs-ln-code"> class="hljs-ln-line">UPDATE accounts SET balance = balance + 100 WHERE id = 2;
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="18"> class="hljs-ln-code"> class="hljs-ln-line">
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="19"> class="hljs-ln-code"> class="hljs-ln-line">-- 提交事务
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="20"> class="hljs-ln-code"> class="hljs-ln-line">COMMIT;
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="21"> class="hljs-ln-code"> class="hljs-ln-line">
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="22"> class="hljs-ln-code"> class="hljs-ln-line">-- 为了检查结果,你可以查询账户余额
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="23"> class="hljs-ln-code"> class="hljs-ln-line">SELECT * FROM accounts;
  • class="hide-preCode-box"> class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)">

    代码说明

    1. 创建账户表:首先我们创建了一个名为accounts的表,包含账户ID(id)和余额(balance)两个字段。

    2. 插入示例账户:插入两个示例账户,账户A的余额为1000元,账户B的余额为500元。

    3. 开始事务:通过START TRANSACTION;开始一个新的事务,用于保证接下来的操作的原子性。

    4. 更新账户余额

    5. 提交事务:通过COMMIT;来提交事务,如果所有操作成功执行,所有的变更会被保存到数据库中。

    6. 查询结果:最后,使用SELECT语句检查账户的余额,以确认转账是否成功。

    错误处理

    在实际生产环境中,还需要考虑错误处理。如果在任一步骤发生错误,你应该执行ROLLBACK;来撤销之前的操作。例如:

    1. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="1"> class="hljs-ln-code"> class="hljs-ln-line">-- 当UPDATE操作前后,我们应该有错误处理
    2. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="2"> class="hljs-ln-code"> class="hljs-ln-line">BEGIN;
    3. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="3"> class="hljs-ln-code"> class="hljs-ln-line">
    4. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="4"> class="hljs-ln-code"> class="hljs-ln-line">UPDATE accounts SET balance = balance - 100 WHERE id = 1;
    5. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="5"> class="hljs-ln-code"> class="hljs-ln-line">IF ROW_COUNT() = 0 THEN
    6. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="6"> class="hljs-ln-code"> class="hljs-ln-line"> ROLLBACK;
    7. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="7"> class="hljs-ln-code"> class="hljs-ln-line"> SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Transaction failed: Account A does not have enough balance';
    8. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="8"> class="hljs-ln-code"> class="hljs-ln-line">END IF;
    9. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="9"> class="hljs-ln-code"> class="hljs-ln-line">
    10. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="10"> class="hljs-ln-code"> class="hljs-ln-line">UPDATE accounts SET balance = balance + 100 WHERE id = 2;
    11. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="11"> class="hljs-ln-code"> class="hljs-ln-line">
    12. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="12"> class="hljs-ln-code"> class="hljs-ln-line">-- 提交事务
    13. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="13"> class="hljs-ln-code"> class="hljs-ln-line">COMMIT;
    class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)">

    这种情况下,如果账户A的余额不足,事务将被回滚,确保数据一致性。通过合理使用事务,能够保障银行等业务场景中的数据安全。

    在高并发场景使用事务会出现的问题以及解决方法

    在高并发场景中,使用事务会面临一些挑战,这些挑战主要来源于多个事务并发执行时的相互影响。主要问题包括:

    1. 死锁(Deadlock)

    多个事务在互相等待对方释放资源,导致系统无法继续执行。

    解决方案

    2. 可用性和性能下降

    事务的隔离级别越高,可用性和性能通常越低。比如,使用Serializable级别会导致较长的锁定时间,影响并发性能。

    解决方案

    3. 脏读和不可重复读

    在高并发的情况下,可能会出现脏读(一个事务读取另一个事务未提交的数据)和不可重复读(同一事务的多次查询结果不同)。

    解决方案

    4. 幻读(Phantom Read)

    在启动事务后,另一事务的插入会导致当前事务再次查询时出现不同的记录集。

    解决方案

    5. 回滚带来的性能开销

    在高并发的情况下,频繁的事务回滚会导致性能下降。

    解决方案

    总结

    在高并发场景使用事务时,必须权衡数据一致性和系统性能。通过选择合适的事务隔离级别、利用锁机制、优化数据库操作以及设计合理的应用逻辑,可以减少并发带来的问题。同时,监控系统性能和及时调整也是确保系统稳定的重要手段。

    MySQL自带的隔离级别调整

    事务中的隔离性是指在多用户并发执行事务时,每个事务的执行不会被其他事务所干扰,确保每个事务可以在其独立的环境中执行。这一特性对于维护数据的完整性和一致性至关重要。隔离性通常通过不同的隔离级别来实现,每个级别都在并发性和数据一致性之间取得不同的平衡。

    MySQL支持四种主要的事务隔离级别:

    1. 读未提交(Read Uncommitted)

    2. 读已提交(Read Committed)

    3. 可重复读(Repeatable Read)

    4. 串行化(Serializable)

    隔离性的影响

    总之,事务中的隔离性是支持并发操作的重要机制,通过合理选择隔离级别,可以在系统性能和数据一致性之间找到适当的平衡。

    data-report-view="{"mod":"1585297308_001","spm":"1001.2101.3001.6548","dest":"https://blog.csdn.net/yican2580/article/details/141170773","extend1":"pc","ab":"new"}">> id="blogVoteBox" style="width:400px;margin:auto;margin-top:12px" class="blog-vote-box"> class="vote-box csdn-vote" style="opacity: 1;"> class="pos-box pt0" style="height: 222px; visibility: visible;">
    注:本文转载自blog.csdn.net的一只淡水鱼66的文章"https://blog.csdn.net/yican2580/article/details/141170773"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
    复制链接

    评论记录:

    未查询到任何数据!