Spring Boot+Mybatis+Redis二级缓存2

集成Mybatis

配置数据源

首先我们需要在配置文件中配置我们的数据源。我们采用mysql作为我们的数据库。这里我们采用yaml作为我们配置文件的格式。我们在resources目录下新建application.yml文件:

spring:

# 数据库配置

datasource:

url: jdbc:mysql:///

username:

password:

由于Spring Boot拥有自动配置的特性,我们不用新建一个DataSource的配置类,Sping Boot会自动加载配置文件并且根据配置文件的信息建立数据库的连接池,十分便捷。

笔者推荐大家采用yaml作为配置文件的格式。xml显得冗长,properties没有层级结构,yaml刚好弥补了这两者的缺点。这也是Spring Boot默认就支持yaml格式的原因。

配置Mybatis

我们已经通过Spring Initializer在pom.xml中引入了mybatis-spring-boot-starte库,该库会自动帮我们初始化mybatis。首先我们在application.yml中填写mybatis的相关配置:

# mybatis配置

mybatis:

# 配置映射类所在包名

# 配置mapper xml文件所在路径,这里是一个数组

mapper-locations:

- mappers/ProductMapper.xml

然后,再在代码中定义ProductMapper类:

@Mapper

public interface ProductMapper {

Product select(

@Param("id")

long id);

void update(Product product);

}

这里,只要我们加上了@Mapper注解,Spring Boot在初始化mybatis时会自动加载该mapper类。

Spring Boot之所以这么流行,最大的原因是它自动配置的特性。开发者只需要关注组件的配置(比如数据库的连接信息),而无需关心如何初始化各个组件,这使得我们可以集中精力专注于业务的实现,简化开发流程。

访问数据库

完成了Mybatis的配置之后,我们就可以在我们的接口中访问数据库了。我们在ProductController下通过@Autowired引入mapper类,并且调用对应的方法实现对product的查询和更新操作,这里我们以查询接口为例:

@RestController

@RequestMapping("/product")

public class ProductController {

@Autowired

private ProductMapper productMapper;

@GetMapping("/")

public Product getProductInfo(

@PathVariable("id")

Long productId) {

return productMapper.select(productId);

}

// 避免篇幅过长,省略updateProductInfo的代码

}

然后在你的mysql中插入几条product的信息,就可以运行该项目看看是否能够查询成功了。

至此,我们已经成功地在项目中集成了Mybatis,增添了与数据库交互的能力。但是这还不够,一个现代化的Web项目,肯定会上缓存加速我们的数据库查询。接下来,将介绍如何科学地将Redis集成到Mybatis的二级缓存中,实现数据库查询的自动缓存。

集成Redis

配置Redis

同访问数据库一样,我们需要配置Redis的连接信息。在application.yml文件中增加如下配置:

spring:

redis:

# redis数据库索引(默认为0),我们使用索引为3的数据库,避免和其他数据库冲突

database: 3

# redis服务器地址(默认为localhost)

host: localhost

# redis端口(默认为6379)

port: 6379

# redis访问密码(默认为空)

password:

# redis连接超时时间(单位为毫秒)

timeout: 0

# redis连接池配置

pool:

# 最大可用连接数(默认为8,负数表示无限)

max-active: 8

# 最大空闲连接数(默认为8,负数表示无限)

max-idle: 8

# 最小空闲连接数(默认为0,该值只有为正数才有作用)

min-idle: 0

# 从连接池中获取连接最大等待时间(默认为-1,单位为毫秒,负数表示无限)

max-wait: -1

将Redis作为二级缓存

Mybatis的二级缓存原理本文不再赘述,读者只要知道,Mybatis的二级缓存可以自动地对数据库的查询做缓存,并且可以在更新数据时同时自动地更新缓存。

该接口共有以下五个方法:

·String getId():mybatis缓存操作对象的标识符。一个mapper对应一个mybatis的缓存操作对象。

·void putObject(Object key, Object value):将查询结果塞入缓存。

·Object getObject(Object key):从缓存中获取被缓存的查询结果。

·void clear():发生更新时,清除缓存。

·int getSize():可选实现。返回缓存的数量。

·ReadWriteLock getReadWriteLock():可选实现。用于实现原子性的缓存操作。

接下来,我们新建RedisCache类,实现Cache接口:

public class RedisCache implements Cache {

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

private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

private final String id; // cache instance id

private RedisTemplate redisTemplate;

private static final long EXPIRE_TIME_IN_MINUTES = 30; // redis过期时间

public RedisCache(String id) {

if (id == null) {

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

}

this.id = id;

}

@Override

public String getId() {

return id;

}

/**

* Put query result to redis

*

* @param key

* @param value

*/

@Override

@SuppressWarnings("unchecked")

public void putObject(Object key, Object value) {

RedisTemplate redisTemplate = getRedisTemplate();

ValueOperations opsForValue = redisTemplate.opsForValue();

opsForValue.set(key, value, EXPIRE_TIME_IN_MINUTES, TimeUnit.MINUTES);

logger.debug("Put query result to redis");

}

/**

* Get cached query result from redis

*

* @param key

* @return

*/

@Override

public Object getObject(Object key) {

RedisTemplate redisTemplate = getRedisTemplate();

ValueOperations opsForValue = redisTemplate.opsForValue();

logger.debug("Get cached query result from redis");

return opsForValue.get(key);

}

/**

* Remove cached query result from redis

*

* @param key

* @return

*/

@Override

@SuppressWarnings("unchecked")

public Object removeObject(Object key) {

RedisTemplate redisTemplate = getRedisTemplate();

redisTemplate.delete(key);

logger.debug("Remove cached query result from redis");

return null;

}

/**

* Clears this cache instance

*/

@Override

public void clear() {

RedisTemplate redisTemplate = getRedisTemplate();

redisTemplate.execute((RedisCallback) connection -> {

connection.flushDb();

return null;

});

logger.debug("Clear all the cached query result from redis");

}

@Override

public int getSize() {

return 0;

}

@Override

public ReadWriteLock getReadWriteLock() {

return readWriteLock;

}

private RedisTemplate getRedisTemplate() {

if (redisTemplate == null) {

redisTemplate = ApplicationContextHolder.getBean("redisTemplate");

}

return redisTemplate;

}

}

讲解一下上述代码中一些关键点:

1.自己实现的二级缓存,必须要有一个带id的构造函数,否则会报错。

2.我们使用Spring封装的redisTemplate来操作Redis。网上所有介绍redis做二级缓存的文章都是直接用jedis库,但是笔者认为这样不够Spring Style,而且,redisTemplate封装了底层的实现,未来如果我们不用jedis了,我们可以直接更换底层的库,而不用修改上层的代码。更方便的是,使用redisTemplate,我们不用关心redis连接的释放问题,否则新手很容易忘记释放连接而导致应用卡死。

3.需要注意的是,这里不能通过autowire的方式引用redisTemplate,因为RedisCache并不是Spring容器里的bean。所以我们需要手动地去调用容器的getBean方法来拿到这个bean,具体的实现方式请参考Github中的代码。

4.我们采用的redis序列化方式是默认的jdk序列化。所以数据库的查询对象(比如Product类)需要实现Serializable接口。

这样,我们就实现了一个优雅的、科学的并且具有Spring Style的Redis缓存类。

需要JAVA视频资料的请复制以下代码粘贴网址:

data:text/html;charset=UTF-8;base64,

5oGt5Zac5L2g77yM5p625p6E5biI5a2m5Lmg576k5Y+35pivNTc1NzUxODU0Cg==

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180111A06AET00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励