mysql数据库中的事务

1. 什么是事务:

事务中有多个操作,这些操作的执行结果要么完全成功,要么完全失败,不可能出现一部分成功,一部分失败的情况。比如说转账业务:张三给李四转100w,那么有两个操作,一个是张三减去100w,李四加上100w,两个操作都成功,要么都失败,不能出现张三减了100w,李四没有加上100w的情况。

2.事务的四种特性:

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

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

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

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

3.与事务有关的几个方法:

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

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

Connection.rollback():回滚事务。

4.jdbc处理事务的格式:

try {

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

  ….

  …

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

} catch() {

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

}

 

5.事务的简单例子:

以插入数据为例,同时执行插入两条数据,这两条数据要么都成功插入到数据库中,要么都不能成功的插入到数据库中。

publicint insertUser(){

                   int count = 0;

                   String sql = "insertinto user values(?,?)";

                   PreparedStatementprepareStatement = null;

 

                   try {

                            //手动提交,也就是执行了sql语句但是不同步到数据库中,只有两个都正确,才会自动提交到数据库中。

                            connection.setAutoCommit(false);

                            prepareStatement =connection.prepareStatement(sql);

 

                            prepareStatement.setString(1,"zhang");

                            prepareStatement.setString(2,  "123456");

//插入到数据库张三的数据,张三这个数据是数据库的主键。

                            prepareStatement.execute();

                           

                            prepareStatement.setString(1,"zhang");

                            prepareStatement.setString(2,"123456");

//再次相数据库中插入张三这条数据时,因为张三主键已经存在了,所以执行是不成功的

                            prepareStatement.execute();

//当第二条数据执行不成功时,就会抛出异常

                            connection.commit();

                   } catch (SQLException e) {

                            //执行不成功回滚,回滚到两条数据都没插入之前的数据库状态。

                            try {

                                     connection.rollback();

                            } catch(SQLException e1) {

                                     System.out.println("回滚失败!");

                            }

                           

                            throw newRuntimeException(e.getMessage());

                   }finally{

                            try {

                                     prepareStatement.close();

                            } catch(SQLException e) {

                                     e.printStackTrace();

                            }

                           

                            try {

                                     connection.close();

                            } catch(SQLException e) {

                                     // TODOAuto-generated catch block

                                     e.printStackTrace();

                            }

                   }

                  

                   return count;

}

6.事务的隔离级别:

6.1事务的并发问题:

           脏读:读到另一个事务未提交的更新数据,即读到了脏数据。

           不可重复读:两次读取同一个数据读到的结果不一样。即另一事务修改了事务。

           幻读:对同一张表两次读到的数据不一样,应为另一条事务插入了新的记录。

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

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

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


7.数据库内部定义了四种隔离级别,用于解决三种隔离问题

1 Serializable:可避免脏读、不可重复读、虚读情况的发生。(串行化)

2 Repeatable read:可避免脏读、不可重复读情况的发生。(可重复读)不可以避免虚读

3 Read committed:可避免脏读情况发生(读已提交)

4 Read uncommitted:最低级别,以上情况均无法保证。(读未提交)

 

操作数据库内部隔离级别

set session transaction isolation level 设置事务隔离级别

select @@tx_isolation   查询当前事务隔离级别

 

实验一:演示脏读发生

在A窗口将隔离级别设置 read uncommitted

A、B窗口同时开启事务

B窗口执行转账操作update account set money = money - 500 where name='bbb';

update account set money = money + 500 where name ='aaa'; 未提交事务

A窗口查询 select *from account; 查询到转账结果(脏读)

B 回滚 rollback

A窗口查询 金钱丢失

 

实验二:演示不可重复读

在A窗口设置隔离级别 read committed; 重复实验一,发现无法脏读

B窗口转账后,提交事务

A窗口查询到 B提交的数据 (不可重复读)

 

实验三:演示阻止不可重复读发生

在A窗口设置隔离级别 repeatable read 重复试验二,发现不会发生不可重复读

 

实验四:演示serializable 串行事务效果

A窗口设置隔离级别serializable

A、B同时开启事务

B窗口插入一条数据insert into account values(null,'ddd',1000);

在A窗口查询数据 select * from account;

发现A 窗口阻塞了,等待B事务执行结束

 

安全性:serializable > repeatableread > read committed > read uncommitted

性能 :serializable < repeatable read < read committed < readuncommitted

 

结论: 实际开发中,通常不会选择 serializable 和 read uncommitted , mysql默认隔离级别repeatable read ,oracle默认隔离级别 read committed

 

JDBC程序中能否指定事务的隔离级别 ?

Connection接口中定义事务隔离级别四个常量:

static int TRANSACTION_READ_COMMITTED

          指示不可以发生脏读的常量;不可重复读和虚读可以发生。

static int TRANSACTION_READ_UNCOMMITTED

          指示可以发生脏读 (dirty read)、不可重复读和虚读 (phantom read) 的常量。

static int TRANSACTION_REPEATABLE_READ

          指示不可以发生脏读和不可重复读的常量;虚读可以发生。

static int TRANSACTION_SERIALIZABLE

          指示不可以发生脏读、不可重复读和虚读的常量。

 

通过 void setTransactionIsolation(intlevel) 设置数据库隔离级别


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值