redis mysql 一级缓存_MyBatis系列目录--5. MyBatis一级缓存和二级缓存(redis实现)

查询缓存:绝大数系统主要是读多写少。

缓存作用:减轻数据库压力,提供访问速度。

576f47b1c08e3bda2eaf445e62c924f3.png

1. 一级缓存测试用例

(1) 默认开启,不需要有什么配置

(2) 示意图

58b4677bb617558fc08f300aee02a7bc.png

(3) 测试代码

Java代码  6e5481f2821bc05cfd2ff3ea59133e46.png

package com.sohu.tv.cache;

import org.apache.ibatis.session.SqlSession;

import org.junit.After;

import org.junit.Before;

import org.junit.Test;

import com.sohu.tv.bean.Player;

import com.sohu.tv.mapper.PlayerDao;

import com.sohu.tv.test.mapper.BaseTest;

/**

* 一级缓存测试

*

* @author leifu

* @Date 2015-8-3

* @Time 下午9:51:00

*/

public class FirstCacheTest extends BaseTest {

private SqlSession sqlSession;

private SqlSession sqlSessionAnother;

@Before

public void before() {

sqlSession = sessionFactory.openSession(false);

sqlSessionAnother = sessionFactory.openSession(false);

}

@After

public void after() {

sqlSession.close();

sqlSessionAnother.close();

}

@Test

public void test1() throws Exception {

PlayerDao playerDao = sqlSession.getMapper(PlayerDao.class);

Player player = playerDao.getPlayerById(1);

System.out.println(player);

playerDao = sqlSession.getMapper(PlayerDao.class);

player = playerDao.getPlayerById(1);

System.out.println(player);

playerDao = sqlSessionAnother.getMapper(PlayerDao.class);

player = playerDao.getPlayerById(1);

System.out.println(player);

}

@Test

public void test2() throws Exception {

PlayerDao playerDao = sqlSession.getMapper(PlayerDao.class);

Player player = playerDao.getPlayerById(1);

System.out.println(player);

//1. session清除或者提交

//        sqlSession1.commit();

//        sqlSession.clearCache();

//2. 增删改查

//        playerDao.savePlayer(new Player(-1, "abcd", 13));

//        playerDao.updatePlayer(new Player(4, "abcd", 13));

playerDao.deletePlayer(4);

player = playerDao.getPlayerById(1);

System.out.println(player);

}

}

2、二级缓存(自带 PerpetualCache)

(0) 示意图

7cd02f630af6188a631b54790f70aa9e.png

(1) 二级缓存需要开启

总配置文件中,二级缓存也是开启的,不需要设置

Xml代码  6e5481f2821bc05cfd2ff3ea59133e46.png

mapper级别的cache需要开启,在对应的mapper.xml写入

Xml代码  6e5481f2821bc05cfd2ff3ea59133e46.png

(2) 实体类在二级缓存中需要进行序列化,所以所有实体类需要实现Serializable

(3) 示例:

Java代码  6e5481f2821bc05cfd2ff3ea59133e46.png

package com.sohu.tv.cache;

import org.apache.ibatis.session.SqlSession;

import org.junit.After;

import org.junit.Before;

import org.junit.Test;

import com.sohu.tv.bean.Player;

import com.sohu.tv.mapper.PlayerDao;

import com.sohu.tv.test.mapper.BaseTest;

/**

* 二级缓存测试

*

* @author leifu

* @Date 2015-8-3

* @Time 下午10:10:34

*/

