数据库 | 青训营笔记

89 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第1篇笔记

数据库

外键

外键的优缺点:

(1) 实现表与关联表之间的数据一致性; (2) 可以迅速的建立一个可靠性非常高的数据库结构,而不用让应用程序层去做过多的检查; (3) 可以提高系统鲁棒性、健壮性; (4) 可以实现开发人员和数据库设计人员的分工;

缺点: (1) 数据库需要维护外键的内部管理; (2) 外键等于把数据的一致性事务实现,全部交给数据库服务器完成; (3) 有了外键,当做一些涉及外键字段的增,删,更新操作之后,需要触发相关操作去检查,而不得不消耗资源; (4) 外键还会因为需要请求对其他表内部加锁而容易出现死锁情况; (5) 容易出现数据库I/O的瓶颈;

乐观锁和悲观锁

image.png

  • 乐观锁:乐观锁在操作数据时非常乐观,认为别人不会同时修改数据。因此乐观锁不会上锁,只是在执行更新的时候判断一下在此期间别人是否修改了数据:如果别人修改了数据则放弃操作,否则执行操作。

    • 乐观锁的版本号机制

    在表中设计一个版本字段 version,第一次读的时候,会获取 version 字段的取值。然后对数据进行更新或删除操作时,会执行UPDATE ... SET version=version+1 WHERE version=version。此时如果已经有事务对这条数据进行了更改,修改就不会成功。

    这种方式类似我们熟悉的 SVN、CVS 版本管理系统,当我们修改了代码进行提交时,首先会检查当前版本号与服务器上的版本号是否一致,如果一致就可以直接提交,如果不一致就需要更新服务器上的最新代码,然后再进行提交。

    • 乐观锁的时间戳机制

      时间戳和版本号机制一样,也是在更新提交的时候,将当前数据的时间戳和更新之前取得的时间戳进行比较,如果两者一致则更新成功,否则就是版本冲突。

  • 悲观锁:悲观锁在操作数据时比较悲观,认为别人会同时修改数据。因此操作数据时直接把数据锁住,直到操作完成后才会释放锁;上锁期间其他人不能修改数据。

  • 乐观锁和悲观锁的适用场景:

    1. 乐观锁适合读操作多的场景,相对来说写的操作比较少。它的优点在于程序实现,不存在死锁问题,不过适用场景也会相对乐观,因为它阻止不了除了程序以外的数据库操作。
    2. 悲观锁适合写操作多的场景,因为写的操作具有排它性。采用悲观锁的方式,可以在数据库层面阻止其他事务对该数据的操作权限,防止读 - 写和写 - 写的冲突。

ORM

ORM (Object Relation Mapping)的作用就是建立了对象关系映射。模型的每个属性代表数据表中的一个字段,我们通过操作类实例对象,对数据表中的数据行进行增删改查等操作。

image.png

Gorm

Gorm可以防止SQL注入,更加安全的原因。

参考:Gorm 和 Go 端的 SQL 预编译

在 Gorm 中,就为我们封装了 SQL 预编译技术,可以供我们使用。

db = db.Where("merchant_id = ?", merchantId)

在执行这样的语句的时候实际上我们就用到了 SQL 预编译技术,其中预编译的 SQL 语句merchant_id = ?和 SQL 查询的数据merchantId将被分开传输至 DB 后端进行处理。

db = db.Where(fmt.Sprintf("merchant_id = %s", merchantId))

而当你使用这种写法时,即表示 SQL 由用户来进行拼装,而不使用预编译技术,随之可能带来的,就是 SQL 注入的风险。