• JDBC事务


    jdbc 事务

    1. 什么是事务

    所谓事务,就是针对数据库的一组操作(多条sql)

    位于同一个事务的操作具备同步的特点,也就是要么都成功,要么都失败

     

    2. 事务的作用

    在实际中,我们的很多操作都是需要由多条sql来共同完成的,例如,A账户给B账户转账就会对应两条sql

    update account set money=money-100 where name=a;

    update account set money=money+100 where name=b;

    假设第一条sql成功了,而第二条sql失败了,这样就会导致a账户损失了100元,而b账户并未得到100

     

    如果将两条sql放在一个sql中,当第二条语句失败时,第一条sql语句也同样不会生效,

    这样a账户就不会有任何的损失

     

     

    3. 事务的实现原理

    默认情况下,我们向数据库发送的sql语句是会被自动提交的,开启事务就是相当于关闭自动提交功能,改为手动提交,我们只需要将提交事务的操作放在最后一个操作,这样一来,如果在提交事务之前出现异常,由于没有执行提交操作,事务中未提交的操作就会被回滚掉

     

    4. 例子

    account.sql

    create table account(

    id int primary key auto_increment,

    name varchar(40),

    money float

    )character set utf8 collate utf8_general_ci;

     

    insert into account(name,money) values('aaa',1000);

    insert into account(name,money) values('bbb',1000);

    insert into account(name,money) values('ccc',1000);

     

    aaa 给 bbb 转账 100

    update account set money=money-100 where name='aaa';

    // 异常退出

    update account set money=money+100 where name='bbb';

     

    // 查询结果

    select * from accont;

     

    如果开启事务就可以避免刚才的错误发生

    // 开启事务

    start transaction;

     

    // 如果操作执行完毕,我们需要将事务提交

    commit;

     

    // 还可以手动回顾事务中所有未提交的事务

    rollback;

     

    命令行做实验得出结论:

    如果开了一个事务, 又敲了一次 start transaction 再次开启事务, 前一个事务会自动提交

     

    5、在程序中使用 jdbc 开启事务

    在使用 jdbc 操作数据库时,需要使用 Connection 对象对事务进行管理

    // 开启事务

    Connection.setAutoCommit(false);//设置自动提交为false

    // 回滚事务

    Connection.rollback();

    //提交事务

    Connection.commit();

     

    在 jdbc 程序中我们还可以设置回滚点, 让事务回顾到指定的回滚点,而不是自动回滚所有未提交的操作

    需要将程序中的异常捕获,在catch语句块中回滚事务,在finally中提交事务

    注意 , 将 Commit 操作放在 finally 中是为了保证提交未回滚的事务操作

     

    6. 事务的特性

    事务有四大特性,一般来讲,判断一个数据库是否支持事务,就看数据库是否支持这四个特性

    原子性(Atomicity原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 

     

    一致性(Consistency事务必须使数据库从一个一致性状态变换到另外一个一致性状态。

     

    隔离性(Isolation事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

     

    持久性(Durability持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

     

    7. 事务的隔离级别

    1)多线程开启事务

    由于数据库是多线程并发访问的,所以很容易出现多个线程同时开启事务的情况

    多线程开事务容易引起 赃读、不可重复读、幻读 的情况发生

     

    赃读:dirty read

    是指一个事务读取了另一个事务未提交的数据,这是相当危险的。

    设想一下,A要给B转账100元购买商品, 如果A开启了一个事务做了转账的工作

    update account set money=money+100 while name=b;

    update account set money=money -100 while name=a;

    A先不提交事务,通知B来查询

    这时B来查询账户,由于会读到A开启的事务中未提交的数据,就会发现A确实给自己转了100元,

    自然就会给A发货,AB发货后就将事务回滚,不提交,此时,B就会受到损失

     

    不可重复读:non-repeatable read

    是指事务中两次查询的结果不一致,原因是在查询的过程中其他事务做了更新的操作 update

    例如,银行做报表,第一次查询A账户有100元,第二次查询A账户有200元,原因是期间A存了100

    这样就会导致一行多次统计的报表不一致

     

    和脏读的区别是:

    脏读是读取前一事务未提交的脏数据,不可重复读是在事务内重复读取了别的线程已提交的数据。

     

    有的时候大家会认为这样的结果是正确的,没问题

    我们可以考虑这样一种情况,比如银行程序需要将查询结果分别输出到电脑屏幕和写到文件中,结果在一个事务中针对输出的目的地,进行的两次查询不一致,导致文件和屏幕中的结果不一致,银行工作人员就不知道以哪个为准了。

     

    幻读:phantom read    又名虚读

    是指在一个事务内两次查询中数据笔数不一致

    幻读和不可重复读有些类似,是指两次查询过程中,其他事务做了插入记录的操作,导致记录数有所增加

    insert

     

    例如银行做报表统计account表中所有用户的总额时,此时总共

    五个账户,总金额为500元,这时有一个新的账户产生了,并且

    存了100元,这时银行再统计会发现帐户总金额为600元了,造

    成虚读同样会使银行遇到同样的困惑

     

    实验发现不会出现虚读

    来自网络的解释:

    幻读只是在理论上会发生的一种情况,而现实操作中并不是一定会发生

     

    2)设置事务的隔离级别

    为了避免多线程开事务引发的问题,我们需要将事务进行隔离

    事务有四种隔离级别,不同的隔离级别可以防止不同的错误发生

    serializable:可串行化,能避免脏读、不可重复读、幻读情况的发生

    repeatable read:可重读,能避免脏读、不可重复读情况的发生

    read committed:读取提交的内容,可避免脏读情况发生

    read uncommitted:读取未提交的内容最低级别,避免不了任何情况

     

    操作:

    设置事务隔离级别

    set   transaction isolation level 

    查询当前事务隔离级别

    select @@tx_isolation

     

    查询看到的都是快照

    位于事务中的多次查询,如果隔离级别设置为repeatable read那么多次查询读的就是一个快照

    说白了就是不更新快照

  • 相关阅读:
    性能篇系列—stream详解
    Java正则表达式详细解析
    干货系列性能篇之——序列化
    面试官之问:知道你的接口“QPS”是多少吗?
    Java性能之优化RPC网络通信
    Spring之 JDBC 异常
    Java性能之synchronized锁的优化
    浅谈Java中switch分支语句
    Spring Boot 之异步执行方法
    Java性能 -- Lock优化
  • 原文地址:https://www.cnblogs.com/qq809306794/p/3183331.html
Copyright © 2020-2023  润新知