Java开发 - 数据库中的基本数据结构(一)

简介: Java开发 - 数据库中的基本数据结构

目录


前言

锁按照粒度分,可以分为两种:

锁按照类型来分,也可分为两类:

悲观锁和乐观锁

版本号机制

CAS

事务

什么是事务?

事务的特性

数据库中的事务

查询命令

关闭命令

开启命令

事务的管理

数据库中的死锁

数据库中的视图

什么是视图?

操作视图:

视图的注意事项

事务隔离级别

读未提交

读已提交

可重复读

可串行化

用一张表来表示他们之间的关系:

隔离等级的优先级

数据库使用的隔离级别

MVCC

隐藏字段作用

ReadView

结语


前言


常用的数据库有哪些呢?以博主的认知为例,见过最多的就是以下这三种了:


oracle,sql server和mysql


虽然同为数据库,数据结构也是存在着一些细微的差别的,这个我们后面会简单提到,毕竟都是按照sql的统一规范设计的数据库,才有了相同的增删改查功能,所以他们的差别也大不到哪去,这里先提一嘴,这三者的隔离级别不同。


其实本来也想写写sql语句中的一些坑和注意事项的,但想了想,放在数据结构里略微不合适,还是后期专门开一篇讲讲sql语句中踩到的坑和注意事项吧。



锁按照粒度分,可以分为两种:


表锁行锁从名字也不难推测出它们所处的位置。顾名思义,表锁是加在整张表上的,其他的事务将无法在当前事务执行期间访问整张表,行锁是加在单独的某一行上的,其他事务无法在当前事务执行时访问这一行。这也是我们平时所说的线程安全的一部分,只不过是放在数据库上面的。


锁按照类型来分,也可分为两类:


共享锁


排他锁共享锁也叫share锁/s锁,既可以给表加,也可以给行加,因为其共享特性,所以加上了共享锁的数据,允许其他事务同时访问,但是绝对不允许其他事务给他再加排他锁,却依然可以允许其他事务加共享锁。多用于读操作。


排他锁有些地方也叫独占锁/x锁,被加上排他锁的数据,既不允许其他事务再加共享锁,也不允许其他事务再加排他锁,同时,在当前事务执行结束前,其他事务无法访问。多用于写操作。


数据库中,我们经常使用的读写sql语句为:


select....

insert...

delete...

update...

其中,增删改操作默认给操作的行数据加排它锁,select操作默认不加任何锁。


如果需要在查询时加锁,怎么做呢?


查询加共享锁

select......    所有条件之后 + lock in share mode


查询加排它锁

select......    所有条件之后 + for update


因为我们操作的都是行数据,所以基本上都是加行锁,除非使用模糊查询,才会加表锁。这个和数据库的存储引擎有关。以mysql为例,mysql从5.5开始,存储引擎变成InnoDB,默认加行锁,之前的引擎默认加表锁。


悲观锁和乐观锁


悲观锁和乐观锁不同于行锁和表锁,他们只是两种思想。


悲观锁:当多线程或者事务并发执行的时候,事务会悲观的认为,在自己访问数据期间,其他事务一定会同时访问,为了安全着想,事务再访问数据时,立即给这条数据加锁以保证数据是线程安全的。这很像是一个对自身保护过度的人,所以由此可见,悲观锁的效率一定是偏低的。排他锁符合这种特性,所以排他锁都是悲观锁。


乐观锁:和悲观锁相反,数据访问期间,事务很乐观,认为在自己访问期间不会有其他的事务访问,也不会有线程安全问题,所以就不加锁。但在实际中这是不存在的,一定会存在同时访问的情况,这时候,乐观锁会通过其他的机制来保证线程的安全,分别是版本号机制或CAS(compare and swap  比较并交换)。


假设我有一张user表:

id name age
1 张三 20
2 李四 25

两个线程

线程A:查询张三,并修改其年龄为23

1.查询张三数据

2.执行修改

3.提交事务

线程B:查询张三,并修改其年龄为24

1.查询张三数据

2.执行修改

3.提交事务

若是两个线程同时执行,那么A预期的年龄为23,B预期的年龄为24,不管谁先执行,最后得到的数据,只能是符合其中一个的预期,这样就有问题了。


我们用悲观锁的思想来解决,给行数据加锁,就会变成其中一个先执行,执行完之后另一个线程再执行,这当然可以。但我们想要用乐观锁来做,该怎么做呢?需要使用版本号机制。


版本号机制


依然是这张表,只是多了一个版本号,初始值我们给0.

id name age version
1 张三 20 0
2 李四 25 0

两条线程一起执行

线程A:查询张三,并修改其年龄为23

1.查询张三数据,version=0

2.执行修改,age=23,version=0

3.提交事务,需要对比版本号是否等于查询时的版本号0,相等,执行成功,version+1=1.

线程B:查询张三,并修改其年龄为24

1.查询张三数据,version=0

2.执行修改,age=24,version=0

