回滚

spring异常与事务回滚

喜欢而已 提交于 2020-12-19 08:07:04
默认情况下,spring框架只捕获RuntimeException异常及其子类;对于Exception异常是不会回滚的,如果相让Spring来改变这种默认的行为,那么可以在相应的方法上面加入@Transactional(rollbackFor=MyException.class)设置成回滚,从而改变默认的行为。 令Spring的几种注解事务传播行为 : Required:业务方法需要在一个事务中运行。如果方法运行时,已经在一个事务中,那么加入到该事务,否则自己创建一个新的事务。一般spring默认都是这种事务,像保存,删除,修改等都是这种事务。80%的情况下都用这种事务。 Not_Supported:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为它开启事务。如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会执行。 Requiresnew:属性不管是否存在事务,业务方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务被挂起,新的事务会被创建,直到方法执行结束,新事务才算结束,原先事务才会恢复执行。 Mandatory:该属性指定业务方法必须在一个事务中运行,业务方法不能发起自己的事略。如果业务方法在没有事务的环境下调用,容器会抛出例外。 Supports:这一事务属性表明,如果方法在某个事务范围内被调用

【Java系列002】正确使用@Transactional注解

[亡魂溺海] 提交于 2020-04-05 17:42:43
你好,我是miniluo,今天我和你聊聊Spring声明式事务不生效的坑。 下面就让我和你一起学习有哪些几种情况下Spring声明式事务不生效的坑。 没有正确理解@Transactional注解 你是否曾经写过和下文类似的代码? @Service ( "productService" ) public class ProductServiceImpl implements IProductService { @Override public void createProduct (Product product) { //此处可能会实现一些业务逻辑代码,判断是否满足创建产品的条件 //请求内部方法创建产品 product.setProductName( "Spring声明式事务" ); executeCreateProduct(product); } @Transactional private void executeCreateProduct (Product product) { if (Objects.isNull(product)){ throw new RuntimeException( "无法创建空产品" ); } product.create(); //模拟出现异常期待事务回滚 int zero = 1 / 0 ; } } 经过测试,我们发现抛出了异常

Truncate用法详解

拥有回忆 提交于 2020-04-03 18:32:48
前言: 当我们想要清空某张表时,往往会使用truncate语句。大多时候我们只关心能否满足需求,而不去想这类语句的使用场景及注意事项。本篇文章主要介绍truncate语句的使用方法及注意事项。 1.truncate使用语法 truncate的作用是清空表或者说是截断表,只能作用于表。truncate的语法很简单,后面直接跟表名即可,例如: truncate table tbl_name 或者 truncate tbl_name 。 执行truncate语句需要拥有表的drop权限,从逻辑上讲,truncate table类似于delete删除所有行的语句或drop table然后再create table语句的组合。为了实现高性能,它绕过了删除数据的DML方法,因此,它不能回滚。尽管truncate table与delete相似,但它被分类为DDL语句而不是DML语句。 2.truncate与drop,delete的对比 上面说过truncate与delete,drop很相似,其实这三者还是与很大的不同的,下面简单对比下三者的异同。 truncate与drop是DDL语句,执行后无法回滚;delete是DML语句,可回滚。 truncate只能作用于表;delete,drop可作用于表、视图等。 truncate会清空表中的所有行,但表结构及其约束、索引等保持不变

MySQL表介绍

假装没事ソ 提交于 2020-03-31 17:37:01
MySQL InnoDB表介绍 一、索引组织表 在InnoDB引擎中,表都是根据主键顺序存放的。这种存储方式称为索引组织表,在InnoDB引擎中,每张表都有逐渐。如果没有显示定义主键,则引擎会按照以下方式选择或创建主键。 (1)、判断表是否有非空唯一索引,如果有,则该字段为主键。如果有多个非空唯一索引,则选择第一个定义的非空索引字段作为主键(定义索引的顺序,不是定义字段的顺序) (2)、如果不符合上述条件,InnoDB自动创建一个6字节大小的指针。 二、InnoDB逻辑存储结构 从InnoDB得逻辑存储结构看,索引数据放在一个空间中,称作表空间。表空间又由段(segment),区(extend),页(page)组成。InooDB的逻辑存储结构大致如下图所示: 1、表空间 表空间可以看作InnoDB存储引擎逻辑存储结构的最高层,所有数据都放在表空间中。5.7默认启用参数innodb_file_per_table。每张表数据放在一个单独的表空间里边,如果关闭该参数,所有数据放在一个表空间ibdata1内。 如果启用innodb_file_per_table该参数,每张表的表空间存放的是数据,索引,插入缓冲Bitmap页。其他类的数据,如回滚(undo)信息,插入缓冲索引页,系统事务信息,二次写缓冲等还是放在原来的共享表空间内。 2、段 表空间是由各个段组成的,常见有数据段、索引段

10分钟梳理MySQL核心知识点

被刻印的时光 ゝ 提交于 2020-03-31 04:09:29
今天我们用10分钟,重点梳理一遍以下几方面: 数据库知识点汇总; 数据库事务特性和隔离级别; 详解关系型数据库、索引与锁机制; 数据库调优与最佳实践; 面试考察点及加分项。 一、数据库的不同类型 1.常用的关系型数据库 Oracle:功能强大,主要缺点就是贵 MySQL:互联网行业中最流行的数据库,这不仅仅是因为MySQL的免费。可以说关系数据库场景中你需要的功能,MySQL都能很好的满足,后面详解部分会详细介绍MySQL的一些知识点 MariaDB:是MySQL的分支,由开源社区维护,MariaDB虽然被看作MySQL的替代品,但它在扩展功能、存储引擎上都有非常好的改进 PostgreSQL:也叫PGSQL,PGSQL类似于Oracle的多进程框架,可以支持高并发的应用场景,PG几乎支持所有的SQL标准,支持类型相当丰富。PG更加适合严格的企业应用场景,而MySQL更适合业务逻辑相对简单、数据可靠性要求较低的互联网场景。 2.NoSQL数据库(非关系型数据库) Redis:提供了持久化能力,支持多种数据类型。Redis适用于数据变化快且数据大小可预测的场景。 MongoDB:一个基于分布式文件存储的数据库,将数据存储为一个文档,数据结构由键值对组成。MongoDB比较适合表结构不明确,且数据结构可能不断变化的场景,不适合有事务和复杂查询的场景。 HBase:建立在HDFS

还不知道事务消息吗?这篇文章带你全面扫盲!

旧城冷巷雨未停 提交于 2020-03-30 08:16:23
在分布式系统中,为了保证数据一致性是必须使用分布式事务。分布式事务实现方式就很多种,今天主要介绍一下使用 RocketMQ 事务消息,实现分布事务。 文末有彩蛋,看完再走 为什么需要事务消息? 很多同学可能不知道事务消息是什么,没关系,举一个真实业务场景,先来带你了解一下普通的消息存在问题。 上面业务场景中,当用户支付成功,将会更新支付订单,然后发送 MQ 消息。手续费系统将会通过拉取消息,计算手续费然后保存到另外一个手续费数据库中。 由于计算手续费这个步骤可以离线计算,所以这里采用 MQ 解耦支付与计算手续费的流程。 流程主要涉及三个步骤: 更新订单数据 发送消息给 MQ 手续费系统拉取消息 上面提到的步骤,任何一个都会失败,如果我们没有处理,就会使两边数据不一致,将会造成下面两种情况: 订单数据更新了,手续费数据没有生成 手续费数据生成,订单数据却没有更新 这可是涉及到真正的钱,一旦少计算,就会造成 资损 ,真的赔不起! 对于最后一步来讲,比较简单。如果消费消息失败,只要没有提交消息确认,MQ 服务端将会自动重试。 最大的问题 在于我们无法保证更新操作与发送消息一致性。无论我们采用先更新订单数据,再发送消息,还是先发送消息,再更新订单数据,都在存在一个成功,一个失败的可能。 如下所示,采用先发送消息,然后再更新数据库的方式。 上面流程消息发送成功之后,再进行本地事务的提交

使用SQLite的感想

|▌冷眼眸甩不掉的悲伤 提交于 2020-03-30 06:49:10
  最近都在使用SQLite数据库,老实说这才是我使用的第三款数据库而已。使用它原因就应为它够轻量,而且性能挺不错。但使用久了也发现了一些问题。偶尔也会有怨言,但也不会骂SQLite是个破东西之类的,原因又几个:对SQLite的了解不过透彻,使用方式上总有些不妥;自己的资历尚浅,解决问题的能力有限;自己也没本事写出比SQLite更好的数据库。   在网上看了一下SQLite的适用场景。100000次/天访问量的网站,嵌入式设备和应用软件,应用程序文件格式等。但是读数据可时也会抛锁表的异常,SQLite的锁是粗粒度,这个对异常的处理不知如何是好;还有的就是数据库的损坏。Database disk image is malformed。网上说数据库造成数据库损坏的原因有三个 sqlite数据库在写入时断电等,导致数据库里的结果被破坏。 sqlite数据库所存的磁盘空间不够。 磁盘有坏磁道等   之前数据库的损坏估计是第一种原因。而当时又没有对数据进行什么备份。只能人工用.dump命令从损坏的数据库中把数据导出来。这个顺带也讲一下吧 在SQLite的命令模式中打开数据库,依次输入一下命令 sqlite> .mode insert sqlite> .output test.sql sqlite> .dump sqlite> .exit 当然不一定要”.exit”命令,按“Ctrl+C

MySQL基础篇(07):用户和权限管理,日志体系简介

◇◆丶佛笑我妖孽 提交于 2020-03-26 23:45:48
3 月,跳不动了?>>> 本文源码: GitHub·点这里 || GitEE·点这里 一、MySQL用户 1、基础描述 在数据库的使用过程中,用户作为访问数据库的鉴权因素,起到非常重要的作用,安装MySQL时会自动生成一个root用户,作为数据库管理员,拥有所有权限。在多用户的应用场景下,可能需要给不同的用户分配不同的权限,用来提升系统的稳定性,比如常见:报表库只提供读权限,或者开放给第三方的库,也只提供可读用户。 2、用户管理 基本描述 MySQL将用户信息存储在系统数据库mysql的user表中。根据用户名密码和客户端主机来定义帐户。 用户密码:基本验证操作 ; 客户端IP:类似黑白名单的限制,支持通配符表达式 ; SELECT t.`Host`,t.`User`,t.authentication_string FROM mysql.`user` t ; 添加用户 可以对user表进行增删改查一系列操作,进而添加用户,不同的用户就会涉及到不同的操作权限,这就是另外一个问题:用户的权限管理。 这里添加一个user01用户,作为权限模块的测试用户,权限先给和root用户一样的权限。 INSERT INTO `mysql`.`user`(`Host`, `User`, `authentication_string`) VALUES ('%', 'user01', '

Spring事务异常回滚,捕获异常不抛出就不会回滚

坚强是说给别人听的谎言 提交于 2020-03-26 16:34:58
3 月,跳不动了?>>> 最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了....... 为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志。但是这边情况来了,当这个方法异常时候 日志是打印了,但是加的事务却没有回滚。 例: 类似这样的方法不会回滚 (一个方法出错,另一个方法不会回滚) : if(userSave){ try { userDao.save(user); userCapabilityQuotaDao.save(capabilityQuota); } catch (Exception e) { logger.info("能力开通接口,开户异常,异常信息:"+e); } } 下面的方法回滚(一个方法出错,另一个方法会回滚): [html] view plaincopy if(userSave){ try { userDao.save(user); userCapabilityQuotaDao.save(capabilityQuota); } catch (Exception e) { logger.info("能力开通接口,开户异常,异常信息:"+e); throw new RuntimeException(); } } 或者: if(userSave){ try { userDao.save(user);

Spring事务异常回滚,捕获异常不抛出就不会回滚

亡梦爱人 提交于 2020-03-26 16:34:38
3 月,跳不动了?>>> 最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了....... 为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志。但是这边情况来了,当这个方法异常时候 日志是打印了,但是加的事务却没有回滚。 例: 类似这样的方法不会回滚 (一个方法出错,另一个方法不会回滚) : [html] view plain copy if(userSave){ try { userDao.save(user); userCapabilityQuotaDao.save(capabilityQuota); } catch (Exception e) { logger.info("能力开通接口,开户异常,异常信息:"+e); } } 下面的方法回滚(一个方法出错,另一个方法会回滚): [html] view plain copy if(userSave){ try { userDao.save(user); userCapabilityQuotaDao.save(capabilityQuota); } catch (Exception e) { logger.info("能力开通接口,开户异常,异常信息:"+e); throw new RuntimeException(); } } 或者: [html] view plain copy if