解决Cause: java.sql.SQLException: sql injection violation, dbType mysql ... token IDENTIFIER deleted错误

本文详细记录了一次处理SQL错误的经历,从复现错误开始,通过分析错误日志定位到MyBatis的Mapper方法中SQL语句的问题。错误源于SQL关键字缺失,导致解析异常。解决方案是修正SQL语句,添加遗漏的and关键字。此外,文章还提供了防止表字段与关键字冲突的建表规范和解决此类问题的其他方法。
摘要由CSDN通过智能技术生成

本文不仅帮你解决错误,还帮你分析错误的原因👇👇

1. 复现错误


今天写好创建数据源的接口,并启动项目后,通过Knife4j调用单接口,但保出如下图错误:

在这里插入图片描述

于是,查看后端输出详细的错误信息,如下所示:

org.springframework.jdbc.UncategorizedSQLException: 
### Error querying database.  Cause: java.sql.SQLException: sql injection violation, dbType mysql, , druid-version 1.2.11, syntax error: not supported.pos 86, line 1, column 79, token IDENTIFIER deleted : SELECT * FROM `datasource` where datasource_key = ? and id <> ? and app_id = ? deleted = 0 LIMIT 1
### The error may exist in com/xxx/mapper/DatasourceMapper.java (best guess)
### The error may involve com.xxx.mapper.DatasourceMapper.getByDatasourceKeyAndId
### The error occurred while executing a query
### SQL: SELECT * FROM `datasource` where datasource_key = ? and id <> ? and app_id = ? deleted = 0 LIMIT 1
### Cause: java.sql.SQLException: sql injection violation, dbType mysql, , druid-version 1.2.11, syntax error: not supported.pos 86, line 1, column 79, token IDENTIFIER deleted : SELECT * FROM `datasource` where datasource_key = ? and id <> ? and app_id = ? deleted = 0 LIMIT 1
; uncategorized SQLException; SQL state [null]; error code [0]; sql injection violation, dbType mysql, , druid-version 1.2.11, syntax error: not supported.pos 86, line 1, column 79, token IDENTIFIER deleted : SELECT * FROM `datasource` where datasource_key = ? and id <> ? and app_id = ? deleted = 0 LIMIT 1; nested exception is java.sql.SQLException: sql injection violation, dbType mysql, , druid-version 1.2.11, syntax error: not supported.pos 86, line 1, column 79, token IDENTIFIER deleted : SELECT * FROM `datasource` where datasource_key = ? and id <> ? and app_id = ? deleted = 0 LIMIT 1
	at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:92)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441)
	at com.sun.proxy.$Proxy160.selectOne(Unknown Source)
	at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:160)
	at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:89)
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148)
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89)
	at com.sun.proxy.$Proxy166.getByDatasourceKeyAndId(Unknown Source)
	at com.xxx.service.DatasourceService.modifyDatasource(DatasourceService.java:104)
	at com.xxx.service.DatasourceService$$FastClassBySpringCGLIB$$ae4aeefa.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
	at com.xxx.service.DatasourceService$$EnhancerBySpringCGLIB$$1c1c65fc.modifyDatasource(<generated>)
	at com.xxx.controller.DatasourceController.modifyDatasource(DatasourceController.java:96)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1063)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at com.github.xiaoymin.knife4j.spring.filter.SecurityBasicAuthFilter.doFilter(SecurityBasicAuthFilter.java:87)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:114)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
.....

由于篇幅有限,没有粘贴出全部的错误信息。

2. 分析错误


由于错误信息很多,我们只需要关注Cause: java.sql.SQLException: sql injection violation, dbType mysql, , druid-version 1.2.11, syntax error: not supported.pos 86, line 1, column 79, token IDENTIFIER deleted这句话即可。

正赶上最近ChatGPT比较火,我们可以借助它来分析我的错误,如下图所示:

在这里插入图片描述

ChatGPT说我的错误由于SQL注入导致的,使用了mysql不支持的语法。

于是继续分析上述的错误信息,查找到DatasourceMapper类中的getByDatasourceKeyAndId方法,该方法如下代码所示:

 @Select(
      "SELECT "
          + " * "
          + "FROM "
          + " `datasource` "
          + "WHERE "
          + " datasource_key = #{datasourceKey} and id <> #{id} and app_id = #{appId} deleted = 0 LIMIT 1")
  Datasource getByDatasourceKeyAndId(String datasourceKey, Long id, Long appId);

经过反复检查上述代码,却没有发现任何问题,只能通过如下断点的方式分析:

在这里插入图片描述

通过断点发现,在app_id = ? deleted = 0没有and符号,即app_id = #{appId} deleted = 0没有and符号。

3. 解决错误


既然在app_id = #{appId} deleted = 0没有and符号,在其加上and符号即可,如下代码所示:

@Select(
      "SELECT "
          + " * "
          + "FROM "
          + " `datasource` "
          + "where "
          + " datasource_key = #{datasourceKey} and id <> #{id} and app_id = #{appId} and deleted = 0 LIMIT 1")
  Datasource getByDatasourceKeyAndId(String datasourceKey, Long id, Long appId);

在这里插入图片描述

重新启动项目,再次使用Knife4j测试该接口,即可成功访问,如下图所示:

在这里插入图片描述

4. 解决该错误的其他方法

\

4.1 方法说明


我的错误是由于缺少关键字(and)导致的。

如果我的错误解决方法,无法解决你的错误,可以参考如下的解决方法👇👇

一般情况下,该错误是因为表字段和关键字冲突,这个问题解决后多数情况都正常了。

若开发工具不显示SQL的关键字,导致不方便区分的话,我知道如下三种解决办法:

  1. 可以把感觉不对劲的表名和字段名都用 ` ` 给注上,如 `status`。

  2. 给冲突的字段或表名起别名。

  3. 还可以在oracle中使用双引号" ",将冲突的列名括起来。

4.2 建表规范


为了避免表字段和关键字冲突,在数据库最初建表时,需要有意识的避免字段冲突问题,下面是网上找的建表命名规范:

  1. 采用系统名+_+t_+模块名+_+表义名格式构成。

  2. 若数据库中只含有单个模块,命名可采用系统名+t_+表义名格式构成。

  3. 整个表名的长度不要超过30个字符。

  4. 系统名、模块名均采用小写字符。

  5. 模块名或表义名均以其英文单词命名,且字符间不加分割符:

    • 表义名中单词的首字符大写,其它字符小写。

    • 多个单词间也不加任何分割符,单词全部采用单数形式。

  6. 表别名命名规则:

    • 取表义名的前3个字符加最后一个字符。

    • 如果存在冲突,适当增加字符(如取表义名的前4个字符加最后一个字符等)。

  7. 关联表命名为Re_表A_表B

    • ReRelative的缩写

    • 表A表B均采用其表义名或缩写形式。

这样会避免与关键字冲突,将麻烦降到最低。

5. 补充说明


如果你对Knife4j感兴趣,可以参考博文:全网最全的Knife4j swaggerj介绍

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

互联网全栈开发实战

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值