一级缓存
对于一级缓存来说,Mybatis 是直接单个线程隔离的在执行 add,update,delete 的时候, 会自动清空缓存, 避免脏读造成的影响此时 mapper 为线程隔离的, 而管理对象为所有线程所共享的.
修改展示层
<%@ page import=”org.apache.ibatis.session.SqlSession” %>
<%@ page import=”com.ming.Util.SqlSessionFactoryUtil” %>
<%@ page import=”com.ming.MyBatis.RoleMapper” %>
<%@ page import=”java.util.List” %>
<%@ page import=”java.util.Iterator” %>
<%@ page import=”com.ming.MyBatis.POJO.Student” %>
<html>
<body>
<h2>Hello World!</h2>
<%
long startTime = System.currentTimeMillis(); // 获取开始时间
SqlSession sqlSession = null;
List<Student> students = null;
List<Student> students1 = null;
try {
sqlSession = SqlSessionFactoryUtil.openSqlSesion();
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
students = roleMapper.getStudent(1);
students1 = roleMapper.getStudent(1);
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
sqlSession.rollback();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
long endTime = System.currentTimeMillis(); // 获取结束时间
%>
<%
Iterator iterator = students.iterator();
while(iterator.hasNext()){
%>
<%=((Student)iterator.next()).getGender()%>
<%
}
iterator = students1.iterator();
while(iterator.hasNext()){
%>
<%=((Student)iterator.next()).getGender()%>
<%
}
%>
</body>
</html>
查看日志
2019-04-17 22:33:38.147 [DEBUG] org.apache.ibatis.transaction.jdbc.JdbcTransaction.openConnection(JdbcTransaction.java:136) – Opening JDBC Connection
2019-04-17 22:33:38.147 [DEBUG] org.apache.ibatis.datasource.pooled.PooledDataSource.popConnection(PooledDataSource.java:397) – Checked out connection 879027360 from pool.
2019-04-17 22:33:38.148 [DEBUG] org.apache.ibatis.transaction.jdbc.JdbcTransaction.setDesiredAutoCommit(JdbcTransaction.java:100) – Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3464e4a0]
2019-04-17 22:33:38.161 [DEBUG] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:143) – ==> Preparing: SELECT student.uid, student.gender, student.remarks, student.student_id_number, student.student_name FROM student WHERE student.uid = 1;
2019-04-17 22:33:38.162 [DEBUG] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:143) – ==> Parameters:
2019-04-17 22:33:38.181 [DEBUG] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:143) – <== Total: 1
2019-04-17 22:33:38.183 [DEBUG] org.apache.ibatis.transaction.jdbc.JdbcTransaction.resetAutoCommit(JdbcTransaction.java:122) – Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3464e4a0]
2019-04-17 22:33:38.200 [DEBUG] org.apache.ibatis.transaction.jdbc.JdbcTransaction.close(JdbcTransaction.java:90) – Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3464e4a0]
2019-04-17 22:33:38.201 [DEBUG] org.apache.ibatis.datasource.pooled.PooledDataSource.pushConnection(PooledDataSource.java:362) – Returned connection 879027360 to pool.
可以看到只查询了一次
需要注意的是缓存在各个 SqlSession 是相互隔离的
二级缓存
二级缓存直接添加 cache 即可
<?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=”com.ming.MyBatis.RoleMapper”>
<resultMap type=”role” id=”roleMap”>
<!– id 为主键映射关系 其中数据库中的 id 为主键 –>
<id column=”id” property=”id” javaType=”int” jdbcType=”INTEGER”/>
<!– result 为其他基本数据类型和实体类之间的映射 映射关系为 role_name 到 roleName 之间的映射 数据类型为 string 到 VARCHAR 之间的映射关系 –>
<result column=”role_name” property=”roleName” javaType=”string” jdbcType=”VARCHAR”/>
<!– 这里使用 typeHandler 表示遇到此处理集的时候, 将会执行 com.ming.MyBatis.StringTypeHandler –>
<result column=”note” property=”note” typeHandler=”com.ming.MyBatis.StringTypeHandler”/>
</resultMap>
<select id=”getRole” parameterType=”int” resultType=”com.ming.MyBatis.POJO.Role”>
SELECT id, role_name as roleName, note FROM t_role WHERE id = #{id}
</select>
<select id=”findRoleByteMap” parameterType=”map” resultMap=”roleMap”>
SELECT id, role_name, note FROM t_role
WHERE role_name LIKE CONCAT(‘%’, #{roleName}, ‘%’)
AND note LIKE CONCAT(‘%’, #{note}, ‘%’)
</select>
<select id=”findRoleByteMap1″ resultMap=”roleMap”>
SELECT id, role_name, note FROM t_role
WHERE role_name LIKE CONCAT(‘%’, #{roleName}, ‘%’)
AND note LIKE CONCAT(‘%’, #{note}, ‘%’)
</select>
<resultMap id=”studentSelfCardMap” type=”com.ming.MyBatis.POJO.StudentCard”>
<id column=”uid” property=”uid”/>
<result column=”student_number” property=”studentNumber”/>
<result column=”birthplace” property=”birthplace” />
<result column=”date_of_issue” property=”dateOfIssue” jdbcType=”DATE” javaType=”java.util.Date”/>
<result column=”end_date” property=”endDate” jdbcType=”DATE” javaType=”java.util.Date”/>
<result column=”remarks” property=”remarks” />
</resultMap>
<select id=”findStudentSelfCardByStudentId” parameterType=”int” resultMap=”studentSelfCardMap”>
SELECT student_card.uid, student_card.student_number, student_card.remarks,
student_card.end_date, student_card.date_of_issue, student_card.birthplace
FROM student_card WHERE student_card.uid = #{studentId};
</select>
<resultMap id=”studentMap” type=”com.ming.MyBatis.POJO.Student”>
<id column=”uid” property=”uid”/>
<result column=”student_name” property=”studentName”/>
<result column=”gender” property=”gender”/>
<result column=”student_id_number” property=”studentIdNumber”/>
<result column=”remarks” property=”remarks”/>
<!– 将会调用接口代表的 SQL 进行执行查询 –>
<association property=”studentCard” column=”uid” select=”com.ming.MyBatis.RoleMapper.findStudentSelfCardByStudentId”/>
</resultMap>
<select id=”getStudent” parameterType=”int” resultMap=”studentMap”>
SELECT student.uid, student.gender, student.remarks, student.student_id_number,
student.student_name
FROM student
WHERE student.uid = 1;
</select>
<cache/>
</mapper>
此时 select 语句将会缓存 insert update delete 将会刷新缓存会使用 LRU 算法进行回收根据时间表 缓存不会用任何时间顺序来刷新缓存缓存会存储列表集合或对象 1024 个引用
由于对象需要序列化所以需要实现 java.io.Serializable 接口
父类实现序列化 子类会自动实现序列化 若子类实现序列化 父类没有实现序列化 此时在子类中保存父类的值, 直接跳过
2019-04-18 00:55:44.428 [DEBUG] org.apache.ibatis.cache.decorators.LoggingCache.getObject(LoggingCache.java:62) – Cache Hit Ratio [com.ming.MyBatis.RoleMapper]: 0.7586206896551724
2019-04-18 00:55:44.430 [DEBUG] org.apache.ibatis.cache.decorators.LoggingCache.getObject(LoggingCache.java:62) – Cache Hit Ratio [com.ming.MyBatis.RoleMapper]: 0.7666666666666667
2019-04-18 00:55:44.433 [DEBUG] org.apache.ibatis.cache.decorators.LoggingCache.getObject(LoggingCache.java:62) – Cache Hit Ratio [com.ming.MyBatis.RoleMapper]: 0.7741935483870968
2019-04-18 00:55:44.435 [DEBUG] org.apache.ibatis.cache.decorators.LoggingCache.getObject(LoggingCache.java:62) – Cache Hit Ratio [com.ming.MyBatis.RoleMapper]: 0.78125
查看日志, 可以发现再次读取的时候, 直接从缓存中获取了. 缓存生效, 并为执行 sql 语句
已经命中缓存
自定义缓存
这个需要实现 cache 接口
package com.ming.MyBatis;
import java.util.concurrent.locks.ReadWriteLock;
/**
* @author ming
*/
public class Cache implements org.apache.ibatis.cache.Cache {
/**
* @return The identifier of this cache
*/
@Override
public String getId() {
return null;
}
/**
* @param key Can be any object but usually it is a {@link CacheKey}
* @param value The result of a select.
*/
@Override
public void putObject(Object key, Object value) {
}
/**
* @param key The key
* @return The object stored in the cache.
*/
@Override
public Object getObject(Object key) {
return null;
}
/**
* As of 3.3.0 this method is only called during a rollback
* for any previous value that was missing in the cache.
* This lets any blocking cache to release the lock that
* may have previously put on the key.
* A blocking cache puts a lock when a value is null
* and releases it when the value is back again.
* This way other threads will wait for the value to be
* available instead of hitting the database.
*
* @param key The key
* @return Not used
*/
@Override
public Object removeObject(Object key) {
return null;
}
/**
* Clears this cache instance.
*/
@Override
public void clear() {
}
/**
* Optional. This method is not called by the core.
*
* @return The number of elements stored in the cache (not its capacity).
*/
@Override
public int getSize() {
return 0;
}
/**
* Optional. As of 3.2.6 this method is no longer called by the core.
* <p>
* Any locking needed by the cache must be provided internally by the cache provider.
*
* @return A ReadWriteLock
*/
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
}
然后 redis 直接操作即可
额 … 暂时先不连接