基于MyBatis框架所遇到的常见问题及其解决方法

发布于:2023-01-15 ⋅ 阅读:(1245) ⋅ 点赞:(0)

目录

一、MyBatis是什么?

1.1、概述

1.2、MyBatis主要内容

1.3、优点

1.4、缺点

二、MyBatis架构

2.1、mybatis所依赖的jar包

2.2、MyBatis准备工作

三、Mybatis映射中遇到的常见问题

1.主配置文件中的sql语句未对应好

 2.主配置文件中未配置对应mapper文件的namespace的值或配错

3.xml文件和映射器接口的名称要一致

4.xml文件的sql语句标签ID名字要与对应的映射器接口方法名一致 

四、mybatis中的几个关键知识点 

 1.标签传递多个参数时的解决方法2.标签中的主键回填(自动递增)问题解决办法3.resultMap:当多表操作中,返回结果集就应该使用resultMap, 元素的 type 属性表示需要的实体类,id 属性是 resultMap 的唯一标识。4.#{}与${}的区别(重要!!!)

一、MyBatis是什么?

1.1、概述

  • Mybatis是一个优秀的开源、轻量级持久层框架,它对JDBC操作数据库的过程进行封装,简化了加载驱动、创建连接、创建 statement 等繁杂的过程,使开发者只需要关注sql本身。

  • 我们原来使用JDBC操作数据库,需要手动的写代码去注册驱动、获取connection、获取statement等等,现在Mybaits帮助我们把这些事情做了,我们只需要关注我们的业务sql即可,这样可以提高我们的开发效率。

  • MyBatis属于半自动的ORM框架

  • MyBatis 支持定制化 SQL、存储过程以及高级映射,可以在实体类和 SQL 语句之间建立mapping映射关系,是一种半自动化的 ORM 实现。其封装性低于 Hibernate,但性能优秀、小巧、简单易学、应用广泛。

1.2、MyBatis主要内容

MyBatis 前身为 iBatis,2002 年由 Clinton Begin 发布。2010 年从 Apache 迁移到 Google,并改名为 MyBatis,2013 年又迁移到了 Github。


MyBatis 的主要思想是将程序中的大量 SQL 语句剥离出来,使用 XML 文件或注解的方式实现 SQL 的灵活配置,将 SQL 语句与程序代码分离,在不修改程序代码的情况下,直接在配置文件中修改 SQL 语句。MyBatis与其它持久性框架最大的不同是,MyBatis 强调使用 SQL,而其它框架(例如 Hibernate)通常使用自定义查询语言,即 HQL(Hibernate查询语言)或EJB QL(Enterprise JavaBeans查询语言)。

1.3、优点

●MyBatis是免费且开源的。
●与 JDBC 相比,减少了 50% 以上的代码量。
●MyBatis是最简单的持久化框架,体积小巧并且学习门槛低。
●MyBatis相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL 写在 XML 中,和程序逻辑代码分离,降低耦合度,便于同一管理和优化,提高了代码的可重用性。
●提供 XML 标签,支持编写动态 SQL语句。
●提供映射标签,支持实体对象与数据库的表字段关系映射。

1.4、缺点

●编写 SQL语句工作量较大,对开发人员编写 SQL 语句的功底有一定要求。
●SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

二、MyBatis架构

2.1、mybatis所依赖的jar包

lib 文件夹下的 jar 文件是 MyBatis的依赖包(mybatis-3.5.10.jar是MyBatis的核心包)

f732ddf5811f4299bff4059b545c09ae.png

 将需要的核心包全部添加进项目构建路径中

2.2、MyBatis准备工作

4d993046410542d2aa2329b326d82f9d.png

三、Mybatis映射中遇到的常见问题

1.主配置文件中的sql语句未对应好

若库名未配置好会出现

 

 mySql用户名及密码未配置好

 2.主配置文件中未配置对应mapper文件的namespace的值或配错

 会发生错误

3.xml文件和映射器接口的名称要一致

4.xml文件的sql语句标签ID名字要与对应的映射器接口方法名一致 

 若不一致会出现

四、mybatis中的几个关键知识点 

 1.<select>标签传递多个参数时的解决方法

(1.1)使用Map传递参数

在WebsiteMapper.xml中定义<select>节点

<!-- 根据name和url模糊查询网站信息 -->
<select id="selectWebsiteByMap" 
        resultType="com.apesource.entity.Website" 
        parameterType="map">
  SELECT id,NAME,url FROM website
  WHERE name LIKE CONCAT ('%',#{name},'%')
  AND url LIKE CONCAT ('%',#{url},'%')
</select>

在 WebsiteMapper 接口中,定义方法selectWebsiteByMap:

<!-- 根据name和url模糊查询网站信息 -->
<select id="selectWebsiteByMap" 
        resultType="com.apesource.entity.Website" 
        parameterType="map">
  SELECT id,NAME,url FROM website
  WHERE name LIKE CONCAT ('%',#{name},'%')
  AND url LIKE CONCAT ('%',#{url},'%')
</select>

 测试代码:

Map<String,String> paramsMap = new HashMap<String,String>();
paramsMap.put("name","小原网");
paramsMap.put("url","apesource");
websiteMapper.selectWebsiteByMap(paramsMap);

使用 Map 传递参数虽然简单易用,但是由于这样设置参数需要键值对应,业务关联性不强,开发人员需要深入到程序中看代码,造成可读性下降。
(1.2)使用注解传递参数

使用 MyBatis 的注解 @Param() 传递参数,如下所示:

WebsiteMapper.xml

<!-- 根据name和url模糊查询网站信息 -->
<select id="selectWebsiteByAn" resultType="com.apesource.entity.Website">
  SELECT id,NAME,url FROM website
  WHERE name LIKE CONCAT ('%',#{name},'%')
  AND url LIKE CONCAT ('%',#{url},'%')
</select>

  在WebsiteMapper 接口中,定义方法selectWebsiteByAn():

public List<Website> selectWebsiteByAn(@Param("name") String name, @Param("url") String url);

  当我们把参数传递给后台时,MyBatis 通过 @Param 提供的名称就会知道 #{name} 代表 name 参数,提高了参数可读性。但是如果这条 SQL 拥有 10 个参数的查询,就会造成可读性下降,增强了代码复杂性。


(1.3)使用JavaBean传递参数

在参数过多的情况下,MyBatis 允许组织一个 JavaBean,通过简单的 setter和 getter方法设置参数,提高可读性。

WebsiteMapper.xml

<!-- 根据name和url模糊查询网站信息 -->
<select id="selectWebsiteByAn" resultType="com.apesource.entity.Website">
  SELECT id,NAME,url FROM website
  WHERE name LIKE CONCAT ('%',#{name},'%')
  AND url LIKE CONCAT ('%',#{url},'%')
</select>

 WebsiteMapper.java

public List<Website> selectWebsiteByAn(Website website);

 (1.4)区别
以上 3 种方式的区别如下:
●使用 Map 传递参数会导致业务可读性的丧失,继而导致后续扩展和维护的困难。
●使用 @Param 注解传递参数会受到参数个数的影响。当 n≤5 时,它是最佳的传参方式,因为它更加直观;当 n>5 时,多个参数将给调用带来困难。
●当参数个数大于 5 个时,建议使用 JavaBean 方式。

2.<insert>标签中的主键回填(自动递增)问题解决办法

在某些场景下,我们可能需要将这个刚刚生成的主键回填到请求对象(原本不包含主键信息的请求对象)中,供其他业务使用。此时,我们就可以通过在 <insert> 标签中添加 keyProperty 和 useGeneratedKeys 属性,来实现该功能

<insert id="insertNewWebsite" 
			parameterType="com.apesource.entity.Website" 
			useGeneratedKeys="true"
			keyProperty="id">
		insert into website(name,url,age)values(#{name},#{url},#{age})
</insert>

 自定义主键

如果在实际项目中,若数据库不支持主键自动递增(例如 Oracle),或者取消了主键自动递增的规则,我们可以使用 MyBatis 的 <selectKey> 标签自定义生成主键

<insert id="insertNewWebsite" 
			parameterType="com.apesource.entity.Website">
    <selectKey keyProperty="id" resultType="Integer" order="BEFORE">
			select if(max(id) is null,1,max(id)+1) as newId from Website
		</selectKey>
		insert into website(id,name,url,age)values(#{id},#{name},#{url},#{age})
</insert>

<selectKey> 标签中属性说明如下:
●keyProperty:用于指定主键值对应的 PO 类的属性。
●order:该属性取值可以为 BEFORE 或 AFTER。
○BEFORE 表示先执行 <selectKey> 标签内的语句,再执行插入语句;
○AFTER 表示先执行插入语句再执行 <selectKey> 标签内的语句。

3.resultMap:当多表操作中,返回结果集就应该使用resultMap,<resultMap> 元素的 type 属性表示需要的实体类,id 属性是 resultMap 的唯一标识。

 resultType和resultMap的区别
MyBatis 的每一个查询映射的返回类型都是 resultMap,只是当我们提供的返回类型是 resultType 时,MyBatis 会自动把对应的值赋给 resultType 所指定对象的属性,而当我们提供的返回类型是 resultMap 时,MyBatis 会将数据库中的列数据复制到对象的相应属性上,可用于复制查询。
需要注意的是,resultMap 和 resultType 不能同时使用。

4.#{}与${}的区别(重要!!!

默认情况下,使用 #{}参数语法时,MyBatis会创建 PreparedStatement参数占位符,并通过?占位符安全地设置参数。 这样做更安全,更迅速,通常也是首选做法,不过有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。 比如 ORDER BY 子句,这时候你可以:ORDER BY ${columnName},这个时候${}将直接在SQL语句中进行字符串的拼接。

 具体区别点总结如下
(1)使用#{}会产生1个?占位符,并使用PreparedStatement进行处理。而${}则进行的是字符串的拼接。
(2)使用#{}可以预防SQL注入,而${}无法防止SQL注入。
(3)${}一般用于在SQL中拼接数据库表名、视图或关键字,例如动态使用order by 进行排序时,就需要使用${}来拼接排序字段名称和排序规则。

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到