mybatis 动态sql与OGNL表达式

 
(了解)OGNL( Object Graph Navigation Language )对象图导航语言,这是一种强大的
表达式语言,通过它可以非常方便的来操作对象属性。 类似于我们的EL,SpEL等
访问对象属性: person.name
调用方法: person.getName()
调用静态属性/方法: @java.lang.Math@PI
@java.util.UUID@randomUUID()
调用构造方法: new com.atguigu.bean.Person(‘admin’).name
运算符: +,-*,/,%
逻辑运算符: in,not in,>,>=,<,<=,==,!=
注意:xml中特殊符号如”,>,<等这些都需要使用转义字符
类型 伪属性 伪属性对应的 Java 方法
List Set Map size isEmpty List/Set/Map.size(),List/Set/Map.isEmpty()
List Set iterator List.iterator() Set.iterator()
Map keys values Map.keySet() Map.values()
Iterator next hasNext Iterator.next() Iterator.hasNext()
 

MyBatis 采用功能强大的基于 OGNL 的表达式来简化操作。

if
choose (when, otherwise)
trim (where, set)
– foreach(难点)
– sql片段
 

if测试

if举例:

	<select id="getEmpsByConditionIf" resultType="com.bean.Employee">
		select * from tbl_employee
		<where>
		 	<if test="id!=null">
		 		id=#{id}
		 	</if>
		 	<if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
		 		and last_name like #{lastName}
		 	</if>
		 	<if test="email!=null and email.trim()!=&quot;&quot;">
		 		and email=#{email}
		 	</if> 
		 	<!-- ognl会进行字符串与数字的转换判断  "0"==0 -->
		 	<if test="gender==0 or gender==1">
		 	 	and gender=#{gender}
		 	</if>			
		</where>
	</select>

choose (when, otherwise)测试

chose举例:

	 <!-- public List<Employee> getEmpsByConditionChoose(Employee employee); -->
	 <select id="getEmpsByConditionChoose" resultType="com.bean.Employee">
	 	select * from tbl_employee 
	 	<where>
	 		<!-- 如果带了id就用id查,如果带了lastName就用lastName查;只会进入其中一个 -->
	 		<choose>
	 			<when test="id!=null">
	 				id=#{id}
	 			</when>
	 			<when test="lastName!=null">
	 				last_name like #{lastName}
	 			</when>
	 			<when test="email!=null">
	 				email = #{email}
	 			</when>
	 			<otherwise>
	 				gender = 0
	 			</otherwise>
	 		</choose>
	 	</where>
	 </select>

trim (where, set)测试

trim用来自定义字符串的截取规则 ,trim标签体中是整个字符串拼串后的结果。 

trim标签属性:
prefix=" "
前缀:prefix给拼串后的整个字符串加一个前缀 
prefixOverrides=" "
前缀覆盖: 去掉整个字符串前面多余的字符
suffix=" "

后缀:suffix给拼串后的整个字符串加一个后缀 
suffixOverrides=" "

后缀覆盖:去掉整个字符串后面多余的字符

trim举例:

	 <!--public List<Employee> getEmpsByConditionTrim(Employee employee);  -->
	 <select id="getEmpsByConditionTrim" resultType="com.bean.Employee">
	 	select * from tbl_employee
	 	<!-- 自定义字符串的截取规则 -->
	 	<trim prefix="where" suffixOverrides="and"> <!-- 将最后的and去掉 -->
	 		<if test="id!=null">
		 		id=#{id} and
		 	</if>
		 	<if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
		 		last_name like #{lastName} and
		 	</if>
		 	<if test="email!=null and email.trim()!=&quot;&quot;">
		 		email=#{email} and
		 	</if> 
		 	<!-- ognl会进行字符串与数字的转换判断  "0"==0 -->
		 	<if test="gender==0 or gender==1">
		 	 	gender=#{gender}
		 	</if>
		 </trim>
	 </select>

where(略):去掉开头,和set类似
set举例:

	 <!--public void updateEmp(Employee employee);  -->
	 <update id="updateEmpBySet">
	 	<!-- Set标签的使用 ,去除末尾的,-->
	 	update tbl_employee 
		<set>
			<if test="lastName!=null">
				last_name=#{lastName},
			</if>
			<if test="email!=null">
				email=#{email},
			</if>
			<if test="gender!=null">
				gender=#{gender},
			</if>
		</set>
		where id=#{id} 
	</update>	

set也可由trim代替后的代码 举例:

 	<update id="updateEmpByTrim">		
		<trim prefix="set" suffixOverrides=",">
			<if test="lastName!=null">
				last_name=#{lastName},
			</if>
			<if test="email!=null">
				email=#{email},
			</if>
			<if test="gender!=null">
				gender=#{gender}
			</if>
		</trim>
		where id=#{id}
	 </update>	

foreach(难点):

foreach标签相关属性介绍:

collection:指定要遍历的集合(底层是map实现的,因此此集合为map的value)
也可以利用注解:list类型的参数会特殊处理封装在map中,map的key就叫list的名字(自动)

item:将当前遍历出的元素赋值给指定的变量名称

separator:每个元素之间的分隔符

open:遍历出所有结果拼接一个开始的字符

close:遍历出所有结果拼接一个结束的字符

 index:索引。遍历list的时候是index就是索引,item就是当前值遍历map的时候index表示的就是map的key,item就是map的值
             

利用底层传入map集合:

Dao层:
//foreach利用map
public List<Employee> getEmpsByConditionForeachByMap(Map<String, List<Integer>> ids);	


测试:
//查询操作(foreach 传入map)
	@Test
	public void test07() throws IOException{
		SqlSessionFactory sqlSessionFactory=getSqlSessionFactory();
		SqlSession openSession=sqlSessionFactory.openSession();
		EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);		
		Map<String, List<Integer>> map=new HashMap<String, List<Integer>>();
		List<Integer> ids=new ArrayList<>();
		ids.add(17);
		ids.add(18);
		map.put("ids", ids);
		List<Employee> emps=mapper.getEmpsByConditionForeachByMap(map);
		for (Employee emp : emps) {
			System.out.println(emp);
		}
	}
<!--public List<Employee> getEmpsByConditionForeachByMap(Map<String, List<Integer>> ids);  -->
<select id="getEmpsByConditionForeachByMap" resultType="com.bean.Employee">
	 select * from tbl_employee
	 <foreach collection="ids"  item="item_id" separator=","
	 	open="where id in(" close=")">
	 	#{item_id}
	 </foreach>
</select>

利用注解传入list集合

Dao层:
//foreach传入list,利用注解@Param作为map的key
public List<Employee> getEmpsByConditionForeachByList(@Param("ids") List<Integer> ids);

测试:
//查询操作(foreach 传入list)
	@Test
	public void test08() throws IOException{
		SqlSessionFactory sqlSessionFactory=getSqlSessionFactory();
		SqlSession openSession=sqlSessionFactory.openSession();
		EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
		List<Integer> ids=new ArrayList<>();
		ids.add(17);
		ids.add(18);
		List<Employee> emps=mapper.getEmpsByConditionForeachByList(ids);
		for (Employee emp : emps) {
			System.out.println(emp);
		}
	}	
	 <!--public List<Employee> getEmpsByConditionForeach(@Param("ids") List<Integer> ids);  -->
	 <select id="getEmpsByConditionForeachByList" resultType="com.bean.Employee">
	 	select * from tbl_employee
	 	<foreach collection="ids"  item="item_id" separator=","
	 		open="where id in(" close=")">
	 		#{item_id}
	 	</foreach>
	 </select>

 

讨论foreach的批量添加操作:

