zoukankan      html  css  js  c++  java
  • oracle之事务和锁

    一、事务

      首先,我们先介绍什么是PL/SQL。什么是PL/SQL?PL/SQL也是一种程序语言,叫做过程化程序语言(procedural Language/SQL),PL/SQL是oracle数据库对SQL语句的扩展。在普通SQL语句的使用上增加了编程语言的特点,所以PL/SQL就是把数据操作和查询语句组织在PL/SQL代码的过程性单元中,通过逻辑判断,循环等操作实习复杂的功能或者计算的程序语言。

      1、事务的介绍与应用。

      什么是事务,事务是之一个业务逻辑单元执行的一系列操作,这些操作作为一个整体向系统提交,这个整体的全部步骤要么全部成功,要么全部失败。

      事务的特性(ACID):

      原子性:事务的所有步骤必须是一个整体,要么全部成功要么全部失败
      一致性:整个业务逻辑单元执行完成后,数据要保持一致
      隔离性:各个并发事物之间不相互影响
      持久性:事务一旦提交,对数据的影响是永久的  

      语法

      declare --可选部分
        变量、常量、游标、用户自定义异常的声明
      begin --必须部分
        sql语句的程序块
      exception --可选部分
        程序出现异常的时候,捕获异常并处理异常
      end--必须部分

      下面是一个输出“hello world”的案例:

    declare
      --声明一个名叫str的变量,类型是varchar2
      str varchar2(30);
    begin
         --为变量赋值
         str:='Hello World';
         --在控制台输出
         dbms_output.put_line(str);
    end;

      下面是一个转账事务,若转账出现异常,可以回滚事务,那么之前的操作都不生效。

    --帐户表
    create table t_account(
           id int primary key,
           uname varchar2(30) not null,
           money number default 0
    );
    /*添加帐户数据*/
    insert into t_account values(1,'阡陌',1000000);
    insert into t_account values(2,'雅琪老师',0);
    --开始转账
    declare 
           turnMoney number;--存储转账的金额
           division number;--除数
    begin
      --提示用户输入转账金额
      turnMoney:='&请输入转账金额';
      --将点点同学的用户金额减少turnMoney
      update t_account set money = money - turnMoney where uname='点点';
      --division:=1/0;(此处制造一个异常)
      --将money增加到雅琪老师帐户
      update t_account set money = money + turnMoney  where uname='雅琪老师';
      commit;
       exception --异常处理
               when others then --捕获所有错误
                 dbms_output.put_line('出现错误,'||SQLERRM||'之前的操作回滚!');
                 rollback;--回滚事务
    end;

      下面继续看一个事务保存点案例:涨薪事务,设置了保存点的事务,当出现异常时,可以回滚到指定的地方。

    --加工资  事务保存点案例
    create table t_emp as select * from emp;--复制emp表
    
    select e.ename,e.sal,t.sal tsal from emp e,t_emp t where e.empno = t.empno
    
    declare 
           money number;--涨工资的金额
           division number;--除数
    begin
           money:='&请输入涨工资的金额';
           --为SMITH FORD JAMES MILLER JONES 涨薪
           UPDATE T_EMP SET SAL = SAL+MONEY WHERE ENAME='SMITH';
           UPDATE T_EMP SET SAL = SAL+MONEY WHERE ENAME='FORD';
           UPDATE T_EMP SET SAL = SAL+MONEY WHERE ENAME='JAMES';
           UPDATE T_EMP SET SAL = SAL+MONEY WHERE ENAME='MILLER';
           --设置保存点
           SAVEPOINT A;
           UPDATE T_EMP SET SAL = SAL+MONEY WHERE ENAME='JONES';
           division:=1/0;--出现异常
         
           EXCEPTION 
                  WHEN OTHERS THEN
                       DBMS_OUTPUT.put_line('出现错误'||SQLERRM);
                       ROLLBACK TO A;--回滚到保存点A
            commit;--提交所有步骤
    end;

      注意:在事务中的DML(update insert delete)操作都是需要commit的,否则不会生效,而DDL(CREATE ALTER DROP TRUNCATE),DCL(GRANT REVOKE)操作则不需要,他们执行后会自动提交。

    二、锁

      什么是锁?加锁是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据对象进行操作之前,先向系统发出请求,对其加锁。加锁后事务就对该数据对象有了一定的控制,在该事务释放锁之前,其他的事务不能对此数据对象进行更新操作。

      基本锁类型:排它锁(X锁)和共享锁(S锁)。当数据对象被加上排它锁时,其它事务不能对它读取和修改。加了共享锁的数据可以被其它事务读取,但不能修改。数据库利用这两种基本的锁类型来对数据库的事务进行并发控制。

      根据保护的对象不同,oracle数据库锁可以分为以下几大类:DML锁(data locks,数据锁),用于保护数据的完整性;DDL锁(dictionary locks,字典锁),用于保护数据库对象的结构,如表,索引等的结构定义。

      排它锁和共享锁:

    --锁 排他锁 (不允许读取和修改) 共享锁(允许读取不允许修改)
    create table t_user(
          fid int primary key,
          fname varchar2(30) not null
    );
    insert into  t_user values(1,'熬夜');
    insert into t_user values(2,'点点');
    insert into t_user values(3,'Moco');
    
    --在ORACLE执行DML(insert(有主键) update delete)语句会产生阻塞
    update t_user set fname = 'Jaydy' where fid=1;
    --在新窗口中执行(上一条sql没commit,新窗口的语句会等待)
    update t_user set fname='仰望天空' where fid=1;
    
    /*
       当执行dml,系统会自动在所要操作的表上申请表级类型的锁 ddl
       当表级锁申请到以后,系统在自动申请行级类型的锁 dml
    */

      悲观锁和死锁:

    --悲观锁
    select * from 表名 [where] for update;
    select rowid,p.* from emp p;
    select * from t_emp where sal>2000  for update
    --死锁案例
    --用户订单表
    create table t_order (
           fid int primary key,
           productName varchar2(30),
           fUserId int
    );
    insert into t_order values(1,'NIO',1);
    --在A窗口执行
    update t_user set fname='熬夜' where fid=1;
    --在b窗口中执行
    update t_order set productName='彭坚' where fid=1;
    --在A窗口执行
    update t_order set productName='mark' where fid=1;
    ----在b窗口中执行
    update t_user set fname='熬夜' where fid = 1;
    /*造成死锁*/
    /**
       从设计解决,注意多用户并发处理,不同用户之间的相互影响。特别时相互之间对行的影响
    **/
  • 相关阅读:
    UVA 254 Towers of Hanoi
    UVA 701 The Archeologists' Dilemma
    UVA 185 Roman Numerals
    UVA 10994 Simple Addition
    UVA 10570 Meeting with Aliens
    UVA 306 Cipher
    UVA 10160 Servicing Stations
    UVA 317 Hexagon
    UVA 10123 No Tipping
    UVA 696 How Many Knights
  • 原文地址:https://www.cnblogs.com/wanglitao/p/4908747.html
Copyright © 2011-2022 走看看