MyBatis开发过程常见的坑

之所以把写关于MyBatis开发过程中遇到的坑写下来并变成文章,第一个是对自己开发MyBatis的过程中遇到的问题的一个总结,同事也是希望其他看到本博文的网友可以少遇到一些坑。

1. 异常篇

  1. 无效绑定



    提示无效的绑定的方式(映射错误)(比如没有找到那个findAll 的方法)
    原因:出在了XML Mapper文件上,去对应的XML文件查看。
    可能是:
    1). namespace 错误
    2). resultMap 错误(type错误、属性错误)

  2. 查询结果集超过一个


    此异常也是开发过程中常见的坑,比如public User findUserByUsername()这样的查询,方法返回的是一个User对象,但实际数据有可能是可以查询出多条的。很多时候开发的时候由于数据不够真实或者测试的不够充分,问题往往不会暴露出来,等到生产环境才会暴露出来。对于此类问题避免的方法就是对应返回一个非集合类的时候,需要特别注意查询是不是会返回多条记录的问题(单字段查询的话可以看看此字段数据库是不是有唯一性索引),如果不确定那么可以加上limit 1比较保险。

  3. 字段映射不正确


### Error querying database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'name' in 'field list'
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'name' in 'field list'
; bad SQL grammar []

主要原因:

  • Mybatis XML中的SQL语句查询的列,不在数据库中。
  • 新增SQL语句中的列不在数据库中,或列对应的值,数据类型不一致。
    解决办法: 根据项目实际情况,通常有以下三种解决办法:
  • 修改SQL语句中,将不存在的列从语句中去掉。
  • 在数据库中,新增该不存在的列。
  • 在新增时,不要使用中文符号的``表示字符串。也就是~符号对应的键。
  1. join时多个表表中含有相同的字段但是未使用别名
### Error querying database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'oid' in field list is ambiguous
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'oid' in field list is ambiguous
; SQL []; Column 'oid' in field list is ambiguous

2. 其他潜在的问题

  1. insert写成select
    在通常的情况下,此写法是可以正常运行的。不过在有一些公司自定义的MyBatis时(像我们公司为了支持分库分表)开发了一套自定义的mybatis组件,这个组件如果select标签里面写insert时就会报错。
  <select id="insert" resultMap="BaseResultMap">
    insert into user (id, name, password) values
   (#{id}, #{name}, #{password})
  </select>

所以大家标签和语句还是需要对应的好,否则有可能会出现不可预知的错误。

  1. select中的resultMap属性不正确

一些Eclipse或idea有根据Mapper接口自动生成xml的功能,比如作者之前安装的一个插件就会把所有的mapper中的方法生成<select>的标签的的属性是resultType而不是resultMap,这样user_id属性的值就不能得到正确的映射了。

  <select id="selectAll" resultType="com.bfbm.mybatis.entity.User">
    select user_id, name, password
    from user
  </select>

正确的方法是使用resultMap或者select语句中有_的字段都增加AS

  <select id="selectAll" resultType="com.bfbm.mybatis.entity.User">
    select user_id AS userId, name, password
    from user
  </select>
  1. #和$混用的问题
    看官方文档如何描述的http://www.mybatis.org/mybatis-3/sqlmap-xml.html#select

    可以看到官方的问题写的很清楚,使用#,MyBatis会使用PreparedStatement来进行SQL查询,可以防止SQL注入。而$更多的是用来访问配置文件中的属性的。所以大家在自己的SQL中还是应该经量使用#。
    image.png
  2. 在使用resultMap的时候,要把ID写在第一行,否则的话,就会报错。


  3. 时间戳的使用
    很多表一般会给一个create_time和update_time两个字段。很多小伙伴一般在Java中去手动设置两个字段的值。其实更好的办法是使用数据自带的时间戳函数
CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(255) DEFAULT NULL COMMENT '姓名',
  `password` varchar(255) DEFAULT NULL COMMENT '密码',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  1. 可以不用if choose等语句就经量少用
    有一些开发,很多代码都是从别人的Mapper文件copy过来的,很多情况下也思考为什么。比如<if> <choose>这些条件语句的使用,如果你的参数是必传的话,那么就不要写<if>,这样可以减少不必要的运算和使代码清晰。比如你们公司的DBA看见这样的语句,知道你的索引使用的对吗?
<select id="selectByXxx" parameterType="com.bfbm.mybatis.entity.Student">
    select 
  <include refid="Base_Column_List" />
  from student
    <where>
      <if test="mobile != null">
        and mobile = #{mobile,jdbcType=VARCHAR},
      </if>
      <if test="name != null">
        `and name` = #{name,jdbcType=VARCHAR},
      </if>
      <if test="userId != null">
        and user_id = #{userId,jdbcType=INTEGER},
      </if>
    </where>
  </select>

比如此例中的userId如果已经是添加了索引,而且是必填的,那么就不要写<if>啦,直接最后写user_id = #{userId}就可以了。

更多Java开发相关技术文章请关注巴分巴秒官方简书号。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335