mybatis(动态sql,MyBatis-缓存机制,spring+springmvc+mybatis整合)

上篇

动态sql

环境搭建

基本环境搭建以后(详细搭建环境建前篇)
建立相应的接口bao.EmployeeMapperDynamicSQL和映射文件/mybaits/wenjian/EmployeeMapperDynamicSQL.xml

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中特殊符号如”,>,<等这些都需要使用转义字符

访问集合伪属性:
在这里插入图片描述

if

在test中可用属性方法
在这里插入图片描述
例子:

//全局配置文件/mybaits/wenjian/mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties"></properties>
<settings>
		<!-- <setting name="mapUnderscoreToCamelCase" value="true"/> -->
		<setting name="jdbcTypeForNull" value="NULL"/>
		
		<!--显示的指定每个我们需要更改的配置的值,即使他是默认的。防止版本更新带来的问题  -->
		<setting name="lazyLoadingEnabled" value="true"/>
		<setting name="aggressiveLazyLoading" value="false"/>
	</settings>
<typeAliases>
<typeAlias type="bao.User" alias="emp"/>
</typeAliases>
<!--若是再别的包下,/ 分割 -->
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="${driver}" />
				<property name="url" value="${url}" />
				<property name="username" value="${username}" />
				<property name="password" value="${password}" />
			</dataSource>
		</environment>
	</environments>
	<!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中 -->
	<mappers>
	 <mapper resource="EmployeeMapperDynamicSQL.xml" />
	<mapper resource="EmployeeMapper.xml" />
 <mapper resource="DepartmentMapper.xml" />
	</mappers>
	
</configuration>
///////////////////////////////////////////////////////////////////////////
//bean User.java
package bao;
import org.apache.ibatis.type.Alias;
public class User {
private int username;
private String password;
private Department dpartment;

public Department getDpartment() {
	return dpartment;
}
public void setDpartment(Department dpartment) {
	this.dpartment = dpartment;
}

public String getPassword() {
	return password;
}
public void setPassword(String password) {
	this.password = password;
}

public int getUsername() {
	return username;
}
public void setUsername(int username) {
	this.username = username;
}
@Override
public String toString() {
	return "User [dpartment=" + dpartment + ", password=" + password
			+ ", username=" + username + "]";
}

public User() {
	super();
	// TODO Auto-generated constructor stub
}
public User(int username, String password, Department dpartment) {
	super();
	this.username = username;
	this.password = password;
	this.dpartment = dpartment;
}
}
///////////////////////////////////////////////////////////////////////
//接口/mybaits/src/bao/EmployeeMapperDynamicSQL.java
package bao;

import java.util.List;

import org.apache.ibatis.annotations.Param;
public interface EmployeeMapperDynamicSQL {
		
	public List<User> getEmpsByConditionIf(User e);
}
////////////////////////////////////////////////////////////
//映射文件/mybaits/wenjian/EmployeeMapperDynamicSQL.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="bao.EmployeeMapperDynamicSQL">
 <select id="getEmpsByConditionIf" resultType="bao.User">
 select * from USER1
 where
 <if test="username!=null">
  username=#{username}</if>
  <if test="password!=null">
  and password=#{password}</if>
</select> 
</mapper>
///////////////////////////////////////////////
//测试
package bao;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;



public class MyBatisTest {
	
	public static void main(String []args) throws IOException {
		

		SqlSession openSession =getSqlSession();
		try {
			// 3、获取接口的实现类对象
			 EmployeeMapperDynamicSQL mapper = openSession.getMapper( EmployeeMapperDynamicSQL.class);
			System.out.println(mapper.getEmpsByConditionIf(new User(1,"123",null)));
		
		openSession.commit();
		} finally {
			openSession.close();
		}
	}
	public static SqlSession getSqlSession() throws IOException {
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		// 1、获取sqlSessionFactory对象
		// 2、获取sqlSession对象
		SqlSessionFactory a=new SqlSessionFactoryBuilder().build(inputStream);
		return a.openSession();
	}
}

_MyBatis_动态sql_where_查询条件.

查询的时候如果某些条件没带可能sql拼装会有问题
解决方案:
1、给where后面加上1=1,以后的条件都and xxx.
例子(在前面例子基础上)

//映射文件/mybaits/wenjian/EmployeeMapperDynamicSQL.xml改为
<select id="getEmpsByConditionIf" resultType="bao.User">
 select * from USER1
 where 1=1
 <if test="username!=null">
  and username=#{username}</if>
  <if test="password!=null">
  and password=#{password}</if>
</select> 