public class SecondCacheTest extends BaseTest {

private SqlSession sqlSession1 = sessionFactory.openSession();

private SqlSession sqlSession2 = sessionFactory.openSession();

private SqlSession sqlSession3 = sessionFactory.openSession();

private PlayerDao playerDao1;

private PlayerDao playerDao2;

private PlayerDao playerDao3;

@Before

public void before() {

sqlSession1 = sessionFactory.openSession(false);

sqlSession2 = sessionFactory.openSession(false);

sqlSession3 = sessionFactory.openSession(false);

playerDao1 = sqlSession1.getMapper(PlayerDao.class);

playerDao2 = sqlSession2.getMapper(PlayerDao.class);

playerDao3 = sqlSession3.getMapper(PlayerDao.class);

}

@After

public void after() {

sqlSession1.close();

sqlSession2.close();

sqlSession3.close();

}

@Test

public void test1() throws Exception {

int targetId = 1;

//session1 查询并提交

Player player1 = playerDao1.getPlayerById(targetId);

System.out.println("player1: " + player1);

sqlSession1.commit();

//session2 命中后,更新并提交清空缓存

Player player2 = playerDao2.getPlayerById(targetId);

System.out.println("player2: " + player2);

player2.setAge(15);

playerDao2.update(player2);

sqlSession2.commit();

//session3 不命中

Player player3 = playerDao3.getPlayerById(targetId);

System.out.println("player3: " + player3);

}

@Test

public void test2() throws Exception {

int one = 1;

int two = 2;

//session1 查询并提交

Player player1 = playerDao1.getPlayerById(one);

playerDao1.getPlayerById(two);

System.out.println("player1: " + player1);

sqlSession1.commit();

//session2 命中后,更新并提交清空缓存

Player player2 = playerDao2.getPlayerById(one);

System.out.println("player2: " + player2);

player2.setAge(15);

playerDao2.updatePlayer(player2);

sqlSession2.commit();

//session3 不命中

Player player3 = playerDao3.getPlayerById(two);

System.out.println("player3: " + player3);

}

}

(4) 重要日志:

Java代码  6e5481f2821bc05cfd2ff3ea59133e46.png

22:24:37.191 [main] DEBUG com.sohu.tv.mapper.PlayerDao - Cache Hit Ratio [com.sohu.tv.mapper.PlayerDao]: 0.0

22:24:37.196 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Opening JDBC Connection

22:24:37.460 [main] DEBUG o.a.i.d.pooled.PooledDataSource - Created connection 1695520324.

22:24:37.460 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@650f9644]

22:24:37.463 [main] DEBUG c.s.t.mapper.PlayerDao.getPlayerById - ==> Preparing: select id,name,age from players where id=?

22:24:37.520 [main] DEBUG c.s.t.mapper.PlayerDao.getPlayerById - ==> Parameters: 1(Integer)

22:24:37.541 [main] DEBUG c.s.t.mapper.PlayerDao.getPlayerById - <== Total: 1

player1: Player [id=1, name=kaka, age=60]

22:24:37.549 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@650f9644]

22:24:37.549 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@650f9644]

22:24:37.549 [main] DEBUG o.a.i.d.pooled.PooledDataSource - Returned connection 1695520324 to pool.

22:29:13.203 [main] DEBUG com.sohu.tv.mapper.PlayerDao - Cache Hit Ratio [com.sohu.tv.mapper.PlayerDao]: 0.5

player3: Player [id=1, name=kaka, age=60]

22:29:13.204 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Opening JDBC Connection

22:29:13.204 [main] DEBUG o.a.i.d.pooled.PooledDataSource - Checked out connection 1695520324 from pool.

22:29:13.204 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@650f9644]

22:29:13.205 [main] DEBUG c.s.tv.mapper.PlayerDao.updatePlayer - ==> Preparing: update players set name=?,age=? where id=?

22:29:13.207 [main] DEBUG c.s.tv.mapper.PlayerDao.updatePlayer - ==> Parameters: kaka(String), 60(Integer), 1(Integer)

22:29:13.208 [main] DEBUG c.s.tv.mapper.PlayerDao.updatePlayer - <== Updates: 1

22:29:13.210 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@650f9644]

22:29:13.210 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@650f9644]

22:29:13.211 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@650f9644]

22:29:13.211 [main] DEBUG o.a.i.d.pooled.PooledDataSource - Returned connection 1695520324 to pool.

22:29:13.211 [main] DEBUG com.sohu.tv.mapper.PlayerDao - Cache Hit Ratio [com.sohu.tv.mapper.PlayerDao]: 0.3333333333333333

22:29:13.211 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Opening JDBC Connection

22:29:13.212 [main] DEBUG o.a.i.d.pooled.PooledDataSource - Checked out connection 1695520324 from pool.

22:29:13.212 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@650f9644]

22:29:13.212 [main] DEBUG c.s.t.mapper.PlayerDao.getPlayerById - ==> Preparing: select id,name,age from players where id=?

