Wrapper的用途
Wrapper是SQL语句where条件的组装工具类,可灵活的组装where条件,完成复杂的查询。
特性
-
支持写括号来确定多个条件的运算优先级。例如:
- where (name='abc' and age=18) or (addr='北京')
-
where a= 301 and b= 301 and (d= 100 or e= 90 or f= 80) and (g= 70 or h= 60 or i = 50 )
- 支持的条件关键字:where、and、or、group by、having、order by desc asc、distinct
- 支持的运算符:=、<>、is null、is not null、>、>=、<、<=、like %?%、like _?_、in、not in、between、not between、exists、not exists
- 支持:distinct、orderBy
占位符
Wrapper的占位符有两种,基本写法是{0}{1},花括号中放数值。
- 分为显式占位符。 wrapper.and("category_id = {0}",1)
- 隐式占位符两种。 wrapper .and( "category_id =" ,1)
防止SQL注入
为了防止SQL注入,不可直接把参数拼到sql内,如:where name='张三',由于'张三'是互联网用户通过表单输入进入的会有SQL注入攻击的风险。
注意:强制要求参数要使用占位符来传递,隐式占位符也是占位符。下面有示例。
注意:groupBy\orderBy 子句的防止SQL注入工作由正则过滤器完成,你放心使用。
注意:由于安全原因不支持写子查询,select被定义为危险字符。
注意:由于安全原因不支持在sql中写带危险符号的函数,'单引号被定义为危险字符,如:to_date('2012-05-11','yyyy-mm-dd') 函数中有'单引号会被判定sql注入。不带'单引号的函数是可以使用的。下面有示例。
备注:危险符号: 包含 ' (单引号)、注释–和/**/、注释#、和 select|update|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute
其它
Wrapper 自带能力:distinct、orderBy。
分页page 要放在dao接口一级。 带有orderBy能力。
Wrapper的orderBy的优先级高于page的orderBy,同时只能使用一个orderBy。
占位符总结
Wrapper的占位符 {0}{1}
mybatis的占位符 #{
user.id
}
预处理语句的占位符 ?
最终都是基于jdbc PreparedStatement预编译sql的?占位符
简写
mybatis mapper xml 中对象的简写
Wrapper: w
entity: w.e
valueMap: w.v
输出的SQL: w.outputSqlWhere
输出的SQL: w.outputSqlOrderBy
Page: p
示例
各种运算符的示例,使用了隐式占位符
=、<>、is null、is not null、>、>=、<、<=、like %?%、like _?_、 * in、not in、between、not between
Wrapper wrapper = new Wrapper(); wrapper .and("category_id =",1)//=等于 .and("status <>",0) //<>不等于 .and("bak6 is null")//is null 是空 .or("bak7 is not null")//is not null 非空 .andNew("market_price >",0) //大于 .and("market_price >=",0) //大于等于 .and("weight <",100) //<>小于 .and("weight <=",200) //<>小于等于 .orNew("name like", "%手机%") //like .and("name like", "%手机")//左like .and("name like", "手机%")//右like .and("name like", "_手机") //like 单字符匹配 .orNew("status in",new int[]{1,2,3,4,5}) //in 包含 .and("status not in",Arrays.asList(-1, 0)) //not in 不包含 .orNew("market_price between",0,1000) //between 在范围内 .or("market_price not between",0,1) //not between 不在范围内 ; String sqlWhere=wrapper.getOutputSqlAll(); System.out.println("sqlWhere:"+sqlWhere); Map<String, Object> paramMap = wrapper.getValueMap(); System.out.print("占位符参数:"); for (String key : paramMap.keySet()) { Object value = paramMap.get(key); System.out.print(key + "=" + value+","); }
各种运算符的示例,使用了显式占位符
=、<>、is null、is not null、>、>=、<、<=、like %?%、like _?_、 * in、not in、between、not between
Wrapper wrapper = new Wrapper(); wrapper .and("category_id = {0}",1)//=等于 .and("status <> {0}",0) //<>不等于 .and("bak6 is null")//is null 是空 .or("bak7 is not null")//is not null 非空 .andNew("market_price > {0}",0) //大于 .and("market_price >= {0}",0) //大于等于 .and("weight < {0}",100) //<>小于 .and("weight <= {0}",200) //<>小于等于 .orNew("name like {0}", "%手机%") //like .and("name like {0}", "%手机")//左like .and("name like {0}", "手机%")//右like .and("name like {0}", "_手机") //like 单字符匹配 .orNew("status in {0}",new int[]{1,2,3,4,5}) //in 包含 .and("status not in {0}",Arrays.asList(-1, 0)) //not in 不包含 .orNew("market_price between {0} and {1}",0,1000) //between 在范围内 .or("market_price not between {0} and {1}",0,1) //not between 不在范围内 ; String sqlWhere=wrapper.getOutputSqlAll(); System.out.println("sqlWhere:"+sqlWhere); Map<String, Object> paramMap = wrapper.getValueMap(); System.out.print("占位符参数:"); for (String key : paramMap.keySet()) { Object value = paramMap.get(key); System.out.print(key + "=" + value+","); }
日期的查询、使用函数、like查询
Wrapper wrapper = new Wrapper(); wrapper .and("create_date between", new Date(1L),new Date()) //按日期查询,未使用占位符 .and("create_date between {0} and {1}", new Date(1L),new Date()) //按日期查询,使用占位符 .orNew("lower(name) like lower({0})", "%HuaWei%") //lower()函数,使用lower()把HuaWei转为小写 .or("lower(name) like", "%huawei%") //lower()函数,开发人员保证huawei是全小写的,与数据库中的值对比 ; String rs="AND (create_date between #{w.v[p0]} AND #{w.v[p1]} AND create_date between #{w.v[p2]} and #{w.v[p3]}) \n" + "OR (lower(name) like lower(#{w.v[p4]}) OR lower(name) like #{w.v[p5]})"; Assert.assertEquals(rs,wrapper.getOutputSqlAll());
多个 and or测试 ,用括号确定运算优先级
Wrapper wrapper = new Wrapper(); wrapper.and("p_id=", 301).or("name=", "1") .orNew("brand_id=", 100).and("util=", 20) .andNew("status=", 5) ; String sqlWhere=wrapper.getOutputSqlAll(); System.out.println("sqlWhere:"+sqlWhere); Map<String, Object> paramMap = wrapper.getValueMap(); System.out.print("占位符参数:"); for (String key : paramMap.keySet()) { Object value = paramMap.get(key); System.out.print(key + "=" + value+","); } System.out.println(); String target="AND (p_id= #{w.v[p0]} OR name= #{w.v[p1]}) \n"+ "OR (brand_id= #{w.v[p2]} AND util= #{w.v[p3]}) \n"+ "AND (status= #{w.v[p4]})"; Assert.assertEquals(target,sqlWhere);
order by使用示例
Wrapper wrapper = new Wrapper(); wrapper.and("name=","zhangsan").orderBy("id,name ASC"); wrapper.setDistinct(true); String sqlWhere=wrapper.getOutputSqlAll(); System.out.println("sqlWhere:"+sqlWhere); Map<String, Object> paramMap = wrapper.getValueMap(); System.out.print("占位符参数:"); for (String key : paramMap.keySet()) { Object value = paramMap.get(key); System.out.print(key + "=" + value+","); } System.out.println();
group By,having使用示例
Wrapper wrapper = new Wrapper(); wrapper.groupBy("brand_id,area").having("id =",22).and().having("password is not null"); String sqlWhere=wrapper.getOutputSqlAll(); System.out.println("sqlWhere:"+sqlWhere); Map<String, Object> paramMap = wrapper.getValueMap(); System.out.print("占位符参数:"); for (String key : paramMap.keySet()) { Object value = paramMap.get(key); System.out.print(key + "=" + value+","); } System.out.println();
exists 使用示例
Wrapper wrapper = new Wrapper(); wrapper.exists("select 1 form table where id=a.p_id"); String sqlWhere=wrapper.getOutputSqlAll(); System.out.println("sqlWhere:"+sqlWhere); Map<String, Object> paramMap = wrapper.getValueMap(); System.out.print("占位符参数:"); for (String key : paramMap.keySet()) { Object value = paramMap.get(key); System.out.print(key + "=" + value+","); } System.out.println();