2、mybatis使用where标签来将所有的查询条件包括在内。mybatis就会将where标签中拼装的sql,多出来的and或者or去掉
where只会去掉前面username=#{username} 多出来的and或者or。
例子(在前面例子基础上)

//映射文件/mybaits/wenjian/EmployeeMapperDynamicSQL.xml改为
 <select id="getEmpsByConditionIf" resultType="bao.User">
 select * from USER1
 <where>
 <if test="username!=100">
   username=#{username}</if>
  <if test="password!=null">
  and password=#{password}</if>
  </where>
</select> 

_MyBatis_动态sql_trim_自定义字符串截取

例子(在前面例子基础上)

//接口bao.EmployeeMapperDynamicSQL.java
public List<User> getEmpsByConditionTrim(User e);
//映射文件/mybaits/wenjian/EmployeeMapperDynamicSQL.xml
	 <select id="getEmpsByConditionTrim" resultType="bao.User">
	 	select * from USER1
	 	<!-- 后面多出的and或者or where标签不能解决 
	 	prefix="":前缀:trim标签体中是整个字符串拼串 后的结果。
	 			prefix给拼串后的整个字符串加一个前缀 
	 	prefixOverrides="":
	 			前缀覆盖: 去掉整个字符串前面多余的字符
	 	suffix="":后缀
	 			suffix给拼串后的整个字符串加一个后缀 
	 	suffixOverrides=""
	 			后缀覆盖:去掉整个字符串后面多余的字符
	 			
	 	-->
	 	<!-- 自定义字符串的截取规则 -->
	 	<trim prefix="where" suffixOverrides="and" prefixOverrides="and">
	 		<if test="username!=100">
		 	and	username=#{username} and
		 	</if>
		 	<if test="password!=null">
		 	and	password=#{password} and
		 	</if>
		 </trim>
	 </select>
//测试
System.out.println(mapper.getEmpsByConditionTrim(new User(100,"123",null)));

_MyBatis_动态sql_choose_分支选择

例子(在前面例子基础上)

//接口bao.EmployeeMapperDynamicSQL.java
public List<User> getEmpsByConditionChoose(User e);
//映射文件/mybaits/wenjian/EmployeeMapperDynamicSQL.xml
	 <select id="getEmpsByConditionChoose" resultType="bao.User">
	 	select * from USER1
	 	<where>
	 		<!-- 选取首个满足的 -->
	 		<choose>
	 			<when test="username!=100">
	 				username=#{username}
	 			</when>
	 			<when test="password!=null">
	 				password=#{password}
	 			</when>
	 			<otherwise>
	 				1=1
	 			</otherwise>
	 		</choose>
	 	</where>
	 </select>

//测试
System.out.println(mapper.getEmpsByConditionChoose(new User(100,"123",null)));

_MyBatis_动态sql_set_与if结合的动态更新

例子(在前面例子基础上)

//接口bao.EmployeeMapperDynamicSQL.java
public void updateEmp(User e);
//映射文件/mybaits/wenjian/EmployeeMapperDynamicSQL.xml
<update id="updateEmp">
	 	<!-- Set标签的使用 -->
	 	update USER1 
		<set>
			<if test="password!=null">
				password=#{password},
			</if>
			<if test="dpartment!=null">
				dpartment=#{dpartment},
			</if>
		</set>
		where username=#{username} 
<!-- 		
		Trim:更新拼串
		update tbl_employee 
		<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>

//测试
 mapper.updateEmp(new User(3,"i love you",null));

_MyBatis_动态sql_foreach_遍历集合

例子(在前面例子基础上)

//接口bao.EmployeeMapperDynamicSQL.java
public List<User> getEmpsByConditionForeach(@Param("ids")List<Integer> ids);
//映射文件/mybaits/wenjian/EmployeeMapperDynamicSQL.xml
 <select id="getEmpsByConditionForeach" resultType="bao.User">
	 	select * from USER1
	 	<!--
	 		collection:指定要遍历的集合:
	 			list类型的参数会特殊处理封装在map中,map的key就叫list
	 		item:将当前遍历出的元素赋值给指定的变量
	 		separator:每个元素之间的分隔符
	 		open:遍历出所有结果拼接一个开始的字符
	 		close:遍历出所有结果拼接一个结束的字符
	 		index:索引。遍历list的时候是index就是索引,item就是当前值
	 				      遍历map的时候index表示的就是map的key,item就是map的值
	 		
	 		#{变量名}就能取出变量的值也就是当前遍历出的元素
	 	  -->
	 	<foreach collection="ids" item="item_id" separator=","
	 		open="where username in(" close=")">
	 		#{item_id}
	 	</foreach>
	 </select>
//测试
System.out.println(mapper.getEmpsByConditionForeach(Arrays.asList(1,2,3,4)));

