一.Mydatis中的动态sql
1.Mydatis中的动态sql出现背景?
任何技术的出现都不是空穴来风,一切都是有迹可循的!而动态sql同样如此!
1.1传统sql语句
MyBatis 中出现动态 SQL 的背景是:为了解决传统 SQL 查询的静态性和硬编码的问题。传统的 SQL 查询语句是静态的,即在编写查询语句时需要明确指定所有的条件和参数,无法根据不同的情况生成不同的 SQL 语句。这样会导致以下一些问题:
- 条件判断的处理:在实际的查询中,往往需要根据不同的条件组合生成不同的查询语句,传统的静态 SQL 很难应对这种情况。
- 可读性和可维护性:当 SQL 查询语句过于复杂或包含大量的条件判断时,代码可读性和可维护性变得困难,容易出现错误。
- 重复代码:如果多个查询语句之间只有部分条件不同,使用传统的静态 SQL 会导致大量的重复代码,增加了开发和维护的工作量。
1.2改良的mydatissql优势
为了解决这些问题,MyBatis 引入了动态 SQL 功能,允许开发者在运行时根据不同的条件生成不同的 SQL 语句,从而提供灵活的查询能力。动态 SQL 具有以下优点:
- 灵活性:动态 SQL 允许根据不同的条件生成不同的 SQL 语句,满足各种查询需求。开发者可以根据实际情况动态组装 SQL 语句,而不需要硬编码所有可能的情况。
- 可读性和可维护性:通过使用动态 SQL 标签,可以更清晰地表达查询的逻辑,并减少重复代码。这提高了代码的可读性和可维护性,降低了出错的概率。
- 参数处理:动态 SQL 允许方便地处理参数,可以根据参数的值决定是否包含相关的查询条件或语句片段。
总之,动态 SQL 是 MyBatis 中的一个重要特性,它解决了传统 SQL 查询的静态性和硬编码的问题,使得查询语句更加灵活、可读性更高,并且减少了重复代码的编写。这为开发者带来了更好的开发体验和效率。
2.mydatis中的一些常用动态sql标签
2.1 if标签:它用于根据条件判断是否包含某一部分 SQL 语句
<select id="getUserList" parameterType="User" resultType="User"> SELECT * FROM user <where> <if test="name != null"> AND name = #{name} </if> <if test="age != null"> AND age = #{age} </if> </where> </select>
2.2 <choose>
、<when>
、<otherwise>
标签 实现类似于 switch-case 的逻辑判断
<select id="getUserList" parameterType="User" resultType="User"> SELECT * FROM user <where> <choose> <when test="name != null"> AND name = #{name} </when> <when test="age != null"> AND age = #{age} </when> <otherwise> AND status = 'ACTIVE' </otherwise> </choose> </where> </select>
2.3trim>
标签:它可以根据条件去除或添加 SQL 语句的一部分,例如去除开头或结尾的逗号
<select id="getUserList" parameterType="User" resultType="User"> SELECT * FROM user <trim prefix="WHERE" prefixOverrides="AND | OR"> <if test="name != null"> AND name = #{name} </if> <if test="age != null"> AND age = #{age} </if> </trim> </select>
2.4<foreach>
标签,用于循环遍历集合或数组,并将集合中的元素应用到 SQL 语句中的特定部分
2.4.1<foreach>
标签包含的属性名
collection
:指定要遍历的集合或数组的名称。item
:指定每次遍历时的当前元素的别名。index
:指定每次遍历时的索引的别名。open
:指定循环开始时要添加的字符串。close
:指定循环结束时要添加的字符串。separator
:指定每次循环之间要添加的字符串。
2.4.2实例
<select id="getUserList" parameterType="java.util.List" resultType="User"> SELECT * FROM user WHERE id IN <foreach collection="list" item="id" open="(" close=")" separator=","> #{id} </foreach> </select> 在上述示例中,我们
在上述示例中,我们使用 <foreach>
标签循环遍历名为 list
的集合,将集合中的元素应用到 SQL 语句的 IN
子句中,生成类似于 WHERE id IN (1, 2, 3)
的查询语句。
通过使用 <foreach>
标签,我们可以方便地处理集合或数组中的元素,动态生成适应不同数据集合的 SQL 语句
二.mybatis中的模糊查询
1.三种模糊查询
实现接口方法,和测试类
List<Book> like1(@Param("bname") String bname); List<Book> like2(@Param("bname") String bname); List<Book> like3(@Param("bname") String bname);
@Test public void testlike1() { bookBiz.like1("圣墟").forEach(System.out::println); } @Test public void testlike2() { bookBiz.like1("圣墟").forEach(System.out::println); } @Test public void testlike3() { bookBiz.like1("圣墟").forEach(System.out::println); }
1.1普通模糊查询版本
<select id="like1" resultType="com.lz.model.Book" parameterType="java.lang.String"> select <include refid="Base_Column_List"> from t_mvc_book where bname like </select>
通过此版本进行sql的调用以及功能的实现,在控制台将会打印出所需要查询的数据。而sql语句不会被打印出来,响应结果也没有!所以有缺陷,慢慢的被淘汰了
测试打印结果
1.2$版本的的模糊查询
<select id="like2" resultType="com.lz.model.Book" parameterType="java.lang.String"> select <include refid="Base_Column_List"> from t_mvc_book where bname like '${bname}' </select>
只是传参数时占位符的形式 有sql'语句的打印,标签没有响应结果,而且需要查询的参数要 ' ' 包裹!
测试打印结果
1.3 #版本的模糊查询
<select id="like3" resultType="com.lz.model.Book" parameterType="java.lang.String"> select <include refid="Base_Column_List"> from t_mvc_book where bname like concat ('%', #{bname},'%') </select>
预处理sql,有sql语句的打印并且也有参数的回显,在目前的主流企业开发中经常用到
打印测试结果
2. $和#的区别
2.1#
参数替换方式(预编译方式)
#
是用于预编译阶段的占位符,会将传入的参数值以安全的方式替换到 SQL 语句中。
#
的使用方式是将参数直接嵌入 SQL 语句中,通常在字符串常量、数字等类型的参数值前后都会自动添加单引号或其他必要的转义符号,以确保参数被正确处理。
#
在模糊查询中使用时,可以直接拼接 %
通配符,例如:SELECT * FROM table_name WHERE column_name LIKE CONCAT('%', #{keyword}, '%')
使用 #
可以有效防止 SQL 注入攻击,因为传入的参数值会经过预编译处理,不会被当作 SQL 的一部分进行解析。
2.2 $
参数替换方式(文本替换方式):
$
是直接将参数值拼接到 SQL 语句中,没有任何预编译的过程。
$
的使用方式是直接将参数值嵌入到 SQL 语句中,不会进行任何转义或处理。
$
在模糊查询中使用时,需要手动拼接 %
通配符,例如:SELECT * FROM table_name WHERE column_name LIKE '%' || ${keyword} || '%'
使用 $
时需要特别注意防止 SQL 注入攻击,因为参数值会直接替换到 SQL 语句中,可能会导致安全问题。l
综上所述,#
是推荐使用的参数替换方式,特别是在用户输入参与的查询中,能够提供更好的安全性。而 $
则需要谨慎使用,确保参数的安全性和正确性。无论选择哪种方式,都应根据具体需求和安全要求来决定。
3.总结
1$占位符传参数,#预处理sql
2外在形式:$不带引号 ,#自带引号
3.$存在sql注入 ,#不存在
sql注入:
4.¥可以做动态列,完成动态sql开发
三. mybatis中的结果映射
3.1实例
1.返回单表的所对应的实体类,仅有一个查询结果 可用 resulttype :resultmap
2.返回单表的所对应的实体类,有多一个查询结果 可用 resulttype :resultmap
3.返回多表的所对应的实体类,仅有一个查询结果 通常用resulttype 可以用resultmap
4.返回多表的所对应的实体类,有多一个查询结果 通常用resulttype 可以用resultmap
5.返回单个字段,,仅有一个查询结果 只有resulttype
6.返回单个字段,,有多一个查询结果 只有resultty方法实现
3.2代码展示
<select id="list1" resultMap="BaseResultMap"> select * from t_mvc_book </select> <select id="list2" resultType="com.javaxl.model.Book"> select * from t_mvc_book </select> <select id="list3" resultType="com.javaxl.model.Book" parameterType="com.javaxl.model.BookVo"> select * from t_mvc_book where bid in <foreach collection="bookIds" open="(" close=")" separator="," item="bid"> #{bid} </foreach> </select> <select id="list4" resultType="java.util.Map"> select * from t_mvc_book </select> <select id="list5" resultType="java.util.Map" parameterType="java.util.Map"> select * from t_mvc_book where bid = #{bid} </select>
/** * 使用resultMap返回自定义类型集合 * @return */ List<Book> list1(); /** * 使用resultType返回List<T> * @return */ List<Book> list2(); /** * 使用resultType返回单个对象 * @return */ Book list3(BookVo bookVo); /** * 使用resultType返回List<Map>,适用于多表查询返回结果集 * @return */ List<Map> list4(); /** * 使用resultType返回Map<String,Object>,适用于多表查询返回单个结果集 * @return */ Map list5(Map book);
测试代码 @Test public void testListReturn() { List list = new ArrayList(); list.add("19"); // list.add("20"); BookVo bookVo = new BookVo(); bookVo.setBookIds(list); // 使用resultMap返回自定义类型集合 // List<Book> books = bookService.list1(); // 使用resultType返回List<T> // List<Book> books = bookService.list2(); // 使用resultType返回单个对象 // Book books = bookService.list3(bookVo); // System.out.println(books); // for (Book b : books) { // System.out.println(b); // } // 使用resultType返回List<Map>,适用于多表查询返回结果集 // List<Map> books = bookService.list4(); // for (Map book : books) { // System.out.println(book); // } Map map = new HashMap(); map.put("bid",20); Map book = bookService.list5(map); System.out.println(book); }
3.3总结
resultType
:
resultType
是一种简单的结果映射方式,用于指定查询返回结果的类型。- 通过
resultType
,可以直接指定一个 Java 类型作为查询结果的映射对象,MyBatis 会根据查询结果自动进行映射。 - 例如:
<resultType type="com.example.User"/>
resultType
适用于简单的查询,返回的结果集字段名需要与 Java 类型的属性名一一对应,且类型匹配。- 缺点是当查询结果较复杂或者查询语句中有联表查询时,无法满足灵活的映射需求。
resultMap
:
resultMap
是一种更为灵活和复杂的结果映射方式,用于自定义查询结果的映射规则。- 通过
resultMap
,可以自定义每个结果字段与 Java 对象属性之间的映射关系,支持复杂的嵌套和联表查询映射。 - 使用
resultMap
需要在映射文件中定义具体的 resultMap 配置,指定字段和属性的对应关系。 - 例如:复制代码
<resultMap id="userResultMap" type="com.example.User"> <id property="id" column="user_id"/> <result property="username" column="user_name"/> <result property="email" column="user_email"/> </resultMap>
- 在查询语句中可以使用
<resultMap>
元素的id
属性引用该 resultMap,例如:复制代码<select id="getUser" resultMap="userResultMap"> SELECT user_id, user_name, user_email FROM user WHERE user_id = #{userId} </select>
resultMap
提供了更大的灵活性,可以处理各种复杂的映射需求,但相对于resultType
需要更多的配置和定义。
综上所述,resultType
适用于简单的查询,并且查询结果与 Java 对象属性一一对应的情况。而 resultMap
则更适用于复杂的查询,需要自定义字段和属性的映射关系,包括嵌套对象和联表查询等情况。根据具体的业务需求和查询复杂度,选择合适的方式来进行结果映射。