Wrapper的用途

Wrapper是SQL语句where条件的组装工具类,可灵活的组装where条件,完成复杂的查询。

特性

  1. 支持写括号来确定多个条件的运算优先级。例如:
    1. where (name='abc' and age=18) or (addr='北京')
    2. where a= 301 and b= 301 and (d= 100 or e= 90 or f= 80) and (g= 70 or h= 60 or i = 50 )

  2. 支持的条件关键字:where、and、or、group by、having、order by desc asc、distinct
  3. 支持的运算符:=、<>、is null、is not null、>、>=、<、<=、like %?%、like _?_、in、not in、between、not between、exists、not exists
  4. 支持:distinct、orderBy

占位符

Wrapper的占位符有两种,基本写法是{0}{1},花括号中放数值。

  1. 分为显式占位符。 wrapper.and("category_id = {0}",1)
  2. 隐式占位符两种。  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 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();