MyBatis(随笔: 动态SQL映射文件)

动态SQL

我们可以用mybatis执行sql的形式来对数据的表进行增删改查操作,不过遇到比较复杂的业务需要写复杂的sql时(比如说sql的条件不确定,可能有一个条件或者多个),
我们就需要动态sql来提高sql的灵活性。

  • 基于OGNL表达式
  • 完成多条件查询等逻辑实现
  • 用于实现动态SQL的元素主要有
    if , trim , where , set , choose(when、otherwise), foreach ;

示例代码 : Demo.

查询用户表, 跟名称 密码 地址做多条件查询

Java接口 UserMapper.java

	//动态Sql
	//	1. if where trim 
	//	查询用户表, 跟名称 密码 地址做多条件查询
	//如果参数过多可以使用 Map;
	public List<User> cha(@Param("name")String name,@Param("pwd")String pwd,@Param("address")String address);  

映射文件:UserMapper.XML
if 完成多条件查询

		
		 <select id="cha" resultType="User" >
			SELECT * FROM `smbms_user` WHERE 1=1   
			
			<if test="name!=null and name!='' " >   			
				AND userName LIKE CONCAT('%',#{name},'%')
			if>
			<if test="pwd!=null and pwd!='' " >
				 AND userPassword LIKE CONCAT('%',#{pwd},'%')
			if>
			<if test="address!=null and address!='' " >
				AND address LIKE CONCAT('%',#{address},'%')
			if>
		select>
		
		

where 完成多条件查询

		
		<select id="cha" resultType="User"  >
			SELECT * FROM `smbms_user` 
			<where>
				<if test="name!=null and name!='' " >   			
					AND userName LIKE CONCAT('%',#{name},'%')
				if>
				<if test="pwd!=null and pwd!='' " >
					 AND userPassword LIKE CONCAT('%',#{pwd},'%')
				if>
				<if test="address!=null and address!='' " >
					AND address LIKE CONCAT('%',#{address},'%')
				if>
			where>
		select> 
		

trim 完成多条件查询

		
		<select id="cha" resultType="User" >
			SELECT * FROM `smbms_user` 
			<trim prefix="where" prefixOverrides="and|or" > 
				<if test="name!=null and name!='' " >   			
					AND userName LIKE CONCAT('%',#{name},'%')
				if>
				<if test="pwd!=null and pwd!='' " >
					 AND userPassword LIKE CONCAT('%',#{pwd},'%')
				if>
				<if test="address!=null and address!='' " >
					AND address LIKE CONCAT('%',#{address},'%')
				if>
			trim>
		select> 
		

修改用户表 使用if set trim

Java接口 UserMapper.java

	//2.修改用户表 使用if set frim
	public int upd(User u);

映射文件:UserMapper.XML
set 完成修改

		<update id="upd" parameterType="User" >
			UPDATE `smbms_user` 
			<set>  
				<if test="userName!=null and userName!='' " > `userName` =#{userName},  if>
				<if test="userPassword!=null and userPassword!='' " > `userPassword`=#{userPassword},  if>
			set> 
			where id= #{id} 
		update> -->
		

trim 完成修改

<update id="upd" parameterType="User">
			UPDATE `smbms_user`
			<trim prefix="set" suffix="where id = #{id}" suffixOverrides=",">
				<if test="userName!=null and userName!='' " > `userName` =#{userName},  if>
				<if test="userPassword!=null and userPassword!='' " > `userPassword`=#{userPassword},  if>
			trim>
		update>

in查询用户表, 使用foreach 完成部门查询;

Java接口 UserMapper.java

//	3.in查询用户表, 使用foreach 完成部门查询;	
	public List<User> chain(List<Integer> userRoles);

映射文件:UserMapper.XML


		<select id="chain" parameterType="java.util.List" resultType="User"  >
			SELECT * FROM `smbms_user` WHERE `userRole` IN 
			<foreach collection="list" item="W" open="(" close=")" separator="," >
				#{W}
			foreach>
		select>
		

对于某些查询需求,虽然有多个查询条件,但我们不想应用所有的条件,只选择其中一种查询结果时候可以使用:Choose;

Java接口 UserMapper.java

 	//5.对于某些查询需求,虽然有多个查询条件,但我们不想应用所有的条件,只选择其中一种查询结果时候可以使用:Choose;
	//用户名模糊查询 | 密码模糊查询 都不符合则查全部;
	public List<User> choose(@Param("name")String name,@Param("pwd")String pwd);

映射文件:UserMapper.XML

	
		
		<select id="choose" resultType="User" >
			SELECT * FROM `smbms_user` 
			<where>
				<choose>
					<when test="name!=null and name!='' ">
						AND userName LIKE CONCAT('%',#{name},'%')
					when>
					<when test="pwd!=null and pwd!=''  ">
						 AND userPassword LIKE CONCAT('%',#{pwd},'%')
					when>
					<otherwise>
						and 1=1
					otherwise>
				choose>
			where>
		select>
		

运行类 DTSqlRun .Java

package com.wsm.run;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import org.apache.ibatis.session.SqlSession;

import com.wsm.mapper.UserMapper;
import com.wsm.pojo.User;
import com.wsm.utis.MyBatisUtil;

public class DTSqlRun {
	static Scanner input = new Scanner(System.in);
	public static void main(String[] args) {
		DTSqlRun r = new DTSqlRun();
		//r.cha();
		//r.upd();
		//r.chain();
		r.choose();
	}
	
	public void cha(){
		SqlSession session = MyBatisUtil.create();
		UserMapper um = session.getMapper(UserMapper.class);
		List<User> users = um.cha("w",null,"");  
		if(users.size()==0){
			System.out.println("没有数据!");
		}
		for (User user : users) {
			System.out.println(user.getId() + "\t" + user.getUserCode() + "\t" + user.getUserName() + "\t" + user.getPhone()
					+ "\t" + user.getAddress());
		}
		MyBatisUtil.close(session);
	}
	
	public void upd(){
		User u = new User();
		//u.setUserName("asdsasad");
		u.setUserPassword("xxasssssda");
		u.setId(1);
		
		SqlSession session = MyBatisUtil.create();
		UserMapper um = session.getMapper(UserMapper.class);
		if(um.upd(u)==1){
			session.commit();  //手动提交;
			System.out.println("修改成功");
		}else{
			System.out.println("修改失败");
		}
		MyBatisUtil.close(session);
	}
	
	public void chain(){
		List<Integer> in = new ArrayList<Integer>();
		in.add(1);
		in.add(2);
		//in.add(3);
		SqlSession session = MyBatisUtil.create();
		UserMapper um = session.getMapper(UserMapper.class);
		
		List<User> users = um.chain(in);
		if(users.size()==0){
			System.out.println("没有数据!");
		}
		for (User user : users) {
			System.out.println(user.getId() + "\t" + user.getUserCode() + "\t" + user.getUserName() + "\t" + user.getPhone()
					+ "\t" + user.getAddress()+"\t"+user.getUserRole());
		}
		MyBatisUtil.close(session);
	}
	
	public void choose(){
		SqlSession session = MyBatisUtil.create();
		UserMapper um = session.getMapper(UserMapper.class);
		List<User> users = um.choose("s","ss");   //两个参数都传了,但pwd的属性无效,因为name 成立了  就结束了;  
		if(users.size()==0){
			System.out.println("没有数据!");
		}
		for (User user : users) {
			System.out.println(user.getId() + "\t" + user.getUserCode() + "\t" + user.getUserName() + "\t" + user.getPhone()
					+ "\t" + user.getAddress());
		}
		MyBatisUtil.close(session);
		
	}
	
	
}

MyBatis缓存

正如大多数框架一样,MyBatis提供了一级缓存二级缓存
一级缓存
一级缓存是基于,PerpetyalCache(MyBatis 自带的), HashMap本地缓存,作用范围在 SqlSession域内. 当SqlSession关闭时,则其所有的缓存就会被清空…
二级缓存
二级缓存就是 global caching 它超出 sqlsession 范围之外, 结果可以被所有的sqlSession 共享;
开启它只需要在MyBatis 的核心配置文件( MyBatis-config.xml ) setting 中设置…
二级缓存的配置:
1.需要在MyBatis-config.xml中配置

<settings>
		
		<setting name="logImpl" value="LOG4J" />
		
		<setting name="autoMappingBehavior" value="FULL" />
		
		<setting name="cacheEnabled" value="true"/>
	settings>

2.在对应的Mapper.xml 文件中设置缓存,默认是没有开启缓存的;
需要注意的是:global caching 作用域针对的是 mapper 的 namespace 而言的,即只有在此 namepace 内的查询才可以共享这个 cache…

<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/> 
	

3.在 mapper 文件配置支持 cache 后, 如果需要对个别查询进行调整,可以单独设置 cache 代码
这样就不需要在配置 Cache了… 方法2 和 方法3可以选一种...


<select id="cha" resultMap="RoleMap" useCache="true" >
	...
select>

示例demo

//根据编号查部门及 部门员工;
	public void cha(){
		SqlSession session = MyBatisUtil.create();
		RoleMapper rm = session.getMapper(RoleMapper.class);
		//一级缓存:缓存数据存储在 sqlSession中;
		Role r = rm.cha(2);
		System.out.println(r.getRoleName()+"\t"+r.getId());
		List<User> u = r.getUsers();
		for (User user : u) {
			System.out.println(user.getUserName());
		}
		//因此不关闭 sqlSession 在此查相同的数据不会在需要sql语句; 访问数据库;
		System.out.println("------------------------------------------");
		Role r1 = rm.cha(2);
		System.out.println(r1.getRoleName()+"\t"+r1.getId());
		
		//而查询没有查过的数据还是需要sql 访问数据库
		System.out.println("------------------------------------------");
		Role r2 = rm.cha(3);
		System.out.println(r2.getRoleName()+"\t"+r2.getId());
		MyBatisUtil.close(session);  //关闭SqlSession 
		
		
		
		System.out.println("二级缓存");
		//二级缓存: 数据存储在 sqlSessionFactory工厂中;
		//需要在配置信息中设置
		//MyBatis: 
		//xxxMapper.xml中: 
		//而查询时: