Springboot 优雅的处理数据库报错信息
目录
- 完整性约束报错处理
- 测试实例
- 邮箱字段被占用
- 账号被占用
- 原理
Duplicate entry 'xxx' for key 'xxxx'
平时我们遇到 mysql 报错的时候很难处理,例如字段重复了,破坏了完整性约束,但是我们又不可能每个唯一字段都去进行查询,看看是不是重复了,这样相当于写死了代码。
那么如何动态的去知道那个信息被占用,或者重复了呢? 这里就需要用到反射的原理
首先我们得学会捕获全局异常 :
使用 @RestControllerAdvice
环绕增强 ,然后再使用 @ExceptionHandler
注解,在某个方法上面给指定的异常类进行注解, Speingboot 会自动将异常分发给你的方法进行处理。
这里的
@ResponseHandler
注解是统一信息处理注解,可以在我的文章 https://blog.csdn.net/qq_31254489/article/details/119772338 中去学习配置,如果你不想用,可以删掉。
@RestController
@ResponseHandler
@RestControllerAdvice
@Api(tags = "統一错误请求控制")
public class MyErrorController implements ErrorController {// 统一sql异常处理类@AutowiredSqlExceptionHandler sqlExceptionHandler;// sql 报错处理@ExceptionHandler(value = SQLException.class)@ResponseStatuspublic String sqlError(SQLException e) {// 我们交给异常处理类去处理return sqlExceptionHandler.handle(e);}
}
具体流程如下
完整性约束报错处理
一般就是插入的时候和已经有的数据重复了
接下来复制粘贴下面2个类,并要遵守以下规则
- 数据库的约束名称必须遵守
表名.表名_键1_键2_键3_xxx_uindex
例如user.user_name_unidex
意思就是 user 表下的 name 的唯一约束。 - 实体类的名称,还有属性,必须和数据库中的一致,mysql 必须遵守下划线命名规则, java 则可以使用 驼峰或者下划线。
- 使用
@HandleSqlException
注解去方法上面标注需要处理的具体异常。 例如 下面的integrityConstraint
方法。
/*** sql 错误异常处理** @author enncy*/
@Component
public class SqlExceptionHandler {/*** 分发异常处理* @return: void*/public String handle(SQLException e) {// 获取当前类的方法Optional<Method> first = Arrays.stream(SqlExceptionHandler.class.getDeclaredMethods())// 寻找有 HandleSqlException 注解的方法.filter(m -> m.isAnnotationPresent(HandleSqlException.class))// 寻找和参数 e 的类相等的 HandleSqlException .filter(m -> m.getAnnotation(HandleSqlException.class).value() == e.getClass()).findFirst();// 如果存在,则分发给指定的方法if( first.isPresent()){try {return (String) first.get().invoke(this, e);} catch (IllegalAccessException | InvocationTargetException exception) {return "服务器内部出现异常";}}else{return "服务器内部出现异常";}}/*** 完整性约束被破坏处理* @return: java.lang.String*/@HandleSqlException(SQLIntegrityConstraintViolationException.class)public String integrityConstraint(SQLException e) {// 匹配数据库报错信息String regex = "Duplicate entry '(.*?)' for key '(.*?)\\..*?_(.*?)_uindex'";Matcher matcher = Pattern.compile(regex).matcher(e.getMessage());// 如果存在信息if (matcher.find()) {// 获取被占用的值String value = matcher.group(1);// 获取数据库表String table = matcher.group(2);// 获取发生冲突的约束键String keys = matcher.group(3);// 扫描实体类List<Class<?>> scan = ClassScanner.scan("cn.enncy.funny.entity");// 寻找冲突的字段的注解描述String description = scan.stream().filter(BaseEntity.class::isAssignableFrom).filter(c -> c.getName().toLowerCase().contains(table)).map(c -> {// 获取实体类的属性值Field[] declaredFields = c.getDeclaredFields();for (Field declaredField : declaredFields) {// 驼峰转下划线,这里的 humpToUnderline 方法参考文章 : https://blog.csdn.net/qq_31254489/article/details/115842821String name = StringUtils.humpToUnderline(declaredField.getName());// 如果属性包含在 keys 的值里面if (keys.contains(name)) {// 返回属性上面的 注解信息return declaredField.getAnnotation(ApiModelProperty.class).value();}}return "";}).findFirst().orElse("");return description + " " + value + " 已经被占用";}return "信息已经被占用";}
}
/*** @author enncy*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HandleSqlException {Class<? extends SQLException> value();
}
然后修改完整性约束处理的里面的包路径 cn.enncy.funny.entity
, 这个需要你改到自己项目的实体类包下,也就是POJO类所在的包。
测试实例
这是我的实体类 , 在 ‘cn.enncy.xxx.entity’ 包下,所以把包扫描信息改成 ClassScanner.scan("cn.enncy.xxx.entity");
然后把项目跑起来,测试占用信息。
邮箱字段被占用
报错 : Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry 'xxxxxxxxxx@qq.com' for key 'user.user_email_uindex'
响应
账号被占用
报错 : Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry 'xxxxx' for key 'user.user_account_uindex'
原理
大概的就是利用 mysql 报错的信息, 然后进行字符串处理。
思路 :
- 全局获取 mysql 的报错信息
- 对报错信息进行正则表达式判断,取出有用的信息。
- 利用反射原理找出和报错信息所对应的实体类
- 反射找出实体类的字段和注释信息
- 最后返回统一信息
Springboot 优雅的处理数据库报错信息相关推荐
- SpringBoot 集成 druid 监控数据库报错 Failed to bind properties under ‘xxxx‘ to javax.sql.DataSource 解决(含配置源码)
What Druid是一个JDBC组件,它包括三部分: • DruidDriver 代理Driver,能够提供基于Filter-Chain模式的插件体系. • DruidDataSource 高效可管 ...
- 关于springboot项目连接oracle数据库报错 ORA01017的改正
拉取的项目本身用的是mysql数据库,改用orcl数据库,引入 驱动,连接时报ORA01017 ,确认用户名和密码是正确的.查看报错,之前有druid驱动,注释了就不报错了.
- Springboot连接mysql数据库报错
Springboot连接mysql数据库报错java.sql.SQLException: Access denied for user ''@'localhost' (using password: ...
- Emoji表情符号录入MySQL数据库报错的解决方案
2019独角兽企业重金招聘Python工程师标准>>> 前言:手机app应用评论的时候,恢复表情符号,提示失败. 1,查看tomcat后台日志,核心报错信息如下: Caused ...
- mysql数据库报错1146_关于MySQL报错:[ERR] 1146
最近因为电脑重装了系统,导致自己原本的数据库呗覆盖,需要重新重新安装数据库,但是由于我之前数据库版本是mysql 5.0.22,版本太低,所以小编决定安装mysql 5.7.23版本的,一开始没什么问 ...
- 报错信息为:Failed to configure a DataSource: ‘url‘ attribute is not specified and no embedded datasource
报错信息为:Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource ...
- Laravel 队列:如何查看队列报错信息
Laravel 队列在执行时,如黑盒一样,出错时我们该如何调试呢? 方法一.sync 驱动 如果你在开发环境,修改 .env: QUEUE_DRIVER=sync 这样就可以直接通过 Web 请求触发 ...
- 解决高版本SpringBoot整合swagger时启动报错:Failed to start bean ‘documentationPluginsBootstrapper‘ 问题
一.控制台的报错信息 2021-12-29 15:15:04 [main] ERROR org.springframework.boot.SpringApplication - Application ...
- eclipse spring mysql,eclipse环境下的springboot框架+mybatis访问MySQL报错空指针
"/")public classTestController { @RequestMapping("/login")publicString login() { ...
最新文章
- 国产Linux发行版再添一员,操作界面不输苹果!
- ruby安装插件报错
- python re正则匹配_python re正则表达式模块
- ECMAScript 对象类型
- excel趋势线公式导出_Java 添加、读取、删除Excel中的图表趋势线
- [HNOI2016] 大数(莫队)
- 卡巴斯基亚太区总经理:不做免费杀毒厂商
- mysql文件导出NULL值处理_Mysql select into outfile NULL值导出的处理方法
- LCS 最大子段和,最大子段和在原数组的首末地址
- CodeProject - 在C#使用SHGetFileInfo获取(管理)文件或者文件夹图标(C#封装Win32函数的一个例子)...
- 20190925:(经典算法系列)河内之塔
- CentOS7添加阿里云yum源
- xml简单理解,xml增删改操作,仅作笔记,不作为学习借鉴
- linux监控程序-程序自动重启方法(转)
- 完美解决Win11无法启动安全中心
- 第一章 网络入门【仅参考】
- 7-53 奥运排行榜 (25 分)
- SQL Server新增Contained Database功能
- 史上最全亚马逊申诉模板!!!!
- VMware P2V---从物理机到虚拟机(二)
热门文章
- canvas牛奶液体底部动画js特效
- 【数据挖掘】分类与回归预测
- 深度学习——评估学习模型
- 维护国家主权,保卫国家安全|科力锐助力中华人民共和国无锡出入境边防检查站灾备建设
- java getmethod_java中getMethod*()和getDeclaredMethod*()的区别
- 机械革命极光Pro开机错误重启无法进入桌面怎么办?
- Docker学习:容器五种(3+2)网络模式 | bridge模式 | host模式 | none模式 | container 模式 | 自定义网络模式详解
- 史上最全的常用中英文学术网站(三)
- 基于PBOC电子钱包的圈存过程详解
- 华为怎么分屏操作技巧_糖豆人终极淘汰赛扒拉怎么操作 扒拉抓人技巧介绍