事务

事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功。

数据库默认事务是自动提交的,也就是发一条sql它就执行一条。如果想多条SQL语句放在一个事务中执行,则需要对数据库自动提交的默认事务进行更改。

JDBC中事务的使用:

当Jdbc程序向数据库获得一个Connection对象时,默认情况下这个Connection对象会自动向数据库提交在它上面发送的SQL语句。每条单独的语句都是一个事务。每个语句后都隐含一个commit (默认)。

一个独立SQL操作什么时候算执行完毕,JDBC规范是这样规定的:
对数据操作语言(DML,如insert,update,delete)和数据定义语言(如create,drop),语句一执行完就视为执行完毕。
对select语句,当与它关联的ResultSet对象关闭时,视为执行完毕。

对存储过程或其他返回多个结果的语句,当与它关联的所有ResultSet对象全部关闭,所有update count(update,delete等语句操作影响的行数)和output parameter(存储过程的输出参数)都已经获取之后,视为执行完毕。

若想关闭这种默认提交方式,让多条SQL在一个事务中执行,可使用下列语句:

Connection.setAutoCommit(false);但是在之后还要把事务的提交方式改回到自动提交

实例:

 1 publicvoid startTransaction(){
 2 
 3           
 4 
 5               con = DBCManager.getConnect();//获取连接对象
 6 
 7              
 8 
 9              
10 
11                             try {
12 
13                   //设置事务的提交方式为非自动提交:
14 
15               con.setAutoCommit(false);
16 
17               //将需要添加事务的代码一同放入try,catch块中
18 
19  
20 
21                   //创建执行语句
22 
23                   String sql ="delete from me where id = 7";
24 
25                   String sql1 = "update me set name ='chengong' ,age ='34' where id =4";
26 
27                   //分别执行事务
28 
29                   ps = con.prepareStatement(sql);
30 
31                   ps.executeUpdate();
32 
33                   ps = con.prepareStatement(sql1);
34 
35                   ps.executeUpdate();
36 
37                   
38 
39                   //在try块内添加事务的提交操作,表示操作无异常,提交事务。
40 
41  
42 
43                   con.commit();
44 
45                  
46 
47               } catch (SQLException e) {
48 
49               try {
50 
51                   //.在catch块内添加回滚事务,表示操作出现异常,撤销事务:
52 
53                   con.rollback();
54 
55               } catch (SQLException e1) {
56 
57                   // TODO Auto-generatedcatch block
58 
59                   e1.printStackTrace();
60 
61               }
62 
63                   e.printStackTrace();
64 
65               }finally{
66 
67                   try {
68 
69                      //设置事务提交方式为自动提交:
70 
71                      con.setAutoCommit(true);
72 
73                   } catch (SQLException e) {
74 
75                      // TODO Auto-generatedcatch block
76 
77                      e.printStackTrace();
78 
79                   }
80 
81                   DBCManager.release(rs, ps, con);
82 
83               }             
84 
85        }
86 
87  
88 
89  
View Code

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

(2) 一致性(consistency):事务在完成时,必须是所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。

(3)隔离性(Isolation)
事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。

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

 

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

如果不考虑隔离性,事务并发处理可能会引起问题:

脏读(dirty reads) 

一个事务读取了另一个未提交的并行事务写的数据。 

不可重复读(non-repeatable read)

一个事务的操作导致另一个事务前后两次读取到不同的数据

幻读(phantom read)

一个事务的操作导致另一个事务前后两次查询的结果数据量不同。

举例:
事务A、B并发执行时,
当A事务update后,B事务select读取到A尚未提交的数据,此时A事务rollback,则B读到的数据是无效的"脏"数据。
当B事务select读取数据后,A事务update操作更改B事务select到的数据,此时B事务再次读去该数据,发现前后两次的数据不一样。
当B事务select读取数据后,A事务insert或delete了一条满足A事务的select条件的记录,此时B事务再次select,发现查询到前次不存在的记录("幻影"),或者前次的某个记录不见了。

JDBC定义了五种事务隔离级别:
TRANSACTION_NONE JDBC驱动不支持事务
TRANSACTION_READ_UNCOMMITTED 允许脏读、不可重复读和幻读。
TRANSACTION_READ_COMMITTED 禁止脏读,但允许不可重复读和幻读。
TRANSACTION_REPEATABLE_READ 禁止脏读和不可重复读,单运行幻读。
TRANSACTION_SERIALIZABLE 禁止脏读、不可重复读和幻读。

通常来说,一般的应用都会选择Repeatable read或Read committed作为数据库隔离级别来使用。

mysql默认的数据库隔离级别为:REPEATABLE-READ

如何查询当前数据库的隔离级别?select @@tx_isolation;

如何查询当前数据库的隔离级别?select @@tx_isolation;

如何设置当前数据库的隔离级别?set [global/session] transaction isolation level ...;

~此种方式设置的隔离级别只对当前连接起作用。

set transaction isolation level read uncommitted;

set session transaction isolation level read uncommitted;

~此种方式设置的隔离级别是设置数据库默认的隔离级别

set global transaction isolation level read uncommitted;

共享锁:共享锁和共享锁可以共存。共享锁和排他锁不能共存。在Serializable隔离级别下一个事务进行查询操作将会加上共享锁。

排他锁:排他锁和所有锁都不能共存。无论什么隔离级别执行增删改操作时,会加上排他锁

悲观锁:悲观的认为大部分情况下进行操作都会出现更新丢失问题。

在每次进行查询的时候,都手动加上一个排他锁

            select * from table lock in share mode(读锁、共享锁)

            select * from table for update (写锁、排它锁)

乐观锁:乐观的认为大部分的情况下都不会有更新丢失问题。通过时间戳字段,

在表中设计一个版本字段version,当每次对数据库中的数据进行修改操作时,版本号都要进行增加。

如果我的程序修改比较少查询比较多:乐观锁

如果我的程序查询比较少修改比较多:悲观锁

保存点(SavePoint)
JDBC定义了SavePoint接口,提供在一个更细粒度的事务控制机制。当设置了一个保存点后,可以rollback到该保存点处的状态,而不是rollback整个事务。
Connection接口的setSavepoint和releaseSavepoint方法可以设置和释放保存点。

posted on 2015-02-03 18:19  dobestself_994395  阅读(169)  评论(0编辑  收藏  举报