动态SQL中本章只讲if/foreach
- mybatis的动态sql语句是基于OGNL表达式的。可以方便的在sql语句中实现某些逻辑. 总体说来mybatis动态SQL语句主要有以下几类:
- if 语句 (简单的条件判断)
- choose (when,otherwize) ,相当于java 语言中的 switch ,与 jstl 中的choose 很类似
- trim (对包含的内容加上 prefix,或者 suffix 等,前缀,后缀)
- where (主要是用来简化sql语句中where条件判断的,能智能的处理 and or ,不必担心多余导致语法错误)
- set (主要用于更新时)
- foreach (在实现 mybatis in 语句查询时特别有用)
Mybatis中模糊查询的各种写法
#{exp}/${exp}
#与$
的区别
前提:参数类型为字符串,#会在前后加单引号[’],$则直接插入值
- sql中字符串拼接(推荐)
SELECT * FROM tableName WHERE name LIKE CONCAT(CONCAT('%', #{text}), '%');
注:CONCAT是mysql数据库中才有的
SELECT * FROM tableName WHERE name LIKE like '%'+#{bookName}+'%';
注:sqlserver中的写法 - 使用
${...}
代替 #{…}
SELECT * FROM tableName WHERE name LIKE '%${text}%';
#与$
的区别
前提:参数类型为字符串,#会在前后加单引号[’],$则直接插入值 - 程序中拼接
String searchText = “%” + text + “%”; - 大小写匹配查询
SELECT * FROM TABLENAME WHERE UPPER(SUBSYSTEM) LIKE '%' || UPPER('jz') || '%' 或者 SELECT * FROM TABLENAME WHERE LOWER(SUBSYSTEM) LIKE '%' || LOWER('jz') || '%'
注1:sql模糊查询中小于符号“<”报错,< >(>) <(<) &(&) 空格( )
注2:为防止SQL注入,一定要使用#进入赋值。什么是SQL注入参考附录一
- mybatis中返回List集合
- 定义结果集
<!--为了简化开发,类名使用了别名-->
<resultMap type="Book" id="bookList">
<id property="bookId" column="book_id" />
<result property="bookName" column="book_name" />
<result property="bookPrice" column="book_price" />
<result property="bookBrief" column="book_brief" />
</resultMap>
- 指定结果集
<select id="list" resultMap="bookList" parameterType="Book">
select book_id, book_name, book_price, book_brief
from t_book where 1=1
</select>
- 为什么要重写mybatis的分页
Mybatis的分页功能很弱,它是基于内存的分页(查出所有记录再按偏移量offset和边界limit取结果),在大数据量的情况下这样的分页基本上是没有用的
selectList(String statement, Object parameter, RowBounds rowBounds)
使用pagehelper插件分页
- 导入分页插件
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.2</version>
</dependency>
- 将pagehelper插件配置到mybatis中
<!-- 配置分页插件PageHelper, 4.0.0以后的版本支持自动识别使用的数据库 -->
<plugin interceptor="com.github.pagehelper.PageInterceptor">
</plugin>
- 在你需要进行分页的Mybatis方法前调用PageHelper.startPage静态方法即可,紧跟在这个方法后的第一个Mybatis查询方法会被进行分页
//设置分页处理
if (null != pageBean && pageBean.isPaginate()) {
PageHelper.startPage(pageBean.getPage(), pageBean.getRows());
}
- 获取分页信息(二种方式)
- 使用插件后,查询实际返回的是
Page<E>
,而非List<E>
,Page继承了ArrayList,同时还包含分页相关的信息
Page<Book> page = (Page<Book>)list;
System.out.println("页码:" + page.getPageNum());
System.out.println("页大小:" + page.getPageSize());
System.out.println("总记录:" + page.getTotal());
- 使用PageInfo
PageInfo pageInfo = new PageInfo(list);
System.out.println("页码:" + pageInfo.getPageNum());
System.out.println("页大小:" + pageInfo.getPageSize());
System.out.println("总记录:" + pageInfo.getTotal());
如何数据库的数据并发问题
- 通过version字段解决并发问题
throw new RuntimeException("对象已过期(ObjectExpired)或不存在(Object Not Found)")
update t_book set book_price = #{bookPrice},version=version+1
where book_id=#{bookId} and version=#vsersion#
附录
- 以 MySQL 为例,如何进行 SQL 注入和防止被注入?
MySQL为例,现在项目大部分都用框架实现,比如MyBatis框架,轻量级,功能强大:
在MyBatis中,如果写$
{变量名},则为直接把传入的值填充到SQL语句中;
如果写#{变量名},则为传入的值只能作为值,放到SQL语句中。
举例:
DELETE FROM student WHERE name=${stu_name}
如果这样写,假如用户恶意传入这样一个字符串:abc OR 1=1,
那么整个SQL就变成了
DELETE FROM student WHERE name=abc OR 1=1,
结果就是全部数据都删掉了。这就是SQL注入,如果把${stu_name}换成#{stu_name},那么依然传入上面的字符串,
那么SQL是这样的:
DELETE FROM student WHERE name=abc OR 1=1
,会删除名字为abc OR 1=1的学生,没有这个学生则什么都删除不掉,这样就防止了SQL注入。