• 数据库三大范式以及数据库事务,数据库锁


    一:数据库基本设计以及三大范式

    数据库:简而言之可视为电子化的文件柜(存储电子文件的处所),用户可以对文件中的数据进行新增、截取、更新、删除等操作。它分为关系型数据库和非关系型数据,今天我们着重来讲一下关系型数据库。

    1:什么是关系型数据库?其实说白了就是把对象封装起来,然后来表述对象与对象之间的关系。

    2:数据关系一般分为几种,分别是什么?数据关系有三种,分别为一对一,一对多,多对多。下面分别解释举例说明一下这三种关系

    • 一对一:比如一个人对应一张身份证,对应一个护照号,人跟身份证,人跟护照号这样就属于一对一的关系,一般两者之间的关系通过主外键或者相同主键。
    • 一对多:国家对省,省对城市,城市对区域等,这些属于一对多的关系,一般两者之间的联系是通过主外键联系的。
    • 多对多:学生对班级,老师对学生,这些是属于多对多的关系,两者之间的联系通过关系/映射/中间表。

    3:上面的数据库以及之间的关系,已经解释ok,那怎么做数据设计?可以根据以下三部

    • 需求分析,调研讨论明白需要存储什么

    • 概要设计,E-R图设计,把表/属性的关系图使用powerdesigner或者codefirst画出来,解决多方面的沟通问题
    • 详细设计,把表字段对应的属性映射对应出来(一般这一步会省略掉,主要最多的是1,2步)

    4:数据库设计一般会遵循三大范式,分别是什么?下面解析说明。

      A:每一列保持原子性,不可分割;

    学员ID 学员名字 家庭信息
    1 可可 3口人,河南
    2 馨馨 4口人,上海

     如上图的家庭信息这一栏,我们如果这样写,那就是违背了原子性,因为家庭信息是可以分割的,可以分拆为家庭人员数,户籍所在地,可以拆分成如下:

    学员ID 学员名字 家庭人员  信息
    1 可可 3口人  河南
    2 馨馨 4口人

    上海

    B:每一列都得跟主键相关,一张表只应该描述一个对象;这个需要注意两点,一是:主键 ,二是:信息跟主键相关

    ID 员工名字 公司名字 公司地址
    1 可可 缘爱 上海
    2 馨馨 可馨

    深圳

    比如上面的员工表,里面增加了员工公司的一些信息,这样就违背了第二大范式,通过修改如下下面即可:

     员工表:

    ID 员工名字 公司Id
    1 可可 1
    2 馨馨 2

    公司表:

    ID 公司名字 公司地址
    1 缘爱 上海
    2 可馨

    深圳

       C:每一列都得跟主键直接相关,而不是间接相关,如下面的公司名称就属于违背了第三大范式,但是有时候为了方便查询,第三大范式经常会被违背的,这个还要根据具体的业务逻辑去选择的。

    ID 员工名字  公司Id 公司名字
    1 可可  1 缘爱
    2 馨馨  2 可馨

    以上三大范式只是建议,其实都有可能被违背,话说一将不行,累死三军,所以正确的设计,会减少很多工作量。

    二:数据库事务

    1:什么是事务?事务是多条sql作为一个整体提交给数据库系统,要么全部执行完成,要么全部取消。是一个不可分割的逻辑单元。其实我们经常见到的单条update或者insert就是一个简单的事务。

    2:为什么要用事务?事务保证一起成功或者一起失败,比如sql语句,一个下订单成功;另一个减掉库存;如果不使用事务,有可能刚刚执行下单成功,但是在执行减掉库存的时候错误,则会造成订单和库存不能保证统一的。

    3:事务的基本语法

     1 ******************************事务sql***********************************
     2 
     3 ---开启事务
     4  begin tran
     5  --错误扑捉机制,看好啦,这里也有的。并且可以嵌套。
     6  begin try  
     7     --语句正确
     8     insert into [Company] (Name,CreateTime,CreatorId) values ('字节','2019-03-20',1)
     9     --CreatorId为int类型,出错
    10     insert into [Company] (Name,CreateTime,CreatorId) values ('新启','2019-03-20','Test')
    11     --语句正确
    12     insert into [Company] (Name,CreateTime,CreatorId) values ('舞动','2019-03-20',2)
    13  end try
    14  begin catch
    15     select Error_number() as ErrorNumber,  --错误代码
    16            Error_severity() as ErrorSeverity,  --错误严重级别,级别小于10 try catch 捕获不到
    17            Error_state() as ErrorState ,  --错误状态码
    18            Error_Procedure() as ErrorProcedure , --出现错误的存储过程或触发器的名称。
    19            Error_line() as ErrorLine,  --发生错误的行号
    20            Error_message() as ErrorMessage  --错误的具体信息
    21     if(@@trancount>0) --全局变量@@trancount,事务开启此值+1,他用来判断是有开启事务
    22        rollback tran  ---由于出错,这里回滚到开始,第一条语句也没有插入成功。
    23  end catch
    24  if(@@trancount>0)
    25  commit tran  --如果成功Company表中,将会有3条数据。
    26  
    27  --表本身为空表,ID ,Numb为int 类型,其它为nvarchar类型
    28  select * from [Company]
    29 
    30 
    31 
    32 ******************************事务含save tran***********************************
    33 
    34 ---开启事务
    35  begin tran
    36  --错误扑捉机制,看好啦,这里也有的。并且可以嵌套。
    37  begin try  
    38     --语句正确
    39     insert into [Company] (Name,CreateTime,CreatorId) values ('字节','2019-03-20',3)
    40     --加入保存点,如果下面的出错了,上面的还能保存
    41     save tran SavePoint
    42     --CreatorId为int类型,出错
    43     insert into [Company] (Name,CreateTime,CreatorId) values ('新启','2019-03-20','Test')
    44     --语句正确
    45     insert into [Company] (Name,CreateTime,CreatorId) values ('舞动','2019-03-20',4)
    46  end try
    47  begin catch
    48     select Error_number() as ErrorNumber,  --错误代码
    49            Error_severity() as ErrorSeverity,  --错误严重级别,级别小于10 try catch 捕获不到
    50            Error_state() as ErrorState ,  --错误状态码
    51            Error_Procedure() as ErrorProcedure , --出现错误的存储过程或触发器的名称。
    52            Error_line() as ErrorLine,  --发生错误的行号
    53            Error_message() as ErrorMessage  --错误的具体信息
    54     if(@@trancount>0) --全局变量@@trancount,事务开启此值+1,他用来判断是有开启事务
    55        rollback tran  ---由于出错,这里回滚到开始,第一条语句也没有插入成功。
    56  end catch
    57  if(@@trancount>0)
    58  rollback tran SavePoint  --如果成功Company表中,将会有3条数据。
    59  
    60  --表本身为空表,ID ,Numb为int 类型,其它为nvarchar类型
    61  select * from [Company]
    View Code
    --开始事务
    begintransaction tran_bank;
    declare @tran_error int;
    set @tran_error = 0;
    begin try
    update bank set totalMoney = totalMoney - 10000 where userName = 'jack';        
    set @tran_error = @tran_error + @@error;
    update bank set totalMoney = totalMoney + 10000 where userName = 'jason';
    set @tran_error = @tran_error + @@error;
    end try
    begin catch        
    print'出现异常,错误编号:' + convert(varchar, error_number()) + ', 错误消息:' + error_message(); 
    set @tran_error = @tran_error + 1;
    end catch
    if (@tran_error > 0)
    begin
            --执行出错,回滚事务
    rollbacktran;
    print'转账失败,取消交易';
    end
    else
    begin
            --没有异常,提交事务
    committran;
    print'转账成功';
    end
    go
    View Code

    4:事务的特点为ACID

    原子性:要么都成功,要么都失败,一个事务中不可能停滞在中间某个环节。事务发送问题就会被回滚到事务执行之前的状态,就像没有执行过一样。

    一致性:如果事务是并发,系统也会把事务串起来,一个一个的按序执行。

    隔离线:AB两个事务同时操作一张表,B事务要么是在A事务前完成,要么是在A事务完成后执行,事务操作表的时候会锁表

    持久性:事务一旦提交,则数据就会被固化下来,持久存在,直到下次再被修改。

    三:数据锁

    1:为什么要使用锁?

    多数据同时访问一个数据资源时,保证操作有个先后顺序管理,处理并发问题,防止数据

    A:修改丢失 例:多并发操作一张表,一个读,一个删除或者修改

    B:不可重复读 例:多并发操作一张表,一个读,一个改或者删除

    C:脏读/幻读 例:多并发操作一张表,一个修改一半,一个读取

    2:数据锁一般分为几种?

    A:乐观锁:认为没有并发,读取数据--更新数据---保存,比如更新数据时做一个判断,可以使用时间戳/Version/检查更新字段/检查全部字段作为where条件,其实这个是按照业务逻辑来定的,不过要保证所有的操作都按照这个规范来操作,不然也会有漏洞,比如通过其它渠道更新,乐观锁的好处是性能高。

    B:悲观锁:认为任何时候都有可能有多线程并发,比如读数据时别人恰好在修改。悲观锁是基于数据锁的机制来完成,它分为:

    • 共享锁 S锁 读锁,允许别的事务来读,但是不允许修改;读完就释放,锁定数据页;(除非holdlock就一直锁定)
    • 排他锁 X锁 写锁,准备写数据,不允许读也不允许写;
    • 更新锁 U锁   ,先查询再更新;

    其实按照其它的方式可以分为行锁(where id=3),表锁(where 1=1)

    3:怎么避免死锁?

    • 不用锁就不会死锁,乐观锁
    • 统一操作顺序--先A后B再C
    • 最小单元锁,锁里面操作尽量减少
    • 避免事务中等待用户输入
    • 减少数据库并发
    • 分库分表表分区
    • 降低事务级别
    • 设置死锁时间  set lock_timeout(锁超时时间)

    备注:其实高并发下死锁是不可能避免的,只能减少。

  • 相关阅读:
    利用Lambda获取属性名称
    Entity Framework 6.0 源码解读笔记(一)
    [转]Sql server2005中如何格式化时间日期
    python之路_RabbitMQ相关介绍
    python之路_redis相关介绍
    python之路_django之contenttype介绍
    python之路_最简单的Git介绍
    python之路_rest-framework之分页、路由、视图、渲染
    python之路_rest-framework之版本、解析器、序列化
    python之路_rest-framework之认证、权限、频率
  • 原文地址:https://www.cnblogs.com/loverwangshan/p/10570446.html
Copyright © 2020-2023  润新知