Mybatis学习笔记_5、Mybatis动态SQL
动态 SQL 是 MyBatis 的强大特性之一。MyBatis提供的对SQL语句动态组装的功能解决了开发人员在使用JDBC或其他的框架进行数据库开发时,需要手动拼装SQL的繁琐问题.
动态SQL元素
MyBatis 3采用了功能强大的基于OGNL的表达式来完成动态SQL,其主要元素如下:
- if :判断语句,用于单条分支判断.
- choose,when,otherwise :相当于Java中的swith…case…default语句,用于多条件分支判断。
- where,trim,set: 辅助元元素,用于处理一些SQL拼装,特殊字符问题。
- foreach :循环语句,常用于in语句等列举条件中。
- script:要在带注解的映射器接口类中使用动态 SQL,可以使用 script 元素。
- bind : 从OGNL表达式中创建一个变量,并将其绑定到上下文,常用于模糊查询的sql中。
扩展 : OGNL是Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能.它使用相同的表达式去存取对象的属性.这样可以更好的取得数据.
if
使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。比如:
public List<User> selectUserByGenderAndCid(User user);
<select id="selectUserByGenderAndCid" parameterType="user" resultType="user">SELECT *FROM t_userWHERE u_gender = #{u_gender}<if test="u_cid != null">AND u_cid = #{u_cid}</if></select>
这条语句提供了可选的查找文本功能。如果不传入 “u_cid ”,那么所有符合 “u_gender”条件都会返回;如果传入了 “u_cid ” 参数,那么就会对 “u_cid ” 一列进行查找并返回对应的user结果。
@Testpublic void Test3() throws IOException {InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactoryBuilder ssb = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = ssb.build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = new User();user.setU_gender(0);List<User> userList = mapper.selectUserByGenderAndCid(user);for (User u : userList) {System.out.println(u);}user.setU_cid(1);userList = mapper.selectUserByGenderAndCid(user);for (User u : userList) {System.out.println(u);}}
choose、when、otherwise
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
还是上面的例子,但是策略变为:传入了 “u_gender” 就按 “u_gender” 查找,传入了 “u_cid” 就按 “u_cid” 查找的情形。若两者都没有传入,就返回表中所有数据。
public List<User> selectUserByGenderOrCid(User user);
<select id="selectUserByGenderOrCid" parameterType="user" resultType="user">SELECT *FROM t_userWHERE 1=1<choose><when test="u_gender != null">AND u_gender = #{u_gender}</when><when test="u_cid != null">AND u_cid = #{u_cid}</when><otherwise></otherwise></choose></select>
@Testpublic void Test4() throws IOException {InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactoryBuilder ssb = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = ssb.build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> userList = null;//传入u_genderUser user = new User();user.setU_gender(0);userList = mapper.selectUserByGenderOrCid(user);for (User u : userList) {System.out.println(u);}//传入u_cidUser user2 = new User();user2.setU_cid(1);userList = mapper.selectUserByGenderOrCid(user2);for (User u : userList) {System.out.println(u);}//u_gender、u_cid均不传入User user3 = new User();userList = mapper.selectUserByGenderOrCid(user3);for (User u : userList) {System.out.println(u);}//传入u_gender、u_cidUser user4 = new User();user4.setU_gender(0);user4.setU_cid(1);userList = mapper.selectUserByGenderOrCid(user4);for (User u : userList) {System.out.println(u);} }
trim、where、set
前面几个例子已经方便地解决了一个臭名昭著的动态 SQL 问题。现在回到之前的 “if” 示例,这次我们将 “ u_gender = #{u_gender}” 设置成动态条件,看看会发生什么。
<select id="selectUserByGenderAndCid" parameterType="user" resultType="user">SELECT *FROM t_userWHERE<if test="u_gender != null">u_gender = #{u_gender}</if><if test="u_cid != null">AND u_cid = #{u_cid}</if></select>
如果没有匹配的条件会怎么样?最终这条 SQL 会变成这样:
SELECT *FROM t_userWHERE
这会导致查询失败。如果匹配的只是第二个条件又会怎样?这条 SQL 会是这样:
SELECT *FROM t_userWHEREAND u_cid = #{u_cid}
这个查询也会失败。这个问题不能简单地用条件元素来解决。这个问题是如此的难以解决,以至于解决过的人不会再想碰到这种问题。
where
MyBatis 有一个简单且适合大多数场景的解决办法。而在其他场景中,可以对其进行自定义以符合需求。而这,只需要一处简单的改动:
<select id="selectUserByGenderAndCid" parameterType="user" resultType="user">SELECT *FROM t_user<where><if test="u_gender != null">u_gender = #{u_gender}</if><if test="u_cid != null">AND u_cid = #{u_cid}</if></where></select>
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
@Testpublic void Test3() throws IOException {InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactoryBuilder ssb = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = ssb.build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> userList = null;User user = new User();//不设置u_gender u_ciduserList = mapper.selectUserByGenderAndCid(user);for (User u : userList) {System.out.println(u);}//先设置u_ciduser.setU_cid(1);userList = mapper.selectUserByGenderAndCid(user);for (User u : userList) {System.out.println(u);}//在设置u_genderuser.setU_gender(0);userList = mapper.selectUserByGenderAndCid(user);for (User u : userList) {System.out.println(u);} }
trim
如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR ">...
</trim>
prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。
set
用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:
<update id="updateUserIfNecessary" parameterType="user">UPDATE t_user<set><if test="u_username != null">u_username=#{u_username},</if><if test="u_password != null">u_password=#{u_password}</if></set>where u_id=#{u_id}</update>
@Testpublic void Test5() throws IOException {InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactoryBuilder ssb = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = ssb.build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = new User();user.setU_id(1);user.setU_username("隔壁老王");user.setU_password("6666666");mapper.updateUserIfNecessary(user);//提交事务sqlSession.commit();User user2 = mapper.selectUserById(1);System.out.println(user2);}
这个例子中,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。
来看看与 set 元素等价的自定义 trim 元素吧:
<trim prefix="SET" suffixOverrides=",">...
</trim>
注意,我们覆盖了后缀值设置,并且自定义了前缀值。
foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:
public List<User> selectCidIn(List<Integer> list);
<select id="selectCidIn" resultType="user">SELECT *FROM t_userWHERE u_cidIN<foreach item="item" index="index" collection="list" open="(" separator="," close=")">#{item}</foreach></select>
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。
你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
@Testpublic void Test6() throws IOException {InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactoryBuilder ssb = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = ssb.build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<Integer> list = new ArrayList<Integer>();list.add(1);list.add(3);list.add(5);List<User> userlist = mapper.selectCidIn(list);for (User user : userlist) {System.out.println(user);}}
script
要在带注解的映射器接口类中使用动态 SQL,可以使用 script 元素。比如:
@Update({"<script>","update t_user"," <set>"," <if test='u_username != null'>u_username=#{u_username},</if>"," <if test='u_password != null'>u_password=#{u_password},</if>"," </set>","where u_id=#{u_id}","</script>"})void updateUserValues(User user);
bind
元素允许你在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。比如:
public List<User> selectNameLike(User user);
<select id="selectNameLike" resultType="user"><bind name="pattern" value="'%' + u_username + '%'" />select * from t_user where u_username like #{pattern}
</select>
@Testpublic void Test7() throws IOException {InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactoryBuilder ssb = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = ssb.build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = new User();user.setU_username("王");List<User> userlist = mapper.selectNameLike(user);for (User user1 : userlist) {System.out.println(user1);}}
配置文件
db.properties
#database configuration information
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_ssm_mybatis?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
jdbc.username=root
jdbc.password=123456
log4j.properties
#Global configuration
log4j.rootLogger=DEBUG,stdout
#Console configuration
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.layout.ConversionPattern=%5p [%t] - %m%n
sqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- 读取数据库配置文件 --><properties resource="db.properties" /><typeAliases><!-- <typeAlias alias="user" type="pers.goodwin.mybatis.bean.User"/> --><!-- 推荐使用扫描包的形式来配置别名 包的形式会扫描包及子包下的所有文件, 以对象类名为别名,大小写不敏感,推荐使用小写 --><package name="pers.goodwin.mybatis.bean" /></typeAliases><!-- 配置环境-默认环境id为MySQL --><environments default="MySQL"><environment id="MySQL"><!-- 使用JDBC事务管理 --><transactionManager type="JDBC" /><!-- 数据库连接池 --><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></dataSource></environment></environments><!-- 将sql映射文件注册到全局配置文件中 --><mappers><!-- 使用相对于类路径的资源引用 --><!-- <mapper resource="pers/goodwin/mybatis/mapper/UserMapper.xml" /> --><!-- 使用完全限定资源定位符(URL) --><!-- <mapper url="file:///G:\Java\ssm_mybatis_part1\src\pers\goodwin\mybatis\mapper\UserMapper.xml"/> --><!-- 使用映射器接口实现类的完全限定类名 --><!-- <mapper class="pers.goodwin.mybatis.mapper.UserMapper"/> --><!-- 将包内的映射器接口实现全部注册为映射器 --><package name="pers.goodwin.mybatis.mapper" /></mappers>
</configuration>
UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!-- <mapper namespace="org.mybatis.example.BlogMapper"> <select id="selectBlog" resultType="Blog"> select * from Blog where id = #{id} </select> </mapper> --><mapper namespace="pers.goodwin.mybatis.mapper.UserMapper"><select id="selectUserById" parameterType="Integer"resultType="user">select * from t_user where u_id = #{id}</select><!-- #{}占位符 尽量使用占位符来解决问题 --><!-- ${}字符串拼接 容易产生SQL注入问题 --><select id="selectUserByName" parameterType="String"resultType="pers.goodwin.mybatis.bean.User"><!-- select * from t_user where u_username like '%${value}%' -->select * from t_user where u_username like "%"#{id}"%"</select><!-- 添加用户 --><insert id="insertUser"parameterType="pers.goodwin.mybatis.bean.User">insert into t_user values (null, #{u_username}, #{u_password}, #{u_gender},#{u_cid})</insert><update id="updateUser"parameterType="pers.goodwin.mybatis.bean.User">update t_user set u_username = #{u_username} where u_id = #{u_id}</update><delete id="deleteUserById" parameterType="Integer">delete from t_user where u_id = #{id}</delete><select id="selectUserByGenderAndCid" parameterType="user" resultType="user">SELECT *FROM t_user<where><if test="u_gender != null">u_gender = #{u_gender}</if><if test="u_cid != null">AND u_cid = #{u_cid}</if></where></select><select id="selectUserByGenderOrCid" parameterType="user" resultType="user">SELECT *FROM t_userWHERE 1=1<choose><when test="u_gender != null">AND u_gender = #{u_gender}</when><when test="u_cid != null">AND u_cid = #{u_cid}</when><otherwise></otherwise></choose></select><update id="updateUserIfNecessary" parameterType="user">UPDATE t_user<set><if test="u_username != null">u_username=#{u_username},</if><if test="u_password != null">u_password=#{u_password}</if></set>where u_id=#{u_id}</update><select id="selectCidIn" resultType="user">SELECT *FROM t_userWHERE u_cidIN<foreach item="item" index="index" collection="list" open="(" separator="," close=")">#{item}</foreach></select><select id="selectNameLike" resultType="user"><bind name="pattern" value="'%' + u_username + '%'" />select * from t_user where u_username like #{pattern}</select></mapper>
Mybatis学习笔记_5、Mybatis动态SQL相关推荐
- mybatis学习笔记四(动态sql)
直接贴图,注解在代码上,其他的配置文件在学习一中就不贴了 1 数据库 2 实体类 package com.home.entity;/*** 此类是: 用户实体类* @author hpc* @2017 ...
- MyBatis学习 之 三、动态SQL语句
2019独角兽企业重金招聘Python工程师标准>>> 有些时候,sql语句where条件中,需要一些安全判断,例如按某一条件查询时如果传入的参数是空,此时查询出的结果很可能是空的, ...
- 【最全Mybatis学习笔记(导入mybatis相关jar包)】
目录 1. 什么是Mybatis 2. 如何引入Mybatis? 3.编写Mybatis工具类 4. 万能Map 5. 模糊查询怎么写? 6. 作用域(Scope)和生命周期SqlSessionFac ...
- xml模糊查询语句_2Mybatis学习笔记07:动态SQL语句(原创,转载请注明来源)
开发环境: 硬件环境:Windows10+JDK 1.8: 软件环境:Java+Eclipse+Mybatis+maven3.6+tomcat8.0+Postgresql 10.6: 用到的jar包: ...
- Mybatis学习笔记(一) —— mybatis介绍
一.Mybatis介绍 MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名 ...
- 【Mybatis学习笔记】Mapper动态代理四项原则和注意事项
如果使用原始的DAO,要自己对其进行实现,而如果使用Mybatis的Mapper动态代理,就可以让Mybatis自动帮你实现DAO接口. Mapper动态代理的四项原则 1.接口方法名需要与Mappe ...
- mybatis 学习笔记:mybatis 初认识
简介 MyBatis是一个Java持久层框架,它通过XML描述符或注解把对象与存储过程或SQL语句关联起来.mybatis 可以将 preparedStatement 中的输入参数自动进行映射,将查询 ...
- MyBatis学习笔记(一)——MyBatis快速入门
转自孤傲苍狼的博客:http://www.cnblogs.com/xdp-gacl/p/4261895.html 一.Mybatis介绍 MyBatis是一个支持普通SQL查询,存储过程和高级映射的优 ...
- MyBatis:学习笔记(4)——动态SQL
MyBatis:学习笔记(4)--动态SQL 转载于:https://www.cnblogs.com/MrSaver/p/7453949.html
最新文章
- java任何表达式都可以当作语句_在Java语言中语句用分号终止,并不是所有的表达式都可以构成语句...
- 国内是否可以安装alexa_Alexa可以听到您无法听到的命令,哪些黑客可以利用
- *【CodeForces - 122C 】Lucky Sum (bfs记录状态,二分查找,有坑)(或分块)
- Vue笔记-Ant Design Vue构建前端连接后端WebSocket
- [ES6] 细化ES6之 -- 块级作用域
- antdesign 柱状图_ant design pro (十)advanced 图表
- 目标检测——Anchor-Based算法的学习笔记
- Script:Diagnostic Resource Manager
- TP-LINK无线上网短信Wifi认证配置流程
- 恒生ufx接口转变成CTP接口
- 如何制作macOS Big Sur 系统启动U盘
- Linux内核4.4 init,linux4.4内核启动到INIT: version 2.88 booting 卡住
- 停车位检测方法研究综述
- win10自动更新导致显卡驱动出问题,No AMD Graphics driver is installed or.......的解决方案
- selenium的工作原理
- 百度地图api实现轨迹运动效果
- android微信支付吊不起微信,安卓系统微信支付失败原因
- python实现去重_Python列表去重的4种实现方法
- 三万字速通JavaScript
- 头肩模拟器在免提或头戴式终端测试中的应用
热门文章
- LWIP协议与TCP/IP
- Android 架构之长连接技术
- 387. 字符串中的第一个唯一字符(javascript)387. First Unique Character in a String
- Java里面的同步和异步
- STM32之ADC的理解及运用
- java代理模式解析
- 【5G系列】MICO学习总结(2)
- 什么是Openflow?
- C语言中的%d、%u、%p、%f、%lu...
- php毕业论文选题系统,php毕业论文选题管理系统