22:29:13.213 [main] DEBUG c.s.t.mapper.PlayerDao.getPlayerById - ==> Parameters: 1(Integer)

22:29:13.214 [main] DEBUG c.s.t.mapper.PlayerDao.getPlayerById - <== Total: 1

player2: Player [id=1, name=kaka, age=60]

22:29:13.215 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@650f9644]

22:29:13.216 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@650f9644]

22:29:13.216 [main] DEBUG o.a.i.d.pooled.PooledDataSource - Returned connection 1695520324 to pool.

3、二级缓存(Redis版)

(1) redis使用一个简单的单点实例作为数据源:

引入jedis pom依赖:

Xml代码  6e5481f2821bc05cfd2ff3ea59133e46.png

2.8.0

1.0.8

redis.clients

jedis

${jedis.version}

com.dyuproject.protostuff

protostuff-runtime

${protostuff.version}

com.dyuproject.protostuff

protostuff-core

${protostuff.version}

jedis获取工具(使用jedispool)

Java代码  6e5481f2821bc05cfd2ff3ea59133e46.png

package com.sohu.tv.redis;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import redis.clients.jedis.JedisPool;

/**

* jedisPool获取工具

*

* @author leifu

* @Date 2015年8月4日

* @Time 上午9:01:45

*/

public class RedisStandAloneUtil {

private final static Logger logger = LoggerFactory.getLogger(RedisStandAloneUtil.class);

/**

* jedis连接池

*/

private static JedisPool jedisPool;

/**

* redis-host

*/

private final static String REDIS_HOST = "10.10.xx.xx";

/**

* redis-port

*/

private final static int REDIS_PORT = 6384;

static {

try {

jedisPool = new JedisPool(new GenericObjectPoolConfig(), REDIS_HOST, REDIS_PORT);

} catch (Exception e) {

logger.error(e.getMessage(), e);

}

}

public static JedisPool getJedisPool() {

return jedisPool;

}

public static void main(String[] args) {

System.out.println(RedisStandAloneUtil.getJedisPool().getResource().info());

}

}

(2) 如果自己实现mybatis的二级缓存,需要实现org.apache.ibatis.cache.Cache接口,已经实现的有如下:

fedbb5041729d7b11d3cc345ade68240.png

序列化相关工具代码:

Java代码  6e5481f2821bc05cfd2ff3ea59133e46.png

package com.sohu.tv.redis.serializable;

import com.dyuproject.protostuff.LinkedBuffer;

import com.dyuproject.protostuff.ProtostuffIOUtil;

import com.dyuproject.protostuff.Schema;

import com.dyuproject.protostuff.runtime.RuntimeSchema;

import java.util.concurrent.ConcurrentHashMap;

public class ProtostuffSerializer {

private static ConcurrentHashMap, Schema>> cachedSchema = new ConcurrentHashMap, Schema>>();

public  byte[] serialize(final T source) {

VO vo = new VO(source);

final LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);

try {

final Schema schema = getSchema(VO.class);

return serializeInternal(vo, schema, buffer);

} catch (final Exception e) {

throw new IllegalStateException(e.getMessage(), e);

} finally {

buffer.clear();

}

}

public  T deserialize(final byte[] bytes) {

try {

Schema schema = getSchema(VO.class);

VO vo = deserializeInternal(bytes, schema.newMessage(), schema);

if (vo != null && vo.getValue() != null) {

return (T) vo.getValue();

}

} catch (final Exception e) {

throw new IllegalStateException(e.getMessage(), e);

}

return null;

}

private  byte[] serializeInternal(final T source, final Schema schema, final LinkedBuffer buffer) {

return ProtostuffIOUtil.toByteArray(source, schema, buffer);

}

private  T deserializeInternal(final byte[] bytes, final T result, final Schema schema) {

ProtostuffIOUtil.mergeFrom(bytes, result, schema);

return result;

}

private static  Schema getSchema(Class clazz) {

@SuppressWarnings("unchecked")

Schema schema = (Schema) cachedSchema.get(clazz);

if (schema == null) {

schema = RuntimeSchema.createFrom(clazz);

cachedSchema.put(clazz, schema);

}

return schema;

}

}

