事情的发展是这样的:

  因为一个需求,需要在java中拼接出一个完整的sql语句,然后将整条sql语句传递给mybatis执行。

mapper.java是这样的:

  1. int insertMaster(WorksheetMasterSQLBean masterBean);

这个对象是:

  1. public class WorksheetMasterSQLBean {
  2.  
  3. private Long id;
  4.  
  5. private String masterInsertSql;

【就是用

  1. masterInsertSql 字段装了一下SQL,因为要在insert执行后返回自增ID的缘故,所以把SQL装在一个对象的属性中。主要就是想用一个beanid取接收一下自增id.

无所谓啦,往下看】【mybatis的insert返回自增id

mapper.xml是这样的:

【把sql放进insert标签中,执行】

  1.   <insert id="insertMaster" parameterType="com.lqjava.daywork.api.beans.WorksheetMasterSQLBean" useGeneratedKeys="true" keyProperty="id">
  2. #{masterInsertSql}
  3. </insert>

SQL语句是:

【这就是在java中直接拼接好的sql语句】

  1. INSERT INTO worksheet_data_14 (create_by,create_date,update_by,update_date,`input-number_0`) VALUES (1,'2019-05-15 12:44:45',1,'2019-05-15 12:44:45','坦桑尼亚' )

报错:

【妈的,报错了】

  1. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''INSERT INTO

原因:

1.到了这里,就思考这个问题。

我传入的参数,也就是String类型的sql语句,明明就是上面那个,为什么执行完了会报错。而且错误提示,就是在

  1. ''INSERT INTO

这个地方?

怀疑是不是在java中sql拼接的时候,自己多搞出来几个单引号在前面呀【或者空格之类的】

2.仔细的debug了几次程序,发现,java中拼接出来的sql语句完全没有任何问题。

既没有加单引号,又没有前后空格,也没有使用关键字这一说。

那问题只能在将 sql送进mybatis之后,发生的问题了。

3.这里就说到了mybatis的$和#的区别

首先:

  mybatis拼接sql时候,使用${参数} 和 #{参数} 都可以接受参数

第二:

例如:age = 1

  1. select * from user where age = #{age};
  1. select * from user where age = ${age};

如果使用${参数},那就是将参数原原本本的进行字符串的替换,不会做任何过多的处理。

看一下${}对上面的预编译的结果为

  1. select * from user where age = 1;

如果使用#{参数},则会在预编译阶段生成占位符?,实际值的替换是在DBMS中进行的。

看一下#{}对上面的预编译的结果为

  1. select * from user where age = ?;

4.那看到了$和#的区别,为什么两个都可以在mybatis中使用?各自的优势何在

  1》#{},预编译生成占位符?,实际的参数值替换在DBMS中,根据参数类型,是否添加''单引号

    第一个优势:

      省时省力。那预编译的语句,会被缓存下来,下次相同的语句执行,不用编译,直接就可以拿到数据库操作,直接在数据库中进行参数替换即可。省时省力。

    第二个优势:

      防止SQL注入。如果像我上面的使用情况,我给占位符的地方传入的并不是一个值,而是一个;delete的删除语句,那直接传入数据库中,有了占位符替换的过程,会自动给string类型的加上''单引号在前后,这样就出现了上面我的错误。执行不了。

  2》${},直接进行字符串的替换

    那按上面那么说,${}就完全没有优势可言了么?

    不是的,就像上面的错误一样,这个时候就需要${}出马,才能直接将完整的sql语句替换。不会添加任何的''在前后。

    所以,像是如果mybatis中写了sql,但是表名是动态的,则需要${}。因为表名是不需要加''在前后的。

5.对于mybatis中#和$的总结

  #{}是占位符号

  ${}是sql拼接符号

解决方案:

替换mapper.xml中的#为$,即可解决问题:

  1.   <insert id="insertMaster" parameterType="com.lqjava.daywork.api.beans.WorksheetMasterSQLBean" useGeneratedKeys="true" keyProperty="id">
  2. ${masterInsertSql}
  3. </insert>

【mybatis】从一个错误,看mybatis中的#和$的区别的更多相关文章

  1. OpenStack学习系列-----第二篇 由一个错误看理解整个架构的重要性

    看了openstack没几天,然后就开始试着用Java调用所有的API,第一步得到Credentials的时候成功了,然后第二步,传参数使所有的server信息都列出来的时候报错404.具体描述如下( ...

  2. 记录定时任务的一个错误:crontab 中使用"%"的问题

    最近工作需要,需要定时执行命令文件,并且把执行的日志重定向输出到以日期命名的文件中,命令如下: /bin/bash /data/shell/merge.sh &>> /data/s ...

  3. mybatis 学习笔记 -详解mybatis 及实例demo

    快速入门1 要点: 首先明白mybatis 是什么 这是一个持久层的框架.之前叫做ibatis.所以,在它的代码中出现ibatis这个词的时候,不要感到惊讶.不是写错了,它确实就是这个样子的. 首先, ...

  4. 【mybatis】mybatis执行一个update方法,返回值为1,但是数据库中数据并未更新,粘贴sql语句直接在数据库执行,等待好久报错:Lock wait timeout exceeded; try restarting transaction

    今天使用mybatis和jpa的过程中,发现这样一个问题: mybatis执行一个update方法,返回值为1,但是数据库中数据并未更新,粘贴sql语句直接在数据库执行,等待好久报错:Lock wai ...

  5. 关于Mybatis的@Param注解 及 mybatis Mapper中各种传递参数的方法

    原文:https://blog.csdn.net/mrqiang9001/article/details/79520436 关于Mybatis的@Param注解   Mybatis 作为一个轻量级的数 ...

  6. 带你搭建一个简单的mybatis项目:IDEA+spring+springMVC+mybatis+Mysql

    最近小编有点闲,突发奇想想重温一下mybatis,然后在脑海中搜索了一下,纳尼,居然不太会用了,想到这里都是泪啊!!现在我所呆的的公司使用的是springboot+hebinate,编程都是使用的JP ...

  7. 浅析mybatis中${}和#{}取值区别

    mybatis作为一个轻量级的ORM框架,应用广泛,其上手使用也比较简单:一个成熟的框架,必然有精巧的设计,值得学习. 在使用mybatis框架时,在sql语句中获取传入的参数有如下两种方式: ${p ...

  8. 从Mybatis的视角去看Bean的初始化流程

    不涉及Spring完整的启动流程,仅仅从Mybatis的视角去分析几个关键的方法,找到Mybatis是如何通过这几个扩展点植入进去的,反过来看Spring是如何设计,埋下这些伏笔,实现其可扩展性. s ...

  9. Mybatis中的#{}和${}的区别?

    1,首先Mybatis中的#{}与${}到底有什么区别? #{}:表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{} ...

  10. Mybatis源码详解系列(三)--从Mapper接口开始看Mybatis的执行逻辑

    简介 Mybatis 是一个持久层框架,它对 JDBC 进行了高级封装,使我们的代码中不会出现任何的 JDBC 代码,另外,它还通过 xml 或注解的方式将 sql 从 DAO/Repository ...

随机推荐

  1. Android资源限定符

    Android系统会根据设备参数,自动选择最佳资源配置方案. Android中常见的资源限定符: 屏幕特征 限定符 描述 大小 small 提供给小屏幕设备的资源 normal 提供给中等屏幕设备的资 ...

  2. Bit Operation妙解算法题

    5道巧妙位操作的算法题. ***第一道*** 题目描述 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次.找出那个只出现了一次的元素. 说明: 你的算法应该具有线性时间复杂度. ...

  3. 菜鸟之路——机器学习之KNN算法个人理解及Python实现

    KNN(K Nearest Neighbor) 还是先记几个关键公式 距离:一般用Euclidean distance   E(x,y)√∑(xi-yi)2 .名字这么高大上,就是初中学的两点间的距离 ...

  4. Linux下MySQL c++ connector示例

    最近在学习数据库的内容,起先是在windows下用mysql c++ connector进行编程,之所以选用c++而不是c的api,主要是考虑到c++ connector是按照JDBC的api进行实现 ...

  5. [oldboy-django][1初始django]web框架本质 + django框架 + ajax

    web框架本质 浏览器(socket客户端) - 发送请求(ip和端口,url http://www.baidu.com:80/index/) - GET 请求头(数据请求行的url上: Http1. ...

  6. [转]Docker容器内不能联网的6种解决方案

    注: 下面的方法是在容器内能ping通公网IP的解决方案,如果连公网IP都ping不通,那主机可能也上不了网(尝试ping 8.8.8.8) 1.使用--net:host选项 sudo docker ...

  7. Zookeeper ZooDefs.Ids

    OPEN_ACL_UNSAFE  : 完全开放的ACL,任何连接的客户端都可以操作该属性znode CREATOR_ALL_ACL : 只有创建者才有ACL权限 READ_ACL_UNSAFE:只能读 ...

  8. 感谢beyond,感谢家驹

  9. PHP共享内存的应用shmop系列

    简单的说明 可能很少情况会使用PHP来操控共享内存,一方面在内存的控制上,MC已经提供了一套很好的方式,另一方面,自己来操控内存的难度较大,内存的读写与转存,包括后面可能会用到的存储策略,要是没有一定 ...

  10. Android EditText默认不弹出输入法,以及获取光标,修改输入法Enter键的方法

    一.Android EditText默认不弹出输入法的办法:1. 在AndroidManifest.xml中将需要默认隐藏键盘的Activity中添加属性即可(常用此方法) android:windo ...