一、映射关系
1.一对一关系
实现方式 resultType/resultMap
接口方法
resultType实现
/**
* 一对一关联查询 resultType
* @param userId
* @return
*/
UserDto queryUserCardInfoForResultType(@Param("userId")int userId);
sql查询
<select id="queryUserCardInfoForResultType" resultType="userDto">
SELECT
u.id,
u.user_name AS userName,
u.user_pwd AS userPwd,
u.flag,
u.cid,
c.number
FROM
USER u
LEFT JOIN card c ON u.cid = c.id
WHERE
u.id = #{userId}
</select>
- resultType实现
<select id="queryUserByIdResultType" parameterType="int"
resultType="com.shsxt.dto.UserDto">
SELECT
u.id,
u.user_name AS userName,
u.create_time,
u.flag,
u.cid AS cid,
c.number
FROM
User u
LEFT JOIN card c u ON u.cid =c.id
WHERE
u.id = #{id}
</select>
resultMap实现
接口实现
/**
* 一对一关联查询 resultMap
* @param userId
* @return
*/
User queryUserCardInfoForResultMap(@Param("userId")int userId);
resultMap映射定义
<resultMap type="user" id="user_card">
<!-- 主表基本字段配置 -->
<!-- 唯一标识用户记录字段 -->
<id column="id" property="id" />
<!-- 普通字段信息配置标签 -->
<result column="userName" property="userName" />
<result column="userPwd" property="userPwd" />
<result column="flag" property="flag" />
<result column="cid" property="cid" />
<!--
property:一的一方成员变量名
javaType:变量类型 别名代替
-->
<association property="card" javaType="card">
<!--
column:唯一标识从表记录的字段 cid
property:card 的成员变量名
-->
<id column="cid" property="id"/>
<result column="number" property="number"/>
</association>
</resultMap
sql查询
<select id="queryUserCardInfoForResultMap" resultMap="user_card">
SELECT
u.id,
u.user_name AS userName,
u.user_pwd AS userPwd,
u.flag,
u.cid,
c.number
FROM
USER u
LEFT JOIN card c ON u.cid = c.id
WHERE
u.id = #{userId}
</select>
2.一对多关系
实现方式:resultMap实现
resultType有局限,无法去重,需手动处理
接口方法定义
/**
* 一对多关联查询 resultMap
* @param userId
* @return
*/
User queryUserCardAccountInfoForResultMap(@Param("userId")int
userId);
ResultMap定义
<!-- 一对多查询 :resultMap
-->
<resultMap type="user" id="user_card_account" extends="user_card">
<!--添加一对多关系配置
property:多的一方成员变量名称
ofType:集合中元素类型
-->
<collection property="accounts" ofType="account">
<id column="aid" property="id"/>
<result column="aname" property="aname"/>
<result column="type" property="type"/>
<result column="money" property="money"/>
<result column="createTime" property="createTime"/>
<result column="updateTime" property="updateTime"/>
<result column="remark" property="remark"/>
</collection>
</resultMap>
sql查询
<select id="queryUserCardAccountInfoForResultMap"
resultMap="user_card_account" >
SELECT
u.id,
u.user_name AS userName,
u.user_pwd AS userPwd,
u.flag,
u.cid,
c.number,
a.id AS aid,
a.aname,
a.type,
a.money,
a.create_time AS createTime,
a.update_time AS updateTime,
a.remark
FROM
USER u
LEFT JOIN card c ON u.cid = c.id
LEFT JOIN account a ON u.id = a.user_id
WHERE
u.id = #{userId}
</select>
二、Mybatis缓存
MyBatis是持久层框架,MyBatis同样提供了一级缓存和二级缓存的支持;
- 一级缓存
基于 PerpetualCache 的 HashMap 本地缓存(mybatis 内部实现 cache 接口),
其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache
就将清空; - 二级缓存
一级缓存其机制相同,默认也是采用 PerpetualCache 的 HashMap 存储,不同在
于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache;
对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存
Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。
如果二缓存开启,首先从二级缓存查询数据,如果二级缓存有则从二级缓存中获取数据,
如果二级缓存没有,从一级缓存找是否有缓存数据,如果一级缓存没有,查询数据库。
1.一级缓存
Mybatis默认提供一级缓存,缓存范围是一个SQLSession。在同一个SqlSession中,两次执行相同的sql查询,第二次不在从数据库中查询。
原理:一级缓存采用Hashmap存储,mybatis执行查询是,从缓存中查询,如果缓存中没有从数据库查询。如果该SqlSession执行clearCache()提交或者增加 删除 修改操作,清除缓存。
a.缓存存在清况(session为提交)
@Test
public void test01() {
SqlSession sqlSession=sqlSessionFactory.openSession();
AccountDao accountDao=sqlSession.getMapper(AccountDao.class);
Account account=accountDao.queryAccountById(1);
System.out.println(account);
accountDao.queryAccountById(1);
b.刷新缓存
Session提交 此时的缓存被刷新
@Test
public void test02() {
SqlSession sqlSession=sqlSessionFactory.openSession();
AccountDao accountDao=sqlSession.getMapper(AccountDao.class);
Account account=accountDao.queryAccountById(1);
System.out.println(account);
sqlSession.clearCache();
accountDao.queryAccountById(1);
}
2.二级缓存
一级缓存是在同一个sqlSession中,二级缓存是存在同一个namespace中,因此相同的namespace不同的sqlSession可以使用二级缓存。
使用建议
- 1、对查询频率高,变化频率低的数据建议使用二级缓存。
- 2、对应访问多的查询请求用户查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度。
全局文件配置
<setting name="cacheEnabled" value="true"/>
Mapper.xml 中加入 :打开该 mapper 的二级缓存
<!-- 开启该 mapper 的二级缓存 -->
<cache/>
<!--cache 标签常用属性-->
<cache
eviction="FIFO" <!--回收策略为先进先出-->
flushInterval="60000" <!--自动刷新时间 60s-->
size="512" <!--最多缓存 512 个引用对象-->
readOnly="true"/> <!--只读-->
说明:
- 映射语句文件中的所有 select 语句将会被缓存。
- 映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。
- 缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。
- 缓存会根据指定的时间间隔来刷新.
- 缓存会存储 1024 个对象
PO 对象必须支持序列化
public class User implements Serializable {
}
关闭 Mapper 下的具体的 statement 的缓存
<select id="findUserByid" parameterType="int" resultType="User"
useCache="false">//userCache关闭
SELECT * FROM user WHERE id=#{id}
</select>
刷新二级缓存
操作 CUD 的 statement 时候,会强制刷新二级缓存 即默认 flushCache=“true” ,如果想关
闭设定为 flushCache="false"即可 ,不建议关闭刷新,因为操作更新删除修改,关闭后容
易获取脏数据。
二级缓存测试:
@Test
public void test03() {
SqlSession sqlSession=sqlSessionFactory.openSession();
AccountDao accountDao=sqlSession.getMapper(AccountDao.class);
Account account=accountDao.queryAccountById(1);
System.out.println(account);
sqlSession.close();
SqlSession sqlSession2=sqlSessionFactory.openSession();
AccountDao accountDao2=sqlSession2.getMapper(AccountDao.class);
accountDao2.queryAccountById(1);
sqlSession.close();
}
3.分布式缓存ehcache
如果有多台服务器 ,不使用分布缓存,缓存的数据在各个服务器单独存储,不方便
系统 开发。所以要使用分布式缓存对缓存数据进行集中管理。因此可是使用 ehcache
memcached redis
mybatis 本身来说是无法实现分布式缓存的,所以要与分布式缓存框架进行整合。
EhCache 是一个纯 Java 的进程内缓存框架,具有快速、精干等特点;Ehcache 是一种广泛
使用的开源 Java 分布式缓存。主要面向通用缓存,Java EE 和轻量级容器。它具有内存和
磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个 gzip 缓存 servlet 过滤器,支持
REST 和 SOAP api 等特点。
在pom.xml中添加Jar依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.4.4</version>
</dependency>
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.0.3</version>
</dependency>
在mapper.xml中配置缓存接口
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
在 resources 下 加入 ehcache.xml(不是必须的没有使用默认配置)
在resources中,添加ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../bin/ehcache.xsd">
<!--
name:Cache 的唯一标识
maxElementsInMemory:内存中最大缓存对象数
maxElementsOnDisk:磁盘中最大缓存对象数,若是 0 表示无穷大
eternal:Element 是否永远不过期,如果为 true,则缓存的数据始终有效,如果为 false
那么还要根据 timeToIdleSeconds,timeToLiveSeconds 判断
overflowToDisk:配置此属性,当内存中 Element 数量达到 maxElementsInMemory 时,
Ehcache 将会 Element 写到磁盘中
timeToIdleSeconds:设置 Element 在失效前的允许闲置时间。仅当 element 不是永久有效
时使用,可选属性,默认值是 0,也就是可闲置时间无穷大
timeToLiveSeconds:设置 Element 在失效前允许存活时间。最大时间介于创建时间和失效
时间之间。仅当 element 不是永久有效时使用,默认是 0.,也就是 element 存活时间无穷
大
diskPersistent:是否缓存虚拟机重启期数据
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是 120 秒
diskSpoolBufferSizeMB:这个参数设置 DiskStore(磁盘缓存)的缓存区大小。默认是
30MB。每个 Cache 都应该有自己的一个缓冲区
memoryStoreEvictionPolicy:当达到 maxElementsInMemory 限制时,Ehcache 将会根据
指定的策略去清理内存。默认策略是 LRU(最近最少使用)。你可以设置为 FIFO(先进先
出)或是 LFU(较少使用)
-->
<defaultCache overflowToDisk="true" eternal="false"/>
<diskStore path="D:/cache" />
<!--
<cache name="sxtcache" overflowToDisk="true" eternal="false"
timeToIdleSeconds="300" timeToLiveSeconds="600" maxElementsInMemory="1000"
maxElementsOnDisk="10" diskPersistent="true"
diskExpiryThreadIntervalSeconds="300"
diskSpoolBufferSizeMB="100" memoryStoreEvictionPolicy="LRU" />
-->
测试:
@Test
public void test04() {
SqlSession sqlSession=sqlSessionFactory.openSession();
AccountDao accountDao=sqlSession.getMapper(AccountDao.class);
Account account=accountDao.queryAccountById(1);
System.out.println(account);
sqlSession.close();
SqlSession sqlSession2=sqlSessionFactory.openSession();
AccountDao accountDao2=sqlSession2.getMapper(AccountDao.class);
accountDao2.queryAccountById(1);
sqlSession.close();
}
三、Spring与Mybatis集成
1.在pom.xml中引入依赖包
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.shsxt</groupId>
<artifactId>spring_mybatis</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>spring_mybatis Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- junit 测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- spring 核心 jar -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- spring 测试 jar -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- spring jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- spring 事物 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- aspectj 切面编程的 jar -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!-- c3p0 连接池 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
<!-- 添加 mybatis 与 Spring 整合的核心包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!-- mysql 驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
<!-- 日志打印相关的 jar -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.2</version>
</dependency>
</dependencies>
<build>
<finalName>spring_mybatis</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.tld</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>