方法一:执行一次sql语句

	 <!--public void addEmps(@Param("emps") List<Employee2> emps); -->
	 <insert id="addEmps">
	 	insert into tbl_employee(last_name,email,gender,d_id) 
		values
		<foreach collection="emps" item="emp" separator=",">
			(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
		</foreach>
	 </insert>

方法二:执行多次sql语句,用分号" ; "分割

	 <!-- 方法二:不推荐 -->
	 <insert id="addEmps2">
		<foreach collection="emps" item="emp" separator=";">
		insert into tbl_employee(last_name,email,gender,d_id) 
		values(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
		</foreach>
	 </insert>	

注意:方法二必须添加jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true,才能正常运行(支持分号分割)

上述两种方法都执行以下测试用例:

	//批量添加(foreach)
	@Test
	public void test09() throws IOException{
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		try{
			EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
			List<Employee2> emps = new ArrayList<>();
			emps.add(new Employee2(null, "smith0x1", "smith0x1@atguigu.com", "1",new Department(1)));
			emps.add(new Employee2(null, "allen0x1", "allen0x1@atguigu.com", "0",new Department(1)));
			mapper.addEmps(emps);
			openSession.commit();
		}finally{
			openSession.close();
		}
	}

Sql片段:

sql标签作用:抽取可重用的sql片段。方便后面引用  
sql抽取范围:经常将要查询的列名,或者插入用的列名抽取出来方便引用

sql标签相关属性: 

include来引用已经抽取的sql片段。

include还可以自定义一些property 变量,sql标签内部就能使用自定义的属性

sql片段取出include中的property值正确方式${prop},

	<insert id="addEmps3">
	 	insert into tbl_employee(
	 		<include refid="insertColumn">
	 			<property name="test" value="d_id"/>
	 		</include>
	 	) 
	 	values
		<foreach collection="emps" item="emp" separator=",">
			(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
		</foreach>
	 </insert> 

 分析:<insert>标签中嵌套了 <include>标签用来引入sql片段,并且定义了<porperty name=“ ”>标签的name属性名称和值,供sql片段使用,例如下面的${test}使用<include>标签定义的property值。

	  <sql id="insertColumn">
	  	<if test="_databaseId=='oracle'">
	  		employee_id,last_name,email
	  	</if>
	  	<if test="_databaseId=='mysql'">
	  		<!-- last_name,email,gender,d_id -->
	  		last_name,email,gender,${test} //${test}使用<include>标签定义的值
	  	</if>
	  </sql>

 

补充:

1)bind 元素可以从 OGNL 表达式中创建一个变量并 将其绑定到上下文。比如:
模糊查询传入:lastName

	 <!-- 测试bind -->
	 <!--	public List<Employee> getEmpsTestBind(Employee employee);  -->
	  <select id="getEmpsTestBind" resultType="com.bean.Employee">
	  		<!-- bind:可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值 -->
	  		<!-- bind过程:将取得值拼接成value,在赋值给name -->
	  		<bind name="_lastName" value="'%'+lastName+'%'"/>
	  		select * from tbl_employee where last_name like #{_lastName}
	  </select>

 2)mybatis内置参数

不只是方法传递过来的参数可以被用来判断,取值。
mybatis默认还有两个内置参数:

_parameter:代表整个参数
单个参数:_parameter就是这个参数。例如:javabean对象属性--->_parameter.属性名
多个参数:参数会被封装为一个map;_parameter就是代表这个map。

_databaseId:如果配置了databaseIdProvider标签,databaseId就是代表当前数据库的别名oracle

	 <!-- 测试两个内置参数 -->
	 <!--public List<Employee> getEmpsTestInnerParameter(Employee employee);  -->
	  <select id="getEmpsTestInnerParameter" resultType="com.atguigu.mybatis.bean.Employee">
	  		<if test="_databaseId=='mysql'">
	  			select * from tbl_employee
	  			<if test="_parameter!=null">
	  				where last_name like #{lastName}
	  			</if>
	  		</if>
	  		<if test="_databaseId=='oracle'">
	  			select * from employees
	  			<if test="_parameter!=null">
	  				where last_name like #{_parameter.lastName}
	  			</if>
	  		</if>
	  </select> 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值