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

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

数据库中的事务


数据库中的事务提交默认开启,可通过命令查询状态,关闭或者开启:


查询命令


show variables like 'autocommit'


关闭命令

set autocommit=off;


开启命令

set autocommit=on;


事务的管理


开启事务:beigin

提交事务:commit

回滚事务:rollback


尤其需要注意的是,增删改默认开启数据库事务,select不涉及任何事务。


在微服务中,当涉及到多步增删改的操作步骤时,一般我们使用dubbo调用其他模块数据库操作时会用到事务,以保证所有的操作要么一起成功,要么一起失败。此时就会为整个业务实现方法增加事务的注解。


数据库中的死锁


死锁在数据访问安全时时有发生,数据库也是数据访问的一种,虽然数据库提供了一些锁机制来保证线程安全,但,有人的地方就有江湖,数据库也无可避免的就会出现死锁的现象。


下面,我们举个例子来说明数据库中的死锁:


用户表:user1

id name age
1 张三 20
2 李四 30

事务A
1.修改user1的张三为张二
2.删除user2的id为1的王五

<------------------------->

事务B
1.修改user2的王五的年龄为20
2.删除user1的id为1的张三

用户表:user2

id   name age
1 王五 15
2 周六 18

我们可以想象一下,这俩操作会怎么样,上面我们说过,增删改都会增加排他锁,所以第一步操作都可以执行完成,且添加了排他锁,那么在第二步操作的时候,由于排他锁的存在,需要等待排他锁的释放,会导致事务A和事务B相互等待,无法继续执行,死锁产生。


那么出现死锁之后,数据库是怎么解决的呢?


在实际操作用会出现两种情况,一种是提示死锁,另一种是提示锁等待超时,这是因为数据库版本不一致的问题。


在mariadb中,对死锁是这么处理的:当检测到死锁后,让一端的事务回滚,并提示死锁DeadLock,接着让另一端的事务执行成功,一般是让后执行的事务进行回滚,回滚之后的事务执行失败,并且不会再次主动发起自旋执行。


数据库中的视图


什么是视图?


数据库中的视图是一张虚拟表,用于展示结果集,它并不保存数据,而是从已经存在的表中调取数据,后期如果要执行相同的sql,可以直接调用视图名称。听起来有点像我们对方法的封装,这里是对数据库sql语句的封装,只不过数据库没有方法的概念。


使用场景:我们要多次展示数据库中某张表或几张表中相同的数据,一样的sql语句需要多次使用,这时候,就可以为这个sql创建视图,在需要的地方直接调用视图,从视图中获取数据,简化sql语句。


操作视图:


创建视图:


create view view_name as select xx from xxxx_tb where xxxxxx;


也可以进行连表操作。


调用视图:


select xxx from view_name;


删除视图:


drop view view_name;


你会发现视图的操作和数据库的操作是一样的。


视图的注意事项


视图是对sql语句的封装,不是对查询结果集的封装,视图的存在并不存提高任何查询的效率,只是简化了sql语句;

视图一般只用于查询,不对数据进行写操作,所以不应该对视图进行写操作,但是数据库允许这么做。

视图来源于单表

insert操作     成功

delete操作    成功

update操作   成功


视图来源于多表连查

insert操作     失败

delete操作    失败


update操作

修改一张表中数据    成功

修改多张表中数据    失败


视图中不保存真是的数据,而是来源于真实的表中,所以,当真是表中的数据发生变化,视图数据也会发生变化。


事务隔离级别


事务的隔离级别有四种:


read uncommitted  读未提交

read committed   读已提交

repeatable read  可重复读

serializable    可串行化


读未提交


事务的结束表现为两种情况,一种是事务提交,另一种是事务的回滚,读未提交即表现在事务可以读取这两种状态下的数据,从而产生脏读。


什么是脏读?


脏读就是事务读取到了其他事务未提交或未回滚之后的内容,导致最终读取到的数据不存在,这就叫脏读。


我们想想这种情况怎么发生?

时刻 事务A 事务B
t1 begin begin
t2 查询user.name='张三'
t3 修改user.name='李四'
t4 查询到user.name='李四'

t5

由于某些原因导致事务B失败,rollback
t6

commit,此时表中user.name实际为'张三',读到的为'李四'

...

很明显,脏读这种情况不应该出现,所以读未提交这种隔离级别不应该被使用,事实上,也没有数据库使用读未提交的隔离级别。要解决这种情况,产生了另一种隔离级别:读已提交。


读已提交


读已提交的出现就是为了解决读未提交的情况,事务职能读取到其他事务提交后或回滚后的内容,解决了脏读问题,这里应该有掌声👏👏。


不过问题来了,这又产生了新的问题:不可重复读!!!

不可重复读是什么?看下表

时刻 事务A 事务B
t1 begin begin
t2 查询user.name='张三'
t3 修改user.name='李四'
t4 commit

t5

再次查询user.name='李四'
t6

commit

...

两次查询发现查询结果不一样?那么是不是有问题,可能我们看着觉得没错,假设两次分别查询的是银行卡余额,第一次100w,第二次0,我只是查了两次,什么都没干,钱没了,那么你觉得问题大不大? 要不要报警?


在Java中,这就是并发线程的安全问题,所以我们也要避免事务访问期间,其他事务对我们访问的数据进行修改。


根据我们前面学到的内容,我们可以给这条数据加上排他锁,这就解决了这个问题,相信大家已经学会了,此时将产生新的隔离级别:可重复读!


可重复读


可重复读这个隔离级别完美吗?看到这里显然没有结束,所以它一定是不完美的,没错,新的问题又产生了:幻读!


幻读是什么?我们用下面这张表来解读下:

时刻 事务A 事务B
t1 begin begin
t2 查询user表所有数据=2条
t3 添加一个新用户
t4 commit

t5

再次查询useruser表中的数据=3条
t6

commit

...

还以查询银行卡为例,第一次查100w,第二次查0,这是不正常的,因为事务A没有做任何处理。这和不可重复读很相似,但两者也有一定的区别,不可重复读是对数据进行修改,幻读是对数据库进行添加操作,两者都是前后查询到的结果不一致导致的。


我们考虑下幻读应不应该存在? 这种情况可以存在,我认为合法,但是我就需要两次读取到的数据保持一致,该怎么办?给表加排他锁!此时,两次查询结果一致。幻读问题解决!


加了锁,新的隔离级别也就产生了:可串行化!


可串行化


可串行化解决了幻读的问题,但是由于需要给整张表加锁,这样,数据的访问效率就大大降低,现在做开发,谁不使用并发的?所以实际开发中可串行化并不常用,只有在执行一些安全性要求极高的操作时才会使用这一等级。


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

隔离等级 产生脏读 产生不可重复读 产生幻读
读未提交 true true true
读已提交 false true true
可重复读 false false true
可串行化 false false false


隔离等级的优先级


和我上面给出的顺序是一致的,优先级由低到高分别是:读未提交-->读已提交-->可重复读-->可串行化。就像道生一,一生二,二生三,三生万物。


数据库使用的隔离级别

oracle和sql server 默认的隔离级别为读已提交。

mysql的 默认隔离级别为可重复读。


MVCC


MVCC是多版本并发控制,是用来实现可重复读的。它解决了并发安全的问题,大大提高了并发执行效率,优于加锁。


MVCC的实现分为三部分:


undolog  ,用于记录一些信息,我们下面会说到;

mysql中的每张表里隐藏的三个字段

row_id,Innodb引擎提供的隐藏主键,表中没有主键时自动创建,从1开始,自增;

DB_trx_id,表示最后操作这条数据的事务的id;

DB_roll_ptr,表示回滚指针,当前事务操作变更数据时,如果失败,需要回滚到之前的那条数据,这里保存的就是操作前数据的地址。

ReadView

目录
相关文章
|
1月前
|
Java API Maven
如何使用Java开发抖音API接口?
在数字化时代,社交媒体平台如抖音成为生活的重要部分。本文详细介绍了如何用Java开发抖音API接口,从创建开发者账号、申请API权限、准备开发环境,到编写代码、测试运行及注意事项,全面覆盖了整个开发流程。
108 10
|
29天前
|
监控 Java API
如何使用Java语言快速开发一套智慧工地系统
使用Java开发智慧工地系统,采用Spring Cloud微服务架构和前后端分离设计,结合MySQL、MongoDB数据库及RESTful API,集成人脸识别、视频监控、设备与环境监测等功能模块,运用Spark/Flink处理大数据,ECharts/AntV G2实现数据可视化,确保系统安全与性能,采用敏捷开发模式,提供详尽文档与用户培训,支持云部署与容器化管理,快速构建高效、灵活的智慧工地解决方案。
|
19天前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
38 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
6天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
52 13
|
11天前
|
算法 Java API
如何使用Java开发获得淘宝商品描述API接口?
本文详细介绍如何使用Java开发调用淘宝商品描述API接口,涵盖从注册淘宝开放平台账号、阅读平台规则、创建应用并申请接口权限,到安装开发工具、配置开发环境、获取访问令牌,以及具体的Java代码实现和注意事项。通过遵循这些步骤,开发者可以高效地获取商品详情、描述及图片等信息,为项目和业务增添价值。
44 10
|
27天前
|
JSON Java 关系型数据库
Java更新数据库报错:Data truncation: Cannot create a JSON value from a string with CHARACTER SET 'binary'.
在Java中,使用mybatis-plus更新实体类对象到mysql,其中一个字段对应数据库中json数据类型,更新时报错:Data truncation: Cannot create a JSON value from a string with CHARACTER SET 'binary'.
41 4
Java更新数据库报错:Data truncation: Cannot create a JSON value from a string with CHARACTER SET 'binary'.
|
5天前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
40 2
|
14天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
1月前
|
开发框架 Java 关系型数据库
Java哪个框架适合开发API接口?
在快速发展的软件开发领域,API接口连接了不同的系统和服务。Java作为成熟的编程语言,其生态系统中出现了许多API开发框架。Magic-API因其独特优势和强大功能,成为Java开发者优选的API开发框架。本文将从核心优势、实际应用价值及未来展望等方面,深入探讨Magic-API为何值得选择。
42 2
|
1月前
|
监控 前端开发 Java
【技术开发】接口管理平台要用什么技术栈?推荐:Java+Vue3+Docker+MySQL
该文档介绍了基于Java后端和Vue3前端构建的管理系统的技术栈及功能模块,涵盖管理后台的访问、登录、首页概览、API接口管理、接口权限设置、接口监控、计费管理、账号管理、应用管理、数据库配置、站点配置及管理员个人设置等内容,并提供了访问地址及操作指南。