数据库事务

1.事务的概念:

所谓的事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。

例如,银行转账工作:从一个账号扣款并使另一个账号增款,这两个操作要么都执行,要么都不执行。所以,应该把它们看成一个事务。

事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性。针对上面的描述可以看出,事务的提出主要是为了解决并发情况下保持数据一致性的问题


2.事务的四大特性:ACID

  原子性(Atomicity):事务中的操作都是不可分割的原子单位,事务中所有的操作要么全部成功,要么全部失败。

    一致性(Consistemcy):事务执行后,数据库的状态与他的业务规则应该保持不变。比如转账业务,转账前后,两个账户的总额是不变的。

    隔离性(Isolation):隔离是在并发操作中,不同事务之间应该隔离开来,使得每个并发事务都互不干扰。

    持久性(Durability):一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务,数据库马上崩溃,在数据库重新启动完,数据库中的数据也要保持不变。

3.自定义事务:

数据库开启事务命令:

1).start transaction :开启事务

2).rollback:回滚事务

3).commit:提交事务

4.JDBC中与事务有关的几个方法:

connection.setAutoCommit(boolean):设置事务是否自动提交,如果设置为true,自动提交,那么每执行一条sql语句,就相当于执行一个单独的事务,就会自动提交,如果设置为false,那就相当于开启了一条事务。

connection.commit():事务的提交。

Connection.rollback():回滚事务。


try {

 con.setAutoCommit(false);//开启事务…

  ….

  …

  con.commit();//try的最后提交事务

} catch() {

  con.rollback();//回滚事务

}

5.MySQL数据库中操作事务命令

编写测试SQL脚本,如下:

/* 创建数据库 */createdatabase day16;use day16;

/* 创建账户表 */createtable account ( id int primary key auto_increment,  

namevarchar(40), moneyfloat

characterset utf8 collate utf8_general_ci;

/* 插入测试数据 */insertinto account(name,money)values('aaa',1000);

insertinto account(name,money)values('bbb',1000);insertinto account(name,money)values('ccc',1000);

下面我们在MySQL数据库中模拟aaa向bbb转帐这个业务场景。

  • 开启事务(start transaction) 
    使用”start transaction”开启MySQL数据库的事务,如下所示: 

    我们首先在数据库中模拟转账失败的场景,首先执行update语句让aaa用户的money减少100块钱,如下图所示: 

    现在假设程序抛出异常,也即该链接断了,代码块没有完成,此时数据库会自动回滚掉此sql语句造成的影响,也就是说这条sql语句没有执行。我们现在就来模拟这种情况,我们关闭当前操作的dos命令行窗口,这样就导致了刚才执行的update语句的数据库的事务没有被提交,那么我们对aaa用户的修改就不算是真正的修改了,下次在查询aaa用户的money时,依然还是之前的1000,如下图所示: 

  • 提交事务(commit) 
    下面我们在数据库模拟aaa向bbb转账成功的场景。 

    我们手动提交(commit)数据库事务之后,aaa向bbb转账100块钱的这个业务操作算是真正成功了,aaa账户中少了100,bbb账户中多了100。

  • 回滚事务(rollback) 

    通过手动回滚事务,让所有的操作都失效,这样数据就会回到最初的初始状态!

6.隔离性:

下面重点介绍一下事务的隔离级别.

1):并发问题

多个线程开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个线程在获取数据时的准确性。

如果事务不考虑隔离性,可能会引发如下问题

  • 脏读的问题-->指一个事务读取了另外一个事务未提交的数据,即读到了脏数据 
    这是非常危险的,假设a向b转帐100元,对应sql语句如下所示:

    1.update account set money=money+100 while name=‘b’;    
    2.update account set money=money-100 while name=‘a’;
    
       
       
    • 1
    • 2
    • 3
    • 1
    • 2

    当第1条sql执行完,第2条还没执行(a未提交时),如果此时b查询自己的帐户,就会发现自己多了100元钱。如果a等b走后再回滚,b就会损失100元。

  • 不可重复读的问题 -->在一个事务内读取表中的某一行数据,多次读取结果不同(一个事务读取到的是另外一个事务提交的数据,即另一事务修改了数据。) 。即在别的事务更改这个数据的时候,本事务只能读取一次值,这个值和更改这个数据的事务执行完之后的数据结果不同。
  • 虚读(幻读)的问题 -->虚读(幻读)是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。 

不可重复读和幻读的区别:

不可重复读是读取到了另一事务的更新

幻读是读取到了另一事务的插入(MySQL中无法测试到幻读)

1、幻读/虚读:事务T1读取一条指定where条件的语句,返回结果集。此时事务T2插入一行新记录,恰好满足T1的where条件。然后T1使用相同的条件再次查询,结果集中可以看到T2插入的记录,这条新纪录就是幻想。

2、不可重复读取:事务T1读取一行记录,紧接着事务T2修改了T1刚刚读取的记录,然后T1再次查询,发现与第一次读取的记录不同,这称为不可重复读。

3、脏读:事务T1更新了一行记录,还未提交所做的修改,这个T2读取了更新后的数据,然后T1执行回滚操作,取消刚才的修改,所以T2所读取的行就无效,也就是脏数据。

2): 四种隔离级别

为了处理这些问题,SQL标准定义了以下几种事务隔离级别

READ UNCOMMITTED 幻想读、不可重复读和脏读都允许。

READ COMMITTED 允许幻想读、不可重复读,不允许脏读

REPEATABLE READ 允许幻想读,不允许不可重复读和脏读

SERIALIZABLE 幻想读、不可重复读和脏读都不允许

1、未提交读(Read uncommitted) 
事务中的修改及时没提交也会被其他事务可见,这样会产生脏读,如果事务失败回滚,则其他事务之前的到的数据则是脏数据。从性能上讲,不会比别的事务提高太多,但是极其不安全。

2、读提交(Read committed) 
又可叫不可重复读,大多数数据库默认的隔离模式(MySQL不是)。在事务完成提交之前,其他事务看不到该事务的修改结果。执行两次同样的查询可能看到不一样的结果。

3、重复读(Repeatable read) 
事务A读取与搜索条件相匹配的若干行。事务B以插入或删除行等方式来修改事务A的结果集,然后再提交。事务A再读取时,却发现数据发生了变化。造成了幻读。(MySQL默认的隔离级别)

4、序列化(Serializable) 

Serializable是最高的事务隔离级别,同时代价也花费最高,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻像读。



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值