_MyBatis_动态sql_foreach_mysql下foreach批量插入的两种方式

第一种:
例子在之前的基础上

//接口bao.EmployeeMapperDynamicSQL.java
public void addEmps(@Param("emps")List<User> emps);
//映射文件/mybaits/wenjian/EmployeeMapperDynamicSQL.xml
 <!-- 批量保存 -->
	 <!--public void addEmps(@Param("emps")List<Employee> emps);  -->
	 <!--MySQL下批量保存:可以foreach遍历   mysql支持values(),(),()语法-->
	<insert id="addEmps">
	 	insert into USER1(PASSWORD,DID)
		values
		<foreach collection="emps" item="emp" separator=",">
			(#{emp.password},#{emp.dpartment.id})
		</foreach>
	 </insert>
//测试
	ArrayList<User> a= new ArrayList<User>();
			a.add(new User(100,"dhdt",new Department(1,"设计部")));
			 mapper.addEmps(a);

第二种
在这里插入图片描述

//映射文件/mybaits/wenjian/EmployeeMapperDynamicSQL.xml
 <!-- 这种方式需要数据库连接属性allowMultiQueries=true;
	 	这种分号分隔多个sql可以用于其他的批量操作(删除,修改) -->
	<insert id="addEmps">
	 	<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> 

_MyBatis_动态sql_内置参数_parameter&_databaseId

例子在之前的基础上

//接口bao.EmployeeMapperDynamicSQL.java
public List<User> getEmpsTestInnerParameter(User e);
//映射文件/mybaits/wenjian/EmployeeMapperDynamicSQL.xml
 <!-- 两个内置参数:
	 	不只是方法传递过来的参数可以被用来判断,取值。。。
	 	mybatis默认还有两个内置参数:
	 	_parameter:代表整个参数
	 		单个参数:_parameter就是这个参数
	 		多个参数:参数会被封装为一个map;_parameter就是代表这个map
	 	
	 	_databaseId:如果配置了databaseIdProvider标签。//全局配置文件中/mybaits/wenjian/mybatis-config.xml
	 		_databaseId就是代表当前数据库的别名oracle
	  -->
	  
	  <!--public List<User> getEmpsTestInnerParameter(User e);  -->
	  <select id="getEmpsTestInnerParameter" resultType="bao.User">
	 
	  		<if test="_databaseId=='mysql'">
	  			select * from USER1
	  			<if test="_parameter!=null">
	  				where last_name like #{username}
	  			</if>
	  		</if>
	  		<if test="_databaseId=='oracle'">
	  			select * from employees
	  			<if test="_parameter!=null">
	  				where last_name like #{_parameter.lastName}
	  			</if>
	  		</if>
	  </select>
//测试
System.out.println(mapper.getEmpsTestInnerParameter(new User(1,null,null)));

_MyBatis_动态sql_bind_绑定

例子在之前的基础上

//映射文件/mybaits/wenjian/EmployeeMapperDynamicSQL.xml
 <!--public List<Employee> getEmpsTestInnerParameter(Employee employee);  -->
	  <select id="getEmpsTestInnerParameter" resultType="bao.User" >
	  	<!-- bind:可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值 -->
	  <bind name="password" value="'%'+password+'%'"/>
	  			select * from USER1
	  			<if test="_parameter!=null">
	  				where password like #{password}
	  		</if>
	  </select>

_MyBatis_动态sql_sql_抽取可重用的sql片段

例子在之前的基础上

//映射文件/mybaits/wenjian/EmployeeMapperDynamicSQL.xml

insert into employees(
	 		<!-- 引用外部定义的sql -->
	 		<include refid="insertColumn">
	 			<property name="testColomn" value="abc"/>
	 		</include>
	 	)
	 			<foreach collection="emps" item="emp" separator="union"
	 				open="select employees_seq.nextval,lastName,email from("
	 				close=")">
	 				select #{emp.lastName} lastName,#{emp.email} email from dual
	 			</foreach>
	 </insert>

<!-- 
	  	抽取可重用的sql片段。方便后面引用 
	  	1、sql抽取:经常将要查询的列名,或者插入用的列名抽取出来方便引用
	  	2、include来引用已经抽取的sql:
	  	3、include还可以自定义一些property,sql标签内部就能使用自定义的属性
	  			include-property:取值的正确方式${prop},
	  			#{不能使用这种方式}
	  -->
	  <sql id="insertColumn">
	  		<if test="_databaseId=='oracle'">
	  			employee_id,last_name,email,${prop}
	  		</if>
	  		<if test="_databaseId=='mysql'">
	  			last_name,email,gender,d_id
	  		</if>
	  </sql>

MyBatis-缓存机制

• MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率。
• MyBatis系统中默认定义了两级缓存。
• 一级缓存和二级缓存。
– 1、默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启。
– 2、二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
– 3、为了提高扩展性。MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

_MyBatis_缓存_一级缓存失效的四种情况

  • 一级缓存:(本地缓存):sqlSession级别的缓存。一级缓存是一直开启的;SqlSession级别的一个Map与数据库同一次会话期间查询到的数据会放在本地缓存中。以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库;

    一级缓存失效情况(没有使用到当前一级缓存的情况,效果就是,还需要再向数据库发出查询):

    •  1、sqlSession不同。
      
    •  2、sqlSession相同,查询条件不同.(当前一级缓存中还没有这个数据)
      
    •  3、sqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
      
    •  4、sqlSession相同,手动清除了一级缓存(缓存清空)openSession.clearCache();
      

_MyBatis_缓存_二级缓存介绍

二级缓存:(全局缓存):基于namespace级别的缓存:一个namespace对应一个二级缓存:
工作机制:
1、一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;
2、如果会话关闭;一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存中的内容;
3、sqlSession=EmployeeMapper>Employee
DepartmentMapper===>Department
不同namespace查出的数据会放在自己对应的缓存中(map)
效果:数据会从二级缓存中获取查出的数据都会被默认先放在一级缓存中。只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中
使用
1)、开启全局二级缓存配置:
在之前的例子基础上配置文件/mybaits/wenjian/mybatis-config.xml

<settings>
		<setting name="cacheEnabled" value="true"/>
	</settings>

2)、去mapper.xml中配置使用二级缓存:

映射文件/mybaits/wenjian/DepartmentMapper.xml

<!--  
	eviction:缓存的回收策略:
		• LRU – 最近最少使用的:移除最长时间不被使用的对象。
		• FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
		• SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
		• WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
		• 默认的是 LRU。
	flushInterval:缓存刷新间隔
		缓存多长时间清空一次,默认不清空,设置一个毫秒值
	readOnly:是否只读:
		true:只读;mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。
				 mybatis为了加快获取速度,直接就会将数据在缓存中的引用交给用户。不安全,速度快
		false:非只读:mybatis觉得获取的数据可能会被修改。
				mybatis会利用序列化&反序列的技术克隆一份新的数据给你。安全,速度慢
	size:缓存存放多少元素;
	type="":指定自定义缓存的全类名;
			实现Cache接口即可;
	-->
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="256"></cache>

3)、我们的POJO需要实现序列化接口

package bao;
import java.io.Serializable;

import org.apache.ibatis.type.Alias;
public class User implements Serializable{
private int username;
private String password;


public String getPassword() {
	return password;
}
public void setPassword(String password) {
	this.password = password;
}

public int getUsername() {
	return username;
}
public void setUsername(int username) {
	this.username = username;
}
@Override
public String toString() {
	return "User [ password=" + password
			+ ", username=" + username + "]";
}

public User() {
	super();
	// TODO Auto-generated constructor stub
}
public User(int username, String password) {
	super();
	this.username = username;
	this.password = password;

}
}

和缓存有关的设置/属性:

1)、cacheEnabled=true:false:关闭缓存(二级缓存关闭)(一级缓存一直可用的)
2)、每个select标签都有useCache=“true”:false:不使用缓存(一级缓存依然使用,二级缓存不使用)
3)、【每个增删改标签的:flushCache=“true”:(一级二级都会清除)】
增删改执行完成后就会清楚缓存;
测试:flushCache=“true”:一级缓存就清空了;二级也会被清除;
查询标签:flushCache=“false”:
如果flushCache=true;每次查询之后都会清空缓存;缓存是没有被使用的;
4)、sqlSession.clearCache();只是清楚当前session的一级缓存;
5)、localCacheScope:本地缓存作用域:(一级缓存SESSION);当前会话的所有数据保存在会话缓存中;STATEMENT:可以禁用一级缓存;
在这里插入图片描述

整合第三方缓存

架包
详细教程
第三方缓存整合:
1)、导入第三方缓存包即可;
2)、导入与第三方缓存整合的适配包;官方有;
3)、mapper.xml中使用自定义缓存

<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>

在之前的例子中:
映射文件/mybaits/wenjian/EmployeeMapper.xml

<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>

在这里插入图片描述
引用缓存:namespace:指定和哪个名称空间下的缓存一样
在映射文件中

	<cache-ref namespace="dao.EmployeeMapper"/>

spring+springmvc+mybatis整合

猜你喜欢

转载自blog.csdn.net/feiqipengcheng/article/details/106820198
今日推荐