赞
踩
生成SQL语句具有灵活性:动态SQL允许根据不同的条件来生成不同的SQL语句,从而实现动态查询和更新操作。这样我们可以根据项目框架需求灵活地构造所需的SQL语句,避免了不需要硬编码的情况出现。
使SQL语句清晰易懂(可读性):使用动态SQL可以使SQL语句更加清晰易读。通过使用内置携带的函数与标签,根据条件组织SQL语句的不同部分,从而避免大量的SQL嵌套与重复。它使SQL语句更加直观,更有利于开发人员理解及维护。
具有较强的扩展性:动态SQL提供了一种扩展SQL语句的方式,允许我们根据需求加、修改或删除查询条件。这种扩展性使得我们能够轻松地改变和优化SQL语句,而不需要修改大量的固定SQL代码。这样大大减少了开发使用的时间,提高了开发效率及后期的维护效率。
性能优化:通过使用动态SQL,我们可以根据不同的条件动态生成SQL语句,从而避免不必要的查询或更新操作。例如,我们可以根据用户的选择动态生成查询条件, 只查询真正需要的数据,减少了不必要的数据库操作,提高了系统性能。
元素 | 作用 | 备注 |
---|---|---|
if | 判断语句 | 单条件分支判断 |
choose、when、otherwise> | 相当于Java中的Switch case语句 | 多条件分支判断 |
trim | 辅助元素 | 用于去除或补齐SQL语句片段的开头和结尾的空格,可以用于拼接包含可选条件的SQL语句。 |
where | 辅助元素 | 用于拼接WHERE子句,自动处理WHERE关键字和添加适当的AND或OR连接条件。 |
set | 辅助元素 | 用于拼接UPDATE语句的SET子句,自动处理SET关键字和添加适当的逗号分隔更新字段。 |
foreach | 循环语句 | 在in语句等列举条件中较常用 |
bind | 辅助元素 | 拼接参数 |
sql | 定义一个通用功能 | 常用include结合使用 |
函数 | 函数说明 |
---|---|
trim() | 去除字符串的开头或结尾指定字符(默认为空格)。 例子:<trim prefixOverrides="AND |
concat() | 拼接多个字符串。 例子:${param1} + ’ ’ + ${param2} |
substring() | 截取字符串的一部分。 例子:SUBSTRING(column_name, start_index, length) |
lower() | 将字符串转换为小写。 例子:LOWER(column_name) |
upper() | 将字符串转换为大写。 例子:UPPER(column_name) |
replace() | 替换字符串中的某个字符或字符串。 例子:REPLACE(column_name, old_string, new_string) |
length() | 获取字符串的长度。 例子:LENGTH(column_name) |
now() | 获取当前时间。 例子:NOW() |
date_format() | 格式化日期。 例子:DATE_FORMAT(column_name, pattern) |
应用场景 | 说明 |
---|---|
条件查询 | 当需要根据不同的条件进行查询时,可以使用动态SQL来根据条件动态拼接WHERE子句。比如在一个用户管理系统中,可以根据用户的姓名、性别、年龄等条件来进行灵活的查询。 |
动态排序 | 当需要根据不同的字段进行排序时,可以使用动态SQL来动态生成ORDER BY子句。比如在一个商品列表中,用户可以选择按照价格、销量等字段进行排序。 |
动态更新 | 当需要根据不同的条件来进行更新操作时,可以使用动态SQL来根据条件动态生成UPDATE语句。比如在一个订单系统中,可以根据订单状态、支付状态等条件来更新订单信息。 |
动态插入 | 当需要根据不同的条件来进行插入操作时,可以使用动态SQL来根据条件动态生成INSERT语句。比如在一个用户注册系统中,可以根据用户的选择来插入不同的用户信息。 |
复杂逻辑处理 | 当需要根据复杂的业务逻辑来生成SQL语句时,可以使用动态SQL来处理复杂的逻辑判断和条件拼接。比如在一个电商系统中,根据不同的促销活动和用户等级来生成不同的优惠查询条件。 |
批量操作 | 当需要对多个对象进行批量操作时,可以使用动态SQL来生成批量操作的SQL语句。比如批量插入多个用户数据或批量删除多个订单数据。 |
使用OGNL从SQL参数对象中计算表达式的值,根据表达式的值动态拼接SQL,以此来完成动态SQL的功能。
对象person:{id:10,age:18,name:小明}; 若上下文(环境)的对象是person,通过#{ } 可以直接获取到对象的属性值
#{id} 相当于 perosn.getId()
#{age} 相当于 person.getAge()
#{name} 相当于 person.getName()
#{} 的实际作用:现在转成?的占位符,然后再把值设置进去
<!-- 映射文件 --->
<select id="login" resultType="Client">
select id, username, password from client where username = #{username} and password = #{password} ;
</select>
<!-- #{} 的实际作用:现在转成?的占位符,然后再把值设置进去【假设外界传入的值username="小明",password="1"】 -->
select id, username, password from client where username = ? and password = ?;
PreparedStatement.setString(1, "小明");
PreparedStatement.setString(2,"1");
${} 的实际作用:直接把值设置进去。(可能会出现sql注入安全问题,比较不安全)
<!-- 映射文件 --->
<select id="login" resultType="Client">
select id, username, password from client where username = ${username} and password = ${password} ;
</select>
<!-- ${} 的实际作用:直接把值设置进去【假设外界传入的值username="小明",password="1"】 -->
select id, username, password from client where username = "小明" and password = "1";
mapper
List<User> getUserList(@Param("userName")String userName,
@Param("userRole")int userRole);
xml
<select id="getUserList" resultType="User">
SELECT * FROM SMBMS_USER
WHERE 1=1
<if test='userName!=null and userName!=""'>
AND USERCODE LIKE CONCAT('%',#{userName},'%')
</if>
<if test="userRole!=0">
AND USERROLE = #{userRole}
</if>
</select>
where标签会去掉第一个成立的if条件前面的and或者是or
<select id="getUserList" resultType="User">
SELECT * FROM SMBMS_USER
<where>
<if test='userName!=null and userName!=""'>
AND USERCODE LIKE CONCAT('%',#{userName},'%')
</if>
<if test="userRole!=0">
AND USERROLE = #{userRole}
</if>
</where>
</select>
mapper
int updateUserById(User user);
xml
<update id="updateUserById" parameterType="User"> UPDATE SMBMS_USER <set> <if test='userName!=null and userName!=""'> userName = #{userName}, </if> <if test='userPassword!=null and userPassword!=""'> userPassword=#{userPassword}, </if> <if test='phone !=null and phone !=""'> phone=#{phone}, </if> <if test='address!=null and address!=""'> address=#{address}, </if> <if test='userRole!=0'> userRole=#{userRole}, </if> <if test='birthday!=null'> birthday=#{birthday} </if> </set> WHERE ID=#{id} </update>
<update id="updateUserById" parameterType="User"> UPDATE SMBMS_USER <trim prefix="set" suffixOverrides="," suffix="WHERE ID=#{id}"> <if test='userName!=null and userName!=""'> userName = #{userName}, </if> <if test='userPassword!=null and userPassword!=""'> userPassword=#{userPassword}, </if> <if test='phone !=null and phone !=""'> phone=#{phone}, </if> <if test='address!=null and address!=""'> address=#{address}, </if> <if test='userRole!=0'> userRole=#{userRole}, </if> <if test='birthday!=null'> birthday=#{birthday}, </if> </trim> </update>
迭代一个集合,批量查询、批量删除、批量添加等
批量查询上一章已经讲过了,可以看一下
批量查询相当于SQL中的select xx from table where colum in (v1,v2,v3)
要求:foreach 标签中的collection属性值等于array
mapper
List<User> getUserListByids(int[] ids);
xml
<select id="getUserListByids" resultType="User" parameterType="int">
SELECT * FROM SMBMS_USER WHERE ID IN
<foreach collection="array" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
要求:foreach 标签中的collection属性值等于list
List<User> getUserListByids(List<Integer> idList);
xml
<select id="getUserListByids" resultType="User" parameterType="int">
SELECT * FROM SMBMS_USER WHERE ID IN
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
要求:foreach 标签中的collection属性值等于Map中List集合的key
mapper
List<User> getUserListByMap(Map<String,Object> paramMap);
xml
<select id="getUserListByMap" parameterType="map" resultType="User">
SELECT * FROM SMBMS_USER WHERE GENDER = #{gender}
AND USERROLE IN
<foreach collection="idList" item="userRole" open="(" separator="," close=")">
#{userRole}
</foreach>
</select>
测试
@Test
public void getUserListByMap(){
SqlSession session = factory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
List<Integer> roleList = new ArrayList<Integer>();
Collections.addAll(roleList,2,4,6);
Map<String,Object> paramMap = new HashMap<String, Object>();
paramMap.put("idList",roleList);
paramMap.put("gender",1);
List<User> userList = userMapper.getUserListByMap(paramMap);
System.out.println(userList);
session.close();
}
mapper
int insertUserBatch(List<User> userList);
xml
<insert id="insertUserBatch" parameterType="User">
insert into smbms_user (userCode,UserName,UserPassword,birthday,userRole)
values
<foreach collection="list" item="user" separator=",">
(#{user.userCode},#{user.userName},#{user.userPassword},#{user.birthday},#{user.userRole})
</foreach>
</insert>
测试
@Test
public void insertUserBatch(){
SqlSession sqlSession = MybatisUtil.createSqlSession();
userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = new ArrayList<>();
User user1 = new User("A","aaa","123",new Date(),3);
User user2 = new User("B","bbb","123",new Date(),3);
User user3 = new User("C","ccc","123",new Date(),3);
User user4 = new User("D","ddd","123",new Date(),3);
Collections.addAll(userList,user1,user2,user3,user4);
int line = userMapper.insertUserBatch(userList);
System.out.println(line);
//sqlSession.commit();
MybatisUtil.close(sqlSession);
}
flag1修改姓名;flag2修改密码,flag==3修改手机号
mapper
int updateUserByFlag(String flag);
xml
没有传完整参数,直接在sql中写死了,其实可以根据传参修改对应的值
<update id="updateUserByFlag" parameterType="string">
UPDATE SMBMS_USER SET address='金水区',
<choose>
<when test='flag=="1"'>userName='dubbo'</when>
<when test='flag=="2"'>userPassword='123456'</when>
<when test='flag=="3"'>phone='13888888888'</when>
<otherwise>gender=2</otherwise>
</choose>
where id=60
</update>
在开发过程中会遇到许多相同的SQL,以查询功能为例,各功能要查询的参数都是一样,但是筛选条件不同,那么我们便可以将相同的部分抽取出来,用得时候直接引用即可,不用再写重复代码。
<sql id="all">
select * from smbms_user
</sql>
分页查询列表
<select id="getUserByUserNameAndUserRole" resultType="User">
<include refid="all"></include>
<where>
<if test="userRole!=0">
and userRole=#{userRole}
</if>
<if test="userName!=null and userName!=''">
and userName like concat('%',#{userName},'%')
<!--and userName like '%${userName}%'-->
</if>
</where>
limit #{start},#{pageSize}
</select>
查询详情
<select id="getUserById" resultType="User">
<include refid="all"></include>
where id=#{id}
</select>
bind 标签可以使用 OGNL 表达式创建一个变量井将其绑定到上下文中
<bind name = “需要绑定的变量” value = “绑定的最终值” />
select * from smbms_user where
userName like concat("%",#{userName},"%")
select * from smbms_user where
userName like concat("%",concat(#{userName},"%"))
因此,在Oracle迁移至MySQL时,会导致mybatis报错,我们可以使用bind标签直接兼容,如下:
select * from smbms_user where
<bind name="userName" value="'%'+userName+'%'" />
userNamelike #{userName} <!-- userName实际是bind标签中的value->
Mybatis的分页功能很弱,它是基于内存的分页(查询所有记录再按偏移量offset和边界limit取结果),在大数据量的情况下这样的分页基本上是没用的
xml
<select id="getUserByUserNameAndUserRole" resultType="User">
<include refid="all"></include>
limit #{start},#{pageSize}
</select>
测试
@Test
public void getUserByUserNameAndUserRole(){
SqlSession sqlSession = MybatisUtil.createSqlSession();
userMapper = sqlSession.getMapper(UserMapper.class);
int pageSize = 5;
int currentPage = 1;
int start = (currentPage-1)*pageSize;
List<User> userList = userMapper.getUserByUserNameAndUserRole(0,"孙",start,pageSize);
userList.forEach(System.out::println);
MybatisUtil.close(sqlSession);
}
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.2</version>
</dependency>
注意放的顺序
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
@Test
public void getUserByPage(){
SqlSession sqlSession = MybatisUtil.createSqlSession();
userMapper = sqlSession.getMapper(UserMapper.class);
PageHelper.offsetPage(15,3);//偏移量,页面大小
List<User> userList = userMapper.getUserByPage(0,null);
PageInfo<User> pageInfo = new PageInfo<>(userList);
System.out.println(pageInfo);
pageInfo.getList().forEach(System.out::println);
MybatisUtil.close(sqlSession);
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。