一。锁的概念
1.作用:是保证数据的一致性,只能一个人修改数据,不能同时多用户修改
2.分类:行级锁和表级锁
乐观锁和悲观锁
二.事务
1.为了保证数据的一致性和完整性,让数据库的多项操作合并为一个整体,要不全部成功,要不有一个失败全部失败
2.步骤:
a.将jdbc的自动提交事务改为手动提交
b.在业务最后提交事务
c.在异常处理中回滚事务
3.事务的边界:
事务的开始:jdbc的自动提交事务改为手动提交
事务的结束:commit和rollback。如果事务没有正常结束,事务中的锁是不会释放的
4.事务隔离级别:
TRANSACTION_NONE:没有事务
TRANSACTION_READ_UNCOMMITTED:允许脏读
TRANSACTION_READ_COMMITTED:避免脏读
TRANSACTION_REPEATABLE_READ:避免不可重复读
TRANSACTION_SERIALIZABLE:可重复读
5.事务隔离级别的设定:
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);//设置事务级别,默认为该级别
实例:
1 package com.demo1212; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.SQLException; 6 7 public class TanstactionDemo { 8 //模拟转账流程 9 public static void main(String[] args) { 10 Connection conn = null; 11 PreparedStatement ps = null; 12 try{ 13 conn = JDBCFactory.getConn(); 14 //打开事务边界,就是取消自动提交,改为手动 15 conn.setAutoCommit(false); 16 //把一号账户减去500余额 17 String sql1 = "update user_info set balance=balance-500 where user_id=1"; 18 ps = conn.prepareStatement(sql1); 19 ps.executeUpdate(); 20 21 // int num = 1/0;//模拟异常情况 22 23 //把二号账户加上500余额 24 String sql2 = "update user_info set balance=balance+500 where user_id=2"; 25 ps = conn.prepareStatement(sql2); 26 ps.executeUpdate(); 27 28 conn.commit();//提交事务,正常结束 29 }catch (Exception e) { 30 try { 31 conn.rollback();//有异常发生就回滚事务,是为了保证释放锁 32 } catch (SQLException e1) { 33 e1.printStackTrace(); 34 } 35 e.printStackTrace(); 36 }finally { 37 JDBCFactory.closeAll(conn, ps, null); 38 } 39 } 40 }
锁的概念,摘自其他博客...
一、悲观锁和乐观锁
我们经常在开发中遇到数据库并发处理时,处理不一致的问题。需要对程序做并发控制。
典型的并发时出现的冲突有两种:
1、丢失更新:一个事务的更新覆盖了其它事务的更新结果,就是所谓的更新丢失。
例如X=0 A1把X=X+1 A2也设置X=X+1 如果A1和A2同时执行,可能出现最终X=1的情况。而我们需要得到的是X=2 。 这就需要update处理为串行化的。
2、脏读:读到的数据可能是旧的。 初使X=0 A1把X设置为1,A2读取时X是1,但A1后面又修改成了2,或回滚到了0,那么A2读取的数据就是脏数据。
A2读取的是未提交的数据。一般数据库不会设为读未提交,所以一般不会出现脏读。
那什么是乐观锁,什么是悲观锁。
悲观锁:需要使用数据库的锁机制,如数据库有表级排它锁,有行级排它锁。
假定一切操作都可能发现并发冲突,所以采取悲观态度。通过加锁,屏蔽一切可能违反数据完整性的操作
比方select * from table for update; 就是表锁,
select * from table where x = 1 for update; 就是行锁。
当使用for update后,其它会话还是可以执行select操作,但无法执行select xx for update操作,只有当前会话commit后,其它for update操作才会被执行。
典型例子可以参考quartz集群的锁机制:
http://blog.itpub.net/11627468/viewspace-1764753/
当然,此时也不可以update,update需要等select xx for update 所在会话commit后才能执行。
注:mysql需要设置autocommit=0
乐观锁:其实不是真实的去锁住记录不让访问,或者不让更新。
假定操作很少发生冲突,一般对于读多写少的情况。只在提交操作时检查是否违反数据完整性。[1] 乐观锁不能解决脏读的问题。
可以通过版本号是否比上个版本号或者时间戳来实现。
对于冲突检测后的处理,需要业务逻辑去处理。
二、排它锁和共享锁
在数据库中有两种基本的锁类型:排它锁(Exclusive Locks,即X锁)和共享锁(Share Locks,即S锁)。
当数据对象被加上排它锁时,其他的事务不能对它读取和修改。
加了共享锁的数据对象可以被其他事务读取,但不能修改。
数据库利用这两种基本的锁类型来对数据库的事务进行并发控制。
三、表级锁和行级锁
DML锁的目的在于保证并发情况下的数据完整性,主要包括TM锁和TX锁,其中TM锁称为表级锁,TX锁称为事务锁或行级锁。
当Oracle执行DML语句时,系统自动在所要操作的表上申请TM类型的锁。当TM锁获得后,系统再自动申请TX类型的锁,并将实际锁定的数据行的锁标志位进行置位。这样在事务加锁前检查TX锁相容性时就不用再逐行检查锁标志,而只需检查TM锁模式的相容性即可,大大提高了系统的效率。TM锁包括了SS、SX、S、X等多种模式,在数据库中用0-6来表示。不同的SQL操作产生不同类型的TM锁。
值 锁模式 锁描述 SQL
0 NONE 1 NULL 空 SELECT
2 SS(ROW-S) 行级共享锁
其他对象只能查询这些数据行 SELECT FOR UPDATE、LOCK FOR UPDATE、
LOCK ROW SHARE
3 SX(ROW-X) 行级排它锁
在提交前不允许做DML操作 INSERT、UPDATE、DELETE、
LOCK ROW SHARE
4 S(SHARE) 共享锁 CREATE INDEX、LOCK SHARE
5 SSX(S/ROW-X) 共享行级排它锁 LOCK SHARE ROW EXCLUSIVE
6 X(eXclusive) 排它锁 ALTER TABLE、DROP TABLE、DROP INDEX、
TRUNCATE TABLE、LOCK EXCLUSIVE
四、几个问题
1.UPDATE/DELETE操作会将RS锁定,直至操作被COMMIT或者ROLLBACK;
若操作未COMMIT之前其他session对同样的RS做变更操作,则操作会被hold,直至前session的UPDATE/DELETE操作被COMMIT;
2.session内外SELECT的RS范围
前提:INSERT、UPDATE操作未COMMIT之前进行SELECT;
若在同一session内,SELECT出来的RS会包括之前INSERT、UPDATE影响的记录;
若不在同一session内,SELECT出来的RS不会包括未被COMMIT的记录;
3.SELECT.... FOR UPDATE [OF cols] [NOWAIT/WAIT] [SKIP LOCKED]
OF cols:只锁定指定字段所在表的RS,而没有指定的表则不会锁定,只会在多表联合查询时出现;
NOWAIT:语句不会hold,而是直接返回错误ORA-00054: resource busy and acquire with NOWAIT specified;
WAIT N:语句被hold N秒,之后返回错误ORA-30006: resource busy; acquire with WAIT timeout expired;
SKIP LOCKED:不提示错误,而是直接返回no rows selected;
以上几个选项可以联合使用的,比较推荐的有:
SELECT.... FOR UPDATE NOWAIT:对同一RS执行该SQL时,直接返回错误;
SELECT.... FOR UPDATE NOWAIT SKIP LOCKED:对同一RS执行该SQL时,直接返回空行;
PS:当RS被LOCK住之后,只对同样请求LOCK的语句有效,对无需LOCK的SELECT语句并没有任何影响;
以上悲观锁和乐内容参考:
http://www.cnblogs.com/guyufei/archive/2011/01/10/1931632.html
spring锁实现参数:
http://blog.itpub.net/12158104/viewspace-374745
关于隔离级别可以参考:
http://blog.itpub.net/11627468/viewspace-1793036/
关于数据库的锁可以参考:
http://zhidao.baidu.com/link?url=zRnaslJ8INtEviT--BzrT2bMOqf4LJQzL-NQg2ECu6l-s-xPHi11bBlNjN2_zyNrwd9M0ZnbelQntmfYPB0ifq