3.提交事务,需要对比版本号等于产巡视的版本号0,此时版本号为1,不等,执行失败。

版本号机制在提交事务的时候会对查询时的版本号进行对比,对比相等,提交,执行成功,对比 不想等,执行失败,事务回滚。


失败后,因为乐观锁中有一个自旋机制,在失败后会重新发起修改,此时线程A已经执行完毕,线程B中心执行,此时version=1,查询到version=1,提交时,只要没有其他线程参与,version仍为1,提交成功,此时version=2。如果有其他的线程参与导致此次修改再次失败,自旋不会无限自旋,它有一个设置时间,可自定义。


CAS


CAS其实在理解了版本号机制之后就很好理解了。

还是这张user表:

id name age
1 张三 20
2 李四 25

还是这两个线程:

线程A:查询张三,并修改其年龄为23

1.查询张三数据

2.执行修改

3.提交事务

线程B:查询张三,并修改其年龄为24

1.查询张三数据

2.执行修改

3.提交事务

俩线程执行完之后,必然会有其中一个的值被覆盖,这就产生了线程安全问题。在版本号机制中,我们比较的是version,但是在CAS中,我们比较的是值本身,如果修改的时候值和查询时的值不一样,那么进行回滚,自旋机制启动,这时候就和version机制是一样的了。


这样一看,版本号机制和CAS是不是很相似呢?只是比较的对象不一样。


现在,你理解这两种机制了么?


在这里给大家留一个问题,悲观锁和乐观锁哪一个用的多?大家可以评论区讨论下并说说具体原因?


事务


什么是事务?


事务是数据库中执行操作的最小执行单元,不可再分,要么全都执行成功,要么全都执行失败。


事务的特性


原子性

事务是数据库的逻辑工作单位,原子性是指事务包含的所有操作要么全部成功,要么全部失败。


一致性

一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。一致性与原子性是密切相关的。


隔离性

一个事务的执行不能被其他事务干扰


持久性

一个事务一旦提交,它对数据库中数据的改变就应该是永久性的

在前面,我们已经接触到了一些特性,比如原子性,其他的特性也都是相关的联的,不可能单个存在。

目录
相关文章
|
2天前
|
XML Java 数据库连接
性能提升秘籍:如何高效使用Java连接池管理数据库连接
在Java应用中,数据库连接管理至关重要。随着访问量增加,频繁创建和关闭连接会影响性能。为此,Java连接池技术应运而生,如HikariCP。本文通过代码示例介绍如何引入HikariCP依赖、配置连接池参数及使用连接池高效管理数据库连接,提升系统性能。
15 5
|
4天前
|
存储 SQL API
探索后端开发:构建高效API与数据库交互
【10月更文挑战第36天】在数字化时代,后端开发是连接用户界面和数据存储的桥梁。本文深入探讨如何设计高效的API以及如何实现API与数据库之间的无缝交互,确保数据的一致性和高性能。我们将从基础概念出发,逐步深入到实战技巧,为读者提供一个清晰的后端开发路线图。
|
2天前
|
存储 缓存 NoSQL
2款使用.NET开发的数据库系统
2款使用.NET开发的数据库系统
|
6天前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
22 6
|
6天前
|
存储 SQL 数据库
深入浅出后端开发之数据库优化实战
【10月更文挑战第35天】在软件开发的世界里,数据库性能直接关系到应用的响应速度和用户体验。本文将带你了解如何通过合理的索引设计、查询优化以及恰当的数据存储策略来提升数据库性能。我们将一起探索这些技巧背后的原理,并通过实际案例感受优化带来的显著效果。
18 4
|
7天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
18 4
|
8天前
|
缓存 监控 Java
如何运用JAVA开发API接口?
本文详细介绍了如何使用Java开发API接口,涵盖创建、实现、测试和部署接口的关键步骤。同时,讨论了接口的安全性设计和设计原则,帮助开发者构建高效、安全、易于维护的API接口。
29 4
|
12天前
|
存储 Java 索引
Java中的数据结构:ArrayList和LinkedList的比较
【10月更文挑战第28天】在Java编程世界中,数据结构是构建复杂程序的基石。本文将深入探讨两种常用的数据结构:ArrayList和LinkedList,通过直观的比喻和实例分析,揭示它们各自的优势与局限,帮助你在面对不同的编程挑战时做出明智的选择。
|
13天前
|
SQL Java 程序员
倍增 Java 程序员的开发效率
应用计算困境:Java 作为主流开发语言,在数据处理方面存在复杂度高的问题,而 SQL 虽然简洁但受限于数据库架构。SPL(Structured Process Language)是一种纯 Java 开发的数据处理语言,结合了 Java 的架构灵活性和 SQL 的简洁性。SPL 提供简洁的语法、完善的计算能力、高效的 IDE、大数据支持、与 Java 应用无缝集成以及开放性和热切换特性,能够大幅提升开发效率和性能。
|
14天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
32 2