话说那是一个愉快的周五的下午,刚经历双11双黑五12大促连环迎战,一周的工作也接近结束,任务也都要走向提测的节点了,心里美滋滋,可以早点回家啦~

巴特,popo弹出一份:xxx master 的单元测试静态代码检查失败,单元测试失败用例x个。请在1小时内修复并重新执行,否则可能会打回提测,单测失败详情xxx。

点开详情看看失败原因吧~

最近整理了一些Java架构学习视频和大厂项目底层知识点,需要的同学欢迎私信我【Java】发给你~

org.springframework.jdbc.UncategorizedSQLException:
### Error updating database.  Cause: java.sql.SQLException: It is not allowed to execute a(n) DELETE without where condition, sql:delete from mt_flash_sale_nav
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: delete from mt_flash_sale_nav
### Cause: java.sql.SQLException: It is not allowed to execute a(n) DELETE without where condition, sql:delete from mt_flash_sale_nav
; uncategorized SQLException for SQL []; SQL state [HY000]; error code [0]; It is not allowed to execute a(n) DELETE without where condition, sql:delete from mt_flash_sale_nav; nested exception is java.sql.SQLException: It is not allowed to execute a(n) DELETE without where condition, sql:delete from mt_flash_sale_nav

瓦特,怎么可能,之前还是好好的呀~ 我没动过这块代码呀~一定是加班太多晃了我的狗眼~本地跑一次还是这样~! GG

赶紧联系DBAbaba们,原来是测试环境qs升级啦!
xxx


好吧,扯犊子就到这里了

前段时间测试环境ddb开始限制不带where条件的update/delete的sql语句的执行,单测各种失败,且后续还会在生产环境也会这样,于是开始在工程中各种搜索,人工处理难免有遗漏的可能,怎么地也要用程序全部扫描下才放心呀!

那mybatis是如何解析xml和生成sql的呢,比如这样的sql是如何解析的呢?

 <select id="selectByCond" resultMap="BaseResultMap">select<include refid="Base_Column_List" />from test_db<where><if test="a != null">and `a` = #{a}</if><if test="list != null">and b in<foreach collection="list" open="(" close=")" item="item" separator=",">#{item}</foreach></if>order by db_update_time</where></select>

通过分析mybatis的初始化SqlSessionFactoryBean过程,可以一探究竟。

/*** Build a {@code SqlSessionFactory} instance.** The default implementation uses the standard MyBatis {@code XMLConfigBuilder} API to build a* {@code SqlSessionFactory} instance based on an Reader.* Since 1.3.0, it can be specified a {@link Configuration} instance directly(without config file).** @return SqlSessionFactory* @throws IOException if loading the config file failed*/protected SqlSessionFactory buildSqlSessionFactory() throws IOException {// ...if (!isEmpty(this.mapperLocations)) {for (Resource mapperLocation : this.mapperLocations) {if (mapperLocation == null) {continue;}try {XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),configuration, mapperLocation.toString(), configuration.getSqlFragments());// 这里解析xmlxmlMapperBuilder.parse();} catch (Exception e) {throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);} finally {ErrorContext.instance().reset();}if (LOGGER.isDebugEnabled()) {LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'");}}} else {if (LOGGER.isDebugEnabled()) {LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found");}}return this.sqlSessionFactoryBuilder.build(configuration);}

而sql最终如何生成呢?主要靠SqlSource Sql源接口,代表从xml文件或注解映射的sql内容,主要就是用于创建BoundSql,有实现类DynamicSqlSource(动态Sql源),StaticSqlSource(静态Sql源)等:

/*** Represents the content of a mapped statement read from an XML file or an annotation. * It creates the SQL that will be passed to the database out of the input parameter received from the user.** @author Clinton Begin*/
public interface SqlSource {BoundSql getBoundSql(Object parameterObject);}

如此,想要打印工程项目中所有sql并判断是否带有where条件就比较明晰了,直接上代码:

    @Resourceprivate SqlSessionFactory sqlSessionFactory;@Testpublic void test_check() {Configuration configuration = sqlSessionFactory.getConfiguration();System.out.println("#sql.size#" + configuration.getMappedStatements().size());Set<String> errors = Sets.newHashSet();int i = 1;for (Object obj : configuration.getMappedStatements()) {if (obj instanceof MappedStatement) {MappedStatement mappedStatement = (MappedStatement) obj;String sql = mappedStatement.getSqlSource().getBoundSql(new SqlParamMap()).getSql();sql = sql.replaceAll("\n", "");sql = sql.replaceAll("\\s+", " ");System.out.println(String.format("#sql,#%02d #%s #%s", i++, mappedStatement.getSqlCommandType(), sql));if (!sql.toLowerCase().startsWith("insert") && !sql.toLowerCase().startsWith("select")&& !sql.toLowerCase().startsWith("replace")) {if (!sql.toLowerCase().contains("where")) {errors.add(sql);}}}}System.err.println("#error#" + errors.size());for (String errorSql : errors) {System.err.println(errorSql);}}// 这里为了方便生成sql时,解析入参对象的public static class SqlParamMap extends AbstractMap<String, Object> implements Map<String, Object> {@Overridepublic Set<Entry<String, Object>> entrySet() {return Collections.emptySet();}@Overridepublic Object get(Object key) {return new Object[] {1, 2};}}

如此便可打印出不符合条件的sql语句了。比如在我们haitao-matter工程里搜索出:

#error#21delete from mt_baby_article_config
delete from mt_coupon_center_nav
update mt_auction_goods set price_check_status = 4
delete from mt_spring_label
delete from mt_scene_brand
delete FROM mt_newgoods_content_config
update mt_auction_goods_edit set price_check_status = 4
DELETE from mt_coupon_center_coupon_info
delete from mt_spring_label_goods
delete from mt_goods_stock_rel
delete from mt_flash_sale_nav
delete from mt_auction_homeshow_inferior
delete from matter_switcher_param_center
delete from mt_mission_award
delete from `mt_newgoods_category_tab_config`
delete from mt_goods_stock_rel_edit
delete from mt_album_label
delete from matter_app_channel_relations
delete from element_user_baby_coupon_info_log
delete from mt_album_label_category

此外还能打印出工程所有sql出来,比如:

#sql,#1974 #DELETE #delete from mt_auction_homeshow_inferior_edit where id=?
#sql,#1975 #SELECT #select id,title,begin_time,end_time,type,status,db_update_time,content from matter_common_schedule WHERE type =? and begin_time <=? and end_time >=? and type = ? order by begin_time limit ?,?
#sql,#1976 #UPDATE #update element_user_baby_coupon_info_log SET award_info=?, create_time=?, update_time=? where id=?
#sql,#1977 #SELECT #SELECT id from mt_auction_goods where show_status!=2
#sql,#1978 #INSERT #insert into TB_ACTIVITY_SHOW_DETAIL_EDIT (id, zone_id, activity_show_id, related_type, related_id, image_url, image_link, sort_order, config,ui_data ) values
#sql,#1979 #SELECT #select id, related_id, goods_id, goods_title, category_id, category_name, advance_price, question_mark_pos, config, sort_order, db_create_time, db_update_time from mt_advance_price_goods_edit where id = ?
#sql,#1980 #SELECT #select id, apply_category_id, apply_brand_id, import_type, db_create_time,db_update_time, status, goods_qa_scheme_edit_id from goods_qa_category_scope_edit where apply_category_id = ? and apply_brand_id = ? and import_type = ? and goods_qa_scheme_edit_id <> ?
#sql,#1981 #SELECT #select id, skin_scheme_id, skin_order, skin_name, skin_introduce, skin_img_config, skin_gif_config, skin_status, operator, db_create_time, db_update_time from mt_private_custom_skin_config_edit where skin_status = ? order by skin_order asc

如此,算是放心不会又遗漏了。整个思路简单直接,其中涉及到mybatis解析xml和生产动态sql的原理和过程的东西有待分析,这里先留个坑,日后来填。

Reference:

  • http://www.mybatis.org/mybatis-3/dynamic-sql.html
  • https://www.cnblogs.com/fangjian0423/p/mybaits-dynamic-sql-analysis.html

来源:网易工程师-李云鹏

看到这里的小伙伴,如果你喜欢这篇文章的话,别忘了转发、收藏、留言互动!

最近我新整理了一些Java资料,包含个人精选的Java架构学习视频、大厂实战知识点、大厂内部面试题,如果你需要的话,欢迎私信我

如果对文章有任何问题,欢迎在留言区和我交流~

网易工程师亲历:一次sql缺少where条件的惨案…相关推荐

  1. 亲身经历:一次sql缺少where条件的惨案…

    来源:网易工程师-李云鹏 话说那是一个愉快的周五的下午,刚经历双11双黑五12大促连环迎战,一周的工作也接近结束,任务也都要走向提测的节点了,心里美滋滋,可以早点回家啦- 巴特,popo弹出一份:xx ...

  2. 亲身经历:一次sql缺少where条件的惨案,绩效奖金差点没啦~

    话说那是一个愉快的周五的下午,刚经历双11双黑五12大促连环迎战,一周的工作也接近结束,任务也都要走向提测的节点了,心里美滋滋,可以早点回家啦- 巴特,popo弹出一份:xxx master 的单元测 ...

  3. SQL中过滤条件放在on和where中的区别

    sql中过滤条件放在on和where中的区别,inner join没区别.后来才想起来,连接查询除了inner join还有right join,left join. join过程可以这样理解:首先两 ...

  4. sql 触发器嵌套条件_SQL Server中的嵌套触发器

    sql 触发器嵌套条件 Nested Triggers in SQL Server are actions that automatically execute when a certain data ...

  5. ms sql server 多条件模糊查找

    ms sql server 多条件模糊查询 应用情景:为了在一个表A中,查找多个供应商的供货情况.由于录入时,没有限制,经常会出现供应商名称不唯一情况,只能使用模糊查找. 操作方法:建一个表B,把要匹 ...

  6. 2023年湖北黄石初级工程师职称在哪里报名?评审条件是什么启程别

    2023年湖北黄石初级工程师职称在哪里报名?评审条件是什么启程别 湖北黄石网上报名,具体的网址是黄石的人社局官网直接进行申报就可以了.启程别告诉你湖北黄石初级工程师职称在哪里报名? 搜一下启程别就知道 ...

  7. 动态SQL的 if 条件判断

    错误方式一: 在mybatis的动态sql语句中使用<if>标签可以判断sql中的条件是否成立. <select id="getPerson" resultTyp ...

  8. mysql 查询后根据值的不同进行判断与修改,SQL中的条件判断语句(case when zhen)用法

    需求: mysql 查询后根据值的不同进行判断与修改 语法结构: SQL中的条件判断语句(case when zhen)用法 SELECT A.品号,属性,        CASE           ...

  9. SQL中on条件与where条件的区别

    SQL中on条件与where条件的区别 数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户. 在使用left jion时,on和where条件的区别如下: ...

最新文章

  1. 自学考试计算机实践课,自学考试的计算机实践课怎么考大神们帮帮忙
  2. python第三方库numpy-python第三方库之numpy基础
  3. 【原创】面向对象作业:选课系统中用pickle储存多个对象间组合引用关系的那些坑...
  4. JavaScript---Ajax和函数回调,异步编程
  5. 剑指Offer - 面试题7. 重建二叉树(递归)
  6. python随机森林 交叉验证_随机森林是否需要交叉验证+特征的重要性
  7. modify sql_在SQL Server中使用JSON_MODIFY()修改JSON数据
  8. Emgu-WPF 激光雷达研究-移动物体跟踪2
  9. 想要组装一台 RISC-V PC?试试这个 RISC-V 开发板
  10. 阿里云云计算 9 弹性裸金属服务器(神龙)
  11. Scratch2exe-ch将sb2文件转换为exe文件
  12. 英国政府将投资11.4亿英镑部署FTTP和开发5G
  13. 【登录界面】vue、element-ui登录界面模板
  14. 浅析图的邻接矩阵进行平方运算的含义
  15. 80004005错误代码_Win10系统提示0x80004005错误代码快速解决方法
  16. 森林中的兔子java
  17. 一个C语言编写的坦克大战游戏
  18. 以Windows系统搭建基于Ethereum(以太坊)的区块链开发环境(具体操作与截图)
  19. Oracl中PL/SQL编程(10级学员 张帅鹏课堂总结)
  20. 2021年安全员-C证(山东省-2021版)找解析及安全员-C证(山东省-2021版)模拟考试

热门文章

  1. 网上人才招聘系统(php+mysql)
  2. 断言Assertion
  3. matlab 函数,matlab 语法1
  4. 用dd命令克隆ubuntu系统
  5. 【STM32】SPI协议通信详解
  6. gpu显示off_GPU常见故障及排查方法
  7. 技术贴 | 视频清晰度由什么决定
  8. 支持tcam的服务器,使用tcam实现数据流的选择性路由
  9. 图像处理之高斯混合模型
  10. mysql数据库中查看数据库当前连接数