mybatis 细节(${ ..}和#{..},resultType 和 resultMap的区别,别名的使用,Mapper 代理模式)

devtools/2025/3/2 0:47:17/

${..}和#{..} 占位符

#{..}

#{}实现的是向prepareStatement中的预处理语句中设置参数值,sql语句中#{}表示一个占位符即?

<!-- 根据id查询用户信息 -->
<select id="findUserById" parameterType="int" resultType="user">select * from user where id = #{id}
</select>

使用占位符#{}可以有效防止sql攻击

  •  使用#{} 防止SQL注入攻击的底层代码如下
  // SQL查询语句,使用占位符 ?String query = "SELECT * FROM users WHERE username = ? AND password = ?";try (Connection conn = DriverManager.getConnection(dbURL, username, password)) {if (conn != null) {// 创建PreparedStatement对象PreparedStatement pstmt = conn.prepareStatement(query);// 设置参数pstmt.setString(1, userInputUsername); // 第一个占位符pstmt.setString(2, userInputPassword); // 第二个占位符

通过上面的代码可以发现,将 传递的参数 和 sql 语句进行分离。在预编译阶段,sql 语句作为创建 preparedStatement 对象的参数,就已经确定好了。因此即使用户 进行sql 注入攻击 ,无论你输入什么,都当成一般的数据。而不会被拼接到sql 语句去。成为新的sql 语句。

什么是sql 攻击呢?

假设当前是登录界面(不使用#{} 可能会遭受 sql 攻击)

不管你之前输入了,什么,如果你后面添加这种 or 1=1 这种类似的

最后拼接到查询的sql 语句中,即使之前输入错误也可以成功。这就是因为 sql 注入导致的sql 攻击

使用#{..} 的好处

1 预防sql 攻击

2 在 mybatis 框架 映射文件,不需要手动为 传递的数据为字符串 ,添加单引号。最会实现自动添加


${..}

应用场景:${..},占位符 多用于 字符串拼接

${..} 和 #{..} 的区别

${..} 无法预防sql 攻击,当传递参数后,会直接 和 sql 语句 进行拼接,改变原有sql 语句所表达的含义

${..} 在模糊查询中,效果更大


案例

  •  ${..}和#{..} 使用模糊查询,查询数据,在 映射文件中的sql语句,测试类传递的参数 表现不同的形式

项目准备

目的:基于mybatis 框架 基础 使用 模糊查询 查 关于 l 的所有用户信息

使用 #{} 在 映射文件 的sql 语句

   select * from tb_login where username like #{username};

测试类

    List<Login> list = sqlSession.selectList("getLoginByM", "%l%");for (Login login : list) {System.out.println("id: "+login.getId()+"用户名: "+login.getUsername()+"密码: "+login.getPassword());}

 效果展示

使用 ${} 在 映射文件 的sql 语句

  select * from tb_login where username like'%${m}%';

测试类

        List<Login> list = sqlSession.selectList("getLoginByM", "l");for (Login login : list) {System.out.println("id: "+login.getId()+"用户名: "+login.getUsername()+"密码: "+login.getPassword());}

效果展示

发现  在上面使用 #{..} 传递参数 时需要添加,%;而 ${..} 因为在书写 sql 语句就已经拼接好 %,因此传递参数时,就不再需要添加


resultType 和 resultMap

1. resultType 的使用场景

  • 定义resultType 是 MyBatis 中用于指定查询结果映射到的 Java 类型。

  • 特点

    • 简单映射resultType 通常用于简单的情况,比如查询结果直接映射到基本数据类型(如 intStringDate 等)或简单对象(如 UserProduct 等)。

    • 限制:当查询结果的列名与实体类的属性名完全匹配时,可以直接使用 resultType。如果查询结果的列名和实体类的属性名不匹配,或者查询结果包含嵌套对象(如关联对象),则不能直接使用 resultType

    • 不支持复杂映射resultType 不支持复杂的结果映射,比如嵌套对象、多表关联查询等。

2. resultMap 的使用场景

  • 定义resultMap 是 MyBatis 中用于定义复杂的结果映射规则。

  • 特点

    • 复杂映射resultMap 可以处理复杂的情况,比如多表关联查询、嵌套对象、嵌套集合等。

    • 灵活性:通过 resultMap,可以定义列名到属性名的映射规则,支持嵌套结果映射(如一对一、一对多关系)。

    • 适用性resultMap 适用于复杂查询,尤其是当查询结果的列名与实体类的属性名不匹配,或者查询结果包含嵌套对象时。

resultType 和 resultMap 的区别

1resultType 适用于简单查询,要求查询结果的列名与实体类的属性名完全匹配,不支持复杂的结果映射(如嵌套对象)。与之相反,resultMap 可以处理复杂的情况,支持嵌套对象、嵌套集合等,适用于多表关联查询等复杂场景

2 使用 resultType 要求 实体类和 数据库之前 需要存在映射关系,如果不是则无法将数据,传递给实体类的成员变量。而 resultMap 不必遵循这种关系 

 

通过图片,可知 数据库的列名和成员变量要求保持一致,在使用 resultType 


3 resultMap的使用

应用场景:假设是订单和用户的关系。一个用户对应多个订单;一个订单对应一个用户。在实体类 user 类 和 实体类对应的映射文件 描述这种情况

demo(案例)

User 类

Product 类

mapper/dao   UserMapper接口

    // 查询用户 所有商品信息List<Product> queryProduct(User user);

UserMapper.xml映射文件

 <resultMap id="order" type="fs.entity.Order">
<!-- id 标签 表示为一个表的主键 column 表示为表中的列名 ,property 表示为 类中的属性名       --><id property="id" column="id"/>
<!-- result 标签 表示一般的字段        --><result property="name" column="name"/><result property="price" column="price"/>
<!--collection 标签  使用 <collection> 处理一对多关系   ,使用 <association> 处理一对一关系    --><collection property="products" ofType="fs.entity.Product"><id property="id" column="pid"/><result property="name" column="pname"/><result property="price" column="pprice"/>
<!--            		<!-collection:对关联查询到的多条记录映射到集合对象中property:将查询到的多条记录映射到User类的那个属性中ofType: 指明集合中的元素的类型--></collection></resultMap>

id: 唯一标识此 resultMap。
type: 指定要映射到的 Java 类型(可以是全限定名或别名)。
<id> 和 <result> 子元素分别用于映射主键和普通属性。property 属性对应于 Java Bean 的属性名,column 属性对应于 SQL 查询结果中的列名。

collection 标签  使用 <collection> 处理一对多关系   ,使用 <association> 处理一对一关系association
association:用于映射关联单个对象信息 
property:关联的属性名,就是将用户对象关联到Order的那个属性
javaType: 属性的类型

collection

collection:对关联查询到的多条记录映射到集合对象中

property:将查询到的多条记录映射到User类的那个属性中

ofType: 指明集合中的元素的类型


使用 resultMap
在查询语句中引用这个 resultMap

    <select id="queryProduct" parameterType="fs.entity.User" resultMap="order">
// sql 语句</select>

typeAliases(类型别名) 的使用

mybatis支持别名

别名映射的类型
_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal

自定义别名

mybatis-config.xml中配置:

<typeAliases><!-- 单个别名定义 --><typeAlias alias="user" type="org.csmf.mybatis.entity.User"/><!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) --><package name=" org.csmf.mybatis.entity "/><package name="其它包"/>
</typeAliases>

使用别名:


Mapper 代理模式

了解 原始Dao开发方法

想要了解 Mapper 代理模式 ,就要先知道 原始Dao开发方法

使用Mybatis开发Dao,通常有两个方法,即原始Dao开发方法Mapper接口开发方法。

传统的DAO开发模式

 dao/mapper 持久层接口中的方法/*** 根据ID查询User* @param id  用户Id* @return  用户信息* @throws Exception*/public User findUserById(int id) throws Exception;dao/mapper 持久层 接口实现 类//需要往UserDaoImpl注入SQLSessionFactoryprivate SqlSessionFactory sqlSessionFactory;//通过构造方法注入public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {this.sqlSessionFactory = sqlSessionFactory;}@Overridepublic User findUserById(int id) throws Exception {/*** 1.得到SqlSession* 2.调用SqlSession对应的方法(selectOne)来操作数据库* 3.关闭SqlSession* 4.返回结果*/SqlSession sqlSession = sqlSessionFactory.openSession();User user = sqlSession.selectOne("test.findUserById", id);sqlSession.close();return user;}

发现如果在接口中写很多关于操作数据库的方法,那么在接口的实现类中,每次都需要创建sqlSession 对象。基于代码的重复,于是使用依靠 Java动态代理技术的mapper 代理模式


mapper 代理模式

mapper 代理模式 ,被mybatis 官方所推崇。因此 很多情况 实现  dao/mapper持久层 的操作 都是使用 mapper 代理模式

mapper 代理模式 的优点

1 mapper 代理模式 省略了 接口的实现类,使用 映射文件 书写需要的sql 语句,具体如何去实现接口的方法有代理对象调用 

2 代理类去实现对应的接口,调用 相关方法,这些操作都已经封装好了。不需要人为创建代理类,完成这些操作,更加简单,方便


mapper 代理模式 的原则

1 在mapper.xml中namespace写的是对应Mapper接口的全限定名

  1. Mapper接口方法名和Mapper.xml中定义的每个标签如select,update等中的id相同

  2. Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同


http://www.ppmy.cn/devtools/163772.html

相关文章

Tomcat下载,安装,配置终极版(2024)

Tomcat下载&#xff0c;安装&#xff0c;配置终极版&#xff08;2024&#xff09; 1. Tomcat下载和安装 进入Apache Tomcat官网&#xff0c;我们可以看到这样一个界面。 现在官网目前最新版是Tomcat11&#xff0c;我用的是Java17&#xff0c;在这里我们选择Tomcat10即可。Tom…

Redis的优势和特点

什么是redis Remote DIctionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统&#xff0c;是跨平台的非关系型数据库。 Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储…

【Qt QML】QML鼠标事件全面解析

QML鼠标事件全面解析 一、MouseArea基础概念 在 QML 中,鼠标事件是处理用户与界面元素交互的重要部分。QML 提供了多种方式来处理鼠标事件,MouseArea 是 QML 中用于处理鼠标事件的核心元素,它可以覆盖在其他元素之上,捕获鼠标操作并触发相应的信号。 1、基本用法 import …

HTML元素,标签到底指的哪块部分?单双标签何时使用?

1. 标签&#xff08;Tag&#xff09; vs 元素&#xff08;Element&#xff09; 标签&#xff08;Tag&#xff09; 标签是 HTML 中用于定义元素的符号&#xff0c;用尖括号 < > 包裹。例如 <img> 是标签。元素&#xff08;Element&#xff09; 元素是由 标签 内容…

JAVA面试_进阶部分_netty面试题

1.BIO、NIO 和 AIO 的区别&#xff1f; BIO&#xff1a;一个连接一个线程&#xff0c;客户端有连接请求时服务器端就需要启动一个线程进行处理。线程开销大。 伪异步 IO&#xff1a;将请求连接放入线程池&#xff0c;一对多&#xff0c;但线程还是很宝贵的资源。 NIO&#x…

【Python爬虫(95)】Python爬虫进阶:构建大型垂直领域爬虫系统

【Python爬虫】专栏简介:本专栏是 Python 爬虫领域的集大成之作,共 100 章节。从 Python 基础语法、爬虫入门知识讲起,深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑,覆盖网页、图片、音频等各类数据爬取,还涉及数据处理与分析。无论是新手小白还是进阶开发…

华为在不同发展时期的战略选择(节选)

华为在不同发展时期的战略选择&#xff08;节选&#xff09; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 来源&#xff1a;谢宁专著《华为战略管理法&#xff1a;DSTE实战体系》。本文有节选修改。 导言 从目前所取得的成就往回看&#xff0c;华为…

mysqldump 参数详解

mysqldump 是一个用于备份 MySQL 数据库的工具。它可以生成一组 SQL 语句,这些语句可以用来重现原始数据库对象定义和表数据。以下是一些常用的 mysqldump 参数及其详细解释: 常用参数 基本参数 --host=host_name, -h host_name: 指定 MySQL 数据库主机地址,默认为 localh…