Java代码  6e5481f2821bc05cfd2ff3ea59133e46.png

package com.sohu.tv.redis.serializable;

import java.io.Serializable;

public class VO implements Serializable {

private T value;

public VO(T value) {

this.value = value;

}

public VO() {

}

public T getValue() {

return value;

}

@Override

public String toString() {

return "VO{" +

"value=" + value +

'}';

}

}

Redis需要自己来实现,代码如下:

Java代码  6e5481f2821bc05cfd2ff3ea59133e46.png

package com.sohu.tv.redis;

import java.util.concurrent.locks.ReadWriteLock;

import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.ibatis.cache.Cache;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import redis.clients.jedis.Jedis;

import redis.clients.jedis.serializable.ProtostuffSerializer;

/**

* mybatis redis实现

*

* @author leifu

* @Date 2015年8月4日

* @Time 上午9:12:37

*/

public class MybatisRedisCache implements Cache {

private static Logger logger = LoggerFactory.getLogger(MybatisRedisCache.class);

private String id;

private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

private final ProtostuffSerializer protostuffSerializer = new ProtostuffSerializer();

public MybatisRedisCache(final String id) {

if (logger.isInfoEnabled()) {

logger.info("============ MybatisRedisCache id {} ============", id);

}

if (id == null) {

throw new IllegalArgumentException("Cache instances require an ID");

}

this.id = id;

}

@Override

public String getId() {

return this.id;

}

@Override

public int getSize() {

Jedis jedis = null;

int size = -1;

try {

jedis = RedisStandAloneUtil.getJedisPool().getResource();

size = Integer.valueOf(jedis.dbSize().toString());

} catch (Exception e) {

logger.error(e.getMessage(), e);

} finally {

if (jedis != null) {

jedis.close();

}

}

return size;

}

@Override

public void putObject(Object key, Object value) {

if (logger.isInfoEnabled()) {

logger.info("============ putObject key: {}, value: {} ============", key, value);

}

Jedis jedis = null;

try {

jedis = RedisStandAloneUtil.getJedisPool().getResource();

byte[] byteKey = protostuffSerializer.serialize(key);

byte[] byteValue = protostuffSerializer.serialize(value);

jedis.set(byteKey, byteValue);

} catch (Exception e) {

logger.error(e.getMessage(), e);

} finally {

if (jedis != null) {

jedis.close();

}

}

}

@Override

public Object getObject(Object key) {

if (logger.isInfoEnabled()) {

logger.info("============ getObject key: {}============", key);

}

Object object = null;

Jedis jedis = null;

try {

jedis = RedisStandAloneUtil.getJedisPool().getResource();

byte[] bytes = jedis.get(protostuffSerializer.serialize(key));

if (bytes != null) {

object = protostuffSerializer.deserialize(bytes);

}

} catch (Exception e) {

logger.error(e.getMessage(), e);

} finally {

if (jedis != null) {

jedis.close();

}

}

return object;

}

@Override

public Object removeObject(Object key) {

if (logger.isInfoEnabled()) {

logger.info("============ removeObject key: {}============", key);

}

String result = "success";

Jedis jedis = null;

try {

jedis = RedisStandAloneUtil.getJedisPool().getResource();

jedis.del(String.valueOf(key));

} catch (Exception e) {

logger.error(e.getMessage(), e);

} finally {

if (jedis != null) {

jedis.close();

}

}

return result;

}

@Override

public void clear() {

if (logger.isInfoEnabled()) {

logger.info("============ start clear cache ============");

}

String result = "fail";

Jedis jedis = null;

try {

jedis = RedisStandAloneUtil.getJedisPool().getResource();

result = jedis.flushAll();

} catch (Exception e) {

logger.error(e.getMessage(), e);

} finally {

if (jedis != null) {

jedis.close();

}

}

if (logger.isInfoEnabled()) {

logger.info("============ end clear cache result is {}============", result);

}

}

@Override

public ReadWriteLock getReadWriteLock() {

return readWriteLock;

}

}

(3) mapper配置中加入自定义redis二级缓存:

Xml代码  6e5481f2821bc05cfd2ff3ea59133e46.png

(4) 单元测试同第二节

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值