1. 程式人生 > >springBoot2.0 MyBatis Redis 及RedisCache 整合附demo

springBoot2.0 MyBatis Redis 及RedisCache 整合附demo

springboot2.0 + mybatis 或者 springboot2.0 + redis 在網上可以找到很多資料,但是大都不全或者有這樣那樣的問題,所以便自己動手寫了個demo,能只用 yaml 配置的,儘量不再寫程式碼。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.carlton</groupId>
	<artifactId>MybatisDemo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>MybatisDemo</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.5.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-cache</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>com.hynnet</groupId>
			<artifactId>json-lib</artifactId>
			<version>2.4</version>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

application.yml

---
server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/trymaster?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123123
    driver-class-name: com.mysql.jdbc.Driver
    hikari:   #springboot2.X 預設使用hikari作為資料來源
      minimum-idle: 5
      maximum-pool-size: 15
      connection-test-query: select 1
      max-lifetime: 1800000
      connection-timeout: 30000
      pool-name: HikariDataPool
  redis:
    host: 127.0.0.1
    port: 6379
    password: 123123
    database: 1
    timeout: 60s
    jedis:
      pool:
        max-idle: 50
        min-idle: 5
        max-wait: -1s
        max-active: -1
  transaction:
    rollback-on-commit-failure: true
  cache:
    type: redis
    cache-names: redisCache
    redis:
      time-to-live: 60s
      use-key-prefix: true  
      key-prefix: cacheee  
mybatis:
  mapper-locations: com/carlton/demo/mapper/*.xml
  type-aliases-package: com.carlton.demo.entity
logging:
  level:
    com.carlton.demo.mapper: debug
...

mybatis 因為直接用了springboot配置,不需要重寫配置類。

redis 預設的 RedisTemplate 只支援儲存 RedisTemplate<String, String>,如果希望能儲存物件,則需重寫 RedisTemplate<String, Object>,另外,使用RedisCache的話,為解決亂碼問題,也要重寫CacheManager。

RedisConfig.java

package com.carlton.demo.conf;

import java.time.Duration;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.carlton.demo.util.RedisUtil;
import com.fasterxml.jackson.databind.ObjectMapper;

/***
* <p>Title: RedisConfig</p>  
* <p>Description: reids配置類</p>  
* @author Carlton  
* @date 2018年10月8日 下午4:37:44
 */
@Configuration
@ConfigurationProperties(prefix = "spring.cache.redis")
public class RedisConfig {

	private Duration timeToLive = Duration.ZERO;
	private String keyPrefix;

	/***
	 * 注入封裝RedisTemplate
	 * 
	 * @author Carlton
	 * @date 2018年10月8日 下午4:27:06 
	 * @param redisTemplate
	 * @return
	 */
	@Bean(name = "redisUtil")
	public RedisUtil redisUtil(RedisTemplate<String, Object> redisTemplate) {
		RedisUtil redisUtil = new RedisUtil();
		redisUtil.setRedisTemplate(redisTemplate);
		return redisUtil;
	}

	/***
	 * 例項化 RedisTemplate 物件
	 * 
	 * @author Carlton
	 * @date 2018年10月8日 下午4:27:26 
	 * @param redisConnectionFactory
	 * @return
	 */
	@Bean
	public RedisTemplate<String, Object> functionDomainRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
		RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
		initDomainRedisTemplate(redisTemplate, redisConnectionFactory);

		return redisTemplate;
	}

	/***
	 *  設定資料存入 redis 的序列化方式,並開啟事務
	 *  
	 * @author Carlton
	 * @date 2018年10月8日 下午4:27:18 
	 * @param redisTemplate
	 * @param factory
	 */
	private void initDomainRedisTemplate(RedisTemplate<String, Object> redisTemplate, RedisConnectionFactory factory) {
		// 如果不配置Serializer,那麼儲存的時候預設使用String,如果用User型別儲存,那麼會提示錯誤User can't cast to
		// String!
		redisTemplate.setKeySerializer(new StringRedisSerializer());
		redisTemplate.setHashKeySerializer(new StringRedisSerializer());
		redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
		redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
		redisTemplate.setEnableTransactionSupport(true);
		redisTemplate.setConnectionFactory(factory);
	}

	/***
	 * 自定義 RedisCacheManager 類,主要是設定序列化,解決亂碼問題
	 * 
	 * @author Carlton
	 * @date 2018年10月9日 下午2:46:15 
	 * @param factory
	 * @return
	 */
	@Bean
	public CacheManager cacheManager(RedisConnectionFactory factory) {
		RedisSerializer<String> redisSerializer = new StringRedisSerializer();
		Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(
				Object.class);
		// 解決查詢快取轉換異常的問題
		ObjectMapper om = new ObjectMapper();
//        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		jackson2JsonRedisSerializer.setObjectMapper(om);
		// 配置序列化(解決亂碼的問題)
		RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
				.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
				.serializeValuesWith(
						RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
				.disableCachingNullValues().entryTtl(timeToLive).prefixKeysWith(keyPrefix);

		RedisCacheManager cacheManager = RedisCacheManager.builder(factory).cacheDefaults(config).build();
		return cacheManager;

	}

	public void setTimeToLive(Duration timeToLive) {
		this.timeToLive = timeToLive;
	}

	public void setKeyPrefix(String keyPrefix) {
		this.keyPrefix = keyPrefix;
	}

}

RedisUtil.java

redis工具類,封裝各種常用方法,定義了一個變數 RedisTemplate<String, Object> redisTemplate

private RedisTemplate<String, Object> redisTemplate;

public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
		this.redisTemplate = redisTemplate;
	}

具體程式碼不貼了,有興趣請拉到文末看demo。

myBatis 實體類User 和mapper 省略,不過要注意的是,如果要使用 RedisCache,User 需要實現介面Serializable,否則報錯。

測試類:

MybatisDemoApplicationTests.java

package com.carlton.demo;

import javax.sql.DataSource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import com.carlton.demo.entity.User;
import com.carlton.demo.mapper.UserMapper;
import com.carlton.demo.service.TestService;
import com.carlton.demo.util.RedisUtil;

@RunWith(SpringRunner.class)
@SpringBootTest
@EnableCaching
@ConfigurationProperties(prefix = "spring.cache.redis")
public class MybatisDemoApplicationTests {

	private String keyPrefix;

	@Autowired
	DataSource dataSource;

	@Autowired
	RedisTemplate<String, String> redisTemplate;

	@Autowired
	RedisUtil redisUtil;

	@Autowired
	UserMapper userMapper;

	@Autowired
	TestService testService;

	@Test
	public void test() {
		System.out.println(dataSource.getClass());
	}

	@Test
	public void set() {
		// 測試 redisTemplate
		redisTemplate.opsForValue().set("test:set", "testValue1多噢ffff噢噢噢發生的風");
		String str = redisTemplate.opsForValue().get("test:set");
		System.out.println(str);

		// 測試 redisUtil 存取 String
		redisUtil.set("eeeee", "1123地地道道的");
		str = redisTemplate.opsForValue().get("eeeee");
		System.out.println(str);

		// 測試 reidsUtil 儲存物件
		User user = new User();
		user.setAge(555);
		user.setName("娃哈哈哈哈哈");
		user.setId(55);
		redisUtil.set("user:login", user);
	}

	@Test
	public void cacheeMybatis() {
		System.out.println("=============================測試cache 從資料庫取=============================");
		int id = 9;
		User user = userMapper.selectByPrimaryKey(id);
		System.out.println("-------------" + user.getId() + "-------------");

		Object obj = redisUtil.get(keyPrefix + id);
		System.out.println(obj.toString());
		User user2 = (User) obj;
		System.out.println(user2.getName());

	}

	@Test
	public void cachee() {
		System.out.println("=============================測試cache2 自定義生成=============================");
		testService.testPrint();
		User user = testService.gener(99, "qqq", 55);
		System.out.println("-------------" + user.getId() + "-------------");
	}

	public void setKeyPrefix(String keyPrefix) {
		this.keyPrefix = keyPrefix;
	}

}

專案demo: