1、前言
面试官:我看你简历上写了熟悉redis,看来工作中用的很多吧?
我:是的,我们项目中经常用到redis(来,随便问,看我分分钟秒杀你)
面试官:那你给我说说redis的事务和mysql的事务有什么区别吧
我:额。。。事务还有区别????
面试官:比如说redis的事务是不支持原子性和持久性的,包括他们的实现原理等方面也是有很大区别的。
我:学到了。。。。。。
2、正文
事务的四大特性
ACID,指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。
说的是一个事物内所有 *** 作就是最小的一个 *** 作单元,要么全部成功,要么全部失败。这是最基本的特性,保证了因为一些其他因素导致数据库异常,或者宕机。
一个事务可以封装状态改变(除非它是一个只读的)。事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。
一致性有下面特点:
在现实中,事务系统遭遇并发请求时,这种串行化是有成本的, Amdahl法则描述如下:它是描述序列串行执行和并发之间的关系。
“一个程序在并行计算情况下使用多个处理器所能提升的速度是由这个程序中串行执行部分的时间决定的。”
大多数数据库管理系统选择(默认情况下)是放宽一致性,以达到更好的并发性。
事物的隔离性,基于原子性和一致性,因为事物是原子化,量子化的,所以,事物可以有多个原子包的形式并发执行,但是,每个事物互不干扰。
但是,由于多个事物可能 *** 作同一个资源,不同的事物为了保证隔离性,会有很多锁方案,当然这是数据库的实现,他们怎么实现的,我们不必深究。
持久性,当一个事物提交之后,数据库状态永远的发生了改变,即这个事物只要提交了,哪怕提交后宕机,他也确确实实的提交了,不会出现因为刚刚宕机了而让提交不生效,是要事物提交,他就像洗不掉的纹身,永远的固化了,除非你毁了硬盘。
事务命令
mysql:
Begin:显式的开启一个事务
Commit:提交事务,将对数据库进行的所有的修改变成永久性
Rollback:结束用户的事务,并撤销现在正在进行的未提交的修改
redis:
Multi:标记事务的开始
Exec:执行事务的commands队列
Discard:结束事务,并清除commands队列
默认状态
mysql:
mysql会默认开启一个事务,且缺省设置是自动提交,即每成功执行sql,一个事务就会马上commit,所以不能rollback,
redis:
redis默认不会开启事务,即command会立即执行,而不会排队,并不支持rollback
使用方式
mysql(包含两种方式):
用Begin、Rollback、commit显式开启并控制一个 新的 Transaction
执行命令 set autocommit=0,用来禁止当前会话自动commit,控制 默认开启的事务
redis:
用multi、exec、discard,显式开启并控制一个Transaction。
(注意:这里没有强调 “新的” ,因为默认是不会开启事务的)。
实现原理
mysql:
mysql实现事务,是基于undo/redo日志
undo记录修改前状态,rollback基于undo日志实现
redo记录修改后的状态,commit基于redo日志实现
既然是基于redo日志实现记录修改后的状态,那么大家应该也知道,redo日志是innodb专有的,所以innodb会支持事务
在mysql中无论是否开启事务,sql都会被立即执行并返回执行结果,只是事务开启后执行后的状态只是记录在redo日志,执行commit之后,数据才会被写入磁盘
(以上内容后面我会详细在mysql篇给大家讲到,大家可以先简单了解下)
所以,上述代码,insertSelective 将会被立即赋值(无论是否开启事务,只是结果或未被写入磁盘):
redis:
redis实现事务,是基于commands队列
如果没有开启事务,command将会被立即执行并返回执行结果,并且直接写入磁盘
如果事务开启,command不会被立即执行,而是排入队列,并返回排队状态(具体依赖于客户端(例如:spring-data-redis)自身实现)。
调用exec才会执行commands队列
以上代码如果没有开启事务, *** 作被立即执行,a将会被立即赋值(true/false)
如果开启事务, *** 作不会被立即执行,将会返回null值,而a的类型是boolean,所以将会抛出异常:
Redis事务不支持Rollback(重点)
事实上Redis命令在事务执行时可能会失败,但仍会继续执行剩余命令而不是Rollback(事务回滚)。如果你使用过关系数据库,这种情况可能会让你感到很奇怪。然而针对这种情况具备很好的解释:
redis 事务中的错误
事务期间,可能会遇到两种命令错误:
客户端会在EXEC调用之前检测第一种错误。 通过检查排队命令的状态回复(注意:这里是指排队的状态回复,而不是执行结果),如果命令使用QUEUED进行响应,则它已正确排队,否则Redis将返回错误。如果排队命令时发生错误,大多数客户端将中止该事务并清除命令队列。然而:
这是由于INCR命令的语法错误,将在调用EXEC之前被检测出来,并终止事务(version265+)。
EXEC命令执行之后发生的错误并不会被特殊对待:即使事务中的某些命令执行失败,其他命令仍会被正常执行。
如果了解事务的概念,就能知道一个SqlConnection只能同时用一个Transaction
事务的四大特性之一隔离性明确地说明了,各个事务是彼此隔离,互不干扰的。
想提高系统的性能,不是要多线程公用连接(按理肯定是不同连接,否则一个线程在用DataReader读,其他的线程不是要等着),而是要每个连接用完后尽快地归还给连接池,保证连接池又足够多的活动连接就能让下一个数据库请求尽快完成(避免了创建连接和销毁链接的开销)
概念: 事务是一种 *** 作序列,是不可分割最基本的 *** 作序列,要么都执行,要么都不执行,不可再拆分
特性: 事务具有四大特性(ACID):
原子性(Atomicity):一个事务必须被视为一个不可分割的最小工作单元,
整个事务中的所有 *** 作要么全部提交成功,要么全部失败回滚
一致性(Consistency): 多个终端开启事务 *** 作同一数据库同一表, 全部的事务提交结束后,最终所有终端结果是一致的
隔离性(Isolation): 多个终端都开启事务 *** 作同一数据库同一表的同一个字段,
一个终端没有提起事务,其他终端会阻塞,这是隔离的特性
持久性(Durability): 一旦事务提交,则其所做的修改会永久保存到数据库 (数据库存放在硬盘上)
作用: 某些事情需要一次性完成 中途不允许出现中断 例如银行转账,网上订单处理 事务可以解决这种问题
如果小伙伴想深入的学习可以参考黑马程序员软件测试的相关知识进行加强
偶然的一次,网友在taskmacleancom ASK Maclean Home提问了关于112 上一个ORA-600问题的解决途径,我们这里不讨论该ORA-600[kcratr_nab_less_than_odr]错误, 比这个错误本身更有趣的是 该600 trace中记录了一段对于前滚恢复rolling upgrade描述十分详细的KST trace。
很多网友肯定要问什么是KST KST是9i以后引入的内部诊断机制Tracing Facility,每一个Oracle 进程都维护SGA中的一小块Trace buffer,并将自身的默认启用的一些event事件信息写入到Trace Buffer中(这些事件默认包括10280, 10401, 10441, 10442, 10425, 10427, 10429, 10434, 10666),可以使用内部视图x$trace观察这些信息,默认Trace Buffer不写到磁盘上,而只在SGA中维护,当Trace Buffer用完时将被重用。
了解了 KST的知识后,我们可以从容地阅读下面这段TRACE了:
Trace Bucket Dump Begin: default bucket for process 19 (osid: 29785)
TIME(=approx):SEQ:COMPONENT:FILE@LINE:FUNCTION:SECT/DUMP: [EVENT#:PID:SID] DATA
以上是KST Trace的 头部
COMPONENT 组件名 例如 db_trace 、CACHE_RCV,这里的CACHE_RCV意为 cache recovery,实际上是我们所说的前滚rolling forward。
FILE@LINE 指oracle内核代码的文件名和行数 例如:kstc、kcvc,这些都是oracle的核心C代码名
FUNCTION 指oracle内核函数名 例如kcvcrv()、kctrec()
[EVENT#:PID:SID] 即 EVENT ID:PID:SID
DATA 实际的 *** 作内容
我们选择性地阅读KST TRACE的内容:
2012-02-07 13:40:52755567 :800005B3:CACHE_RCV:kcvc@15475:kcvcrv(): kcvcrv: Entering kcvcrv()2012-02-07 13:40:52755609 :800005B4:KFNU:kfnc@2200:kfnPrepareASM(): kfnPrepareASM force=0 state_kfnsg=0x7
2012-02-07 13:40:52772999:800005B5:CACHE_RCV:kcvc@16100:kcvcrv(): kcvcrv: file 1 - cpscn 0x0000018b76b2, rsflg 0
2012-02-07 13:40:52826001:800005B6:CACHE_RCV:kcvc@16100:kcvcrv(): kcvcrv: file 2 - cpscn 0x0000018b76b2, rsflg 0
2012-02-07 13:40:52862014:800005B7:CACHE_RCV:kcvc@16100:kcvcrv(): kcvcrv: file 3 - cpscn 0x0000018b76b2, rsflg 0
2012-02-07 13:40:52909981:800005B8:CACHE_RCV:kcvc@16100:kcvcrv(): kcvcrv: file 4 - cpscn 0x0000018b76b2, rsflg 0
2012-02-07 13:40:52945933:800005B9:CACHE_RCV:kcvc@16100:kcvcrv(): kcvcrv: file 5 - cpscn 0x0000018b76b2, rsflg 0
2012-02-07 13:40:52993824:800005BA:CACHE_RCV:kcvc@16100:kcvcrv(): kcvcrv: file 6 - cpscn 0x0000018b76b2, rsflg 0
2012-02-07 13:40:53005829:800005BB:CACHE_RCV:kcvc@16100:kcvcrv(): kcvcrv: file 7 - cpscn 0x0000018b76b2, rsflg 0
2012-02-07 13:40:53041893:800005BC:CACHE_RCV:kcvc@16100:kcvcrv(): kcvcrv: file 8 - cpscn 0x0000018b76b2, rsflg 0
2012-02-07 13:40:53065779:800005BD:CACHE_RCV:kcvc@16100:kcvcrv(): kcvcrv: file 9 - cpscn 0x0000018b76b2, rsflg 0
2012-02-07 13:40:53089760:800005BE:CACHE_RCV:kcvc@16100:kcvcrv(): kcvcrv: file 10 - cpscn 0x0000018b76b2, rsflg 0
kcvcrv的全称是 [K]ernel [C]ache [R]ecovery [C]rash [R]ecovery [V]erify , kcvcrv内核函数在crash recovery的过程中显得极为重要,它总是发生在当一个前台进程试图启动脏关闭(dirty shutdown)的数据库的时候。kcvcrv 的工作包括检验所有的数据文件头并验证控制文件中的数据文件记录以确认是否需要介质恢复。这个步骤必要地验证仅仅crash recovery是否足以让数据库恢复到一致状态(consistent),相信大家已经耳熟能详 crash recovery 、 instance recovery 、 media recovery 三者的区别。 若kcvcrv发现 data files数据文件、control files控制文件亦或者redo log file在线日志文件存在corrupted 或者 丢失,或者实际上是从之前的备份中还原过来的,那么kcvcrv会强制用户必须使用media recovery才能将数据库恢复到一致,无法通过crash recovery实现恢复。注意 kcvcrv的检测并不是完全的,它主要是检测 数据文件头的checkpoint scn 和 控制文件中data files的checkpoint scn是否一致,以确保 这些数据文件完成了shutdown instance时的最后一次FULL Checkpoint。 kcvcrv并不能检测出除数据文件头部外的datafile body是否存在介质讹误。
kcvcrv需要对control file读写才能完成其必要的任务,所以它会启动一个控制文件读写事务 read-write control file transaction。通过检验控制文件中每个数据文件的记录以确认数据文件是否有被重新同步的必要。 当然kcvcrv会跳过哪些OFFLINE和read-only的数据文件,因为这些文件不存在recovery的必要。
在确认crash recovery的必要性后,kcvcrv还会主导启动并行的恢复工作(parallel recovery),注意parallel recovery只在多CPU且参数recovery_parallelism不为零的环境下有效, kcvcrv会创建并初始化Oracle中的PQ Slave 并行子进程以便恢复实例。 默认的子进程数Slave Processes等于(CPU的总数-1),这是因为需要为recovery coordinator process恢复协调进程保留一个CPU。并且需要kcvcrv分配一个recovery state object给并行恢复 协调进程与其Slave子进程。
最后kcvcrv还会调用另一个关键内核函数 kctrec ( Kernel Cache Threads ), kctrec会在所有打开的redo thread上实施进一步的thread recovery。
2012-02-07 13:40:53366569 :80000687:KFNU:kfnc@2200:kfnPrepareASM(): kfnPrepareASM force=0 state_kfnsg=0x7
2012-02-07 13:40:53366569:80000688:CACHE_RCV:kcvc@16365:kcvcrv(): kcvcrv: Calling kctrec()
2012-02-07 13:40:53366569:80000689:CACHE_RCV:kctc@4163:kctrec(): kctrec: Entering kctrec()
2012-02-07 13:40:53413557:8000068A:CACHE_RCV:kctc@4271:kctrec(): kctrec: thread 1 cf thread ckpt: logseq 1468, block 2,scn 25917106
常见的 kcvcrv 调用堆栈 stack call如下:
kcratr_odr_check <- kcratr <- kctrec <- kcvcrv <- kcfopd <- adbdrv
kcliarq <- kclrinit <- kcbrst <- kcrpci <- kcratr <- kctrec <- kcvcrv <- kcfopd <- adbdrv
kfgrpIterInit()<-kfis_sageonly_anygroup()<-krr_init_rrx()<-kcra_scan_redo()<-kcra_dump_redo()+2246<-kcra_dump_redo_internal()+1752<-kco_image_corrupt()<-kcoapl()<-kcbr_apply_change()<-kcbr_mapply_change()<-kcbrapply()<-kcbr_apply_pending()<-kcbr_media_apply()<-krp_serial_apply()<-krr_do_media_recovery()<-krddmr()<-krd_do_media_rcv()<-krd_implicit_rcv()<-kcvcrv()<-kcfopd()<-adbdrv()
Java 必须掌握的技能:
1 数组、集合、IO流、多线程socket网络技术、
2 面向对象
3 接口和抽象类区别
4 设计模式(工厂模式、策略模式、单例模式、装饰模式比较常见)
5 反射机制
数据库必须掌握的技能:
1 JDBC链接数据库,对数据库 *** 作
2 安装和配置mysql、sqlserver、oracle任意一个数据库
3 增删改查、内外链接
4 触发器
5 事务四大特性(ACID)
6 主从复制,读写分离
框架必须掌握的技能:
1 spirng的依赖注入,aop切面编程
2 hibernate的orm模型
3 springMVC上传文件,处理请求
第三方服务必须掌握的技能:
1 在tomcat +nginx下负载均衡
2 jsp+jstl技术显示页面动态数据
3 maven管理后台项目版本
服务器必须掌握的技能:
1 linux 权限和常用命令
2 防火墙配置
3 shell脚本
如果你也想开发一款属于自己的软件,可以通过第三方专业开发平台,来帮助你实现开发需求:厦门在乎科技-专注小程序、app、网站开发
以上就是关于redis┃面试官问我redis事务和mysql事务的区别,我全部的内容,包括:redis┃面试官问我redis事务和mysql事务的区别,我、C#里一个SqlConnection只能同时begin一个Transaction吗、在测试转账业务或订单处理过程中经常使用到事务,那么什么是事务 事务有哪些特性,主要的作用是什么等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)