项目开发时遇到需要去防止两个服务同时跑一个功能时而导致公用的一个表出现数据错误的问题,领导说了几个解决方案redis是唯一一个听过的就赶紧学了一下,因为并未去很好的浏览项目结构刚开始绕了很大一圈,自己创建连接池配置文件引pom啥的,结果发现都是已经搭好的,但也对redis有了更深的认识,先贴下代码
application的配置
#Jedis版本 #redis.server.host=66666666.666.66.66 #redis.server.port=6666 #redis.server.password= #redis.server.timeOut=3000 #redis.server.maxIdle=50 #redis.server.maxWaitMillis=5000 #redis.server.maxTotal=500
pom.xml
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
连接的属性
import org.springframework.boot.context.properties.ConfigurationProperties; /** * ClassName JedisProperties * Description TODO * * @Author * @Version **/ @ConfigurationProperties(prefix = JedisProperties.JEDIS_PREFIX) public class JedisProperties { public static final String JEDIS_PREFIX = "redis.server"; private String host; private int port; private String password; private int maxTotal; private int maxIdle; private int maxWaitMillis; private int timeOut; public int getTimeOut() { return timeOut; } public void setTimeOut(int timeOut) { this.timeOut = timeOut; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getHost() { return host; } public void setHost(String host) { this.host = host; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public int getMaxTotal() { return maxTotal; } public void setMaxTotal(int maxTotal) { this.maxTotal = maxTotal; } public int getMaxIdle() { return maxIdle; } public void setMaxIdle(int maxIdle) { this.maxIdle = maxIdle; } public int getMaxWaitMillis() { return maxWaitMillis; } public void setMaxWaitMillis(int maxWaitMillis) { this.maxWaitMillis = maxWaitMillis; } }
创建连接池Bean
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; /** * ClassName JedisConfig * Description TODO * * @Author * @Version **/ @Configuration @EnableConfigurationProperties(JedisProperties.class) @ConditionalOnClass(JedisClientSingle.class) public class JedisConfig { private Logger logger = LoggerFactory.getLogger(JedisConfig.class); @Autowired private JedisProperties prop; @Bean(name = "jedisPool") public JedisPool jedisPool() { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(prop.getMaxTotal()); config.setMaxIdle(prop.getMaxIdle()); config.setMaxWaitMillis(prop.getMaxWaitMillis()); return new JedisPool(config, prop.getHost(), prop.getPort(), prop.getTimeOut(), prop.getPassword()); } @Bean @ConditionalOnMissingBean(JedisClientSingle.class) public JedisClientSingle redisClient(@Qualifier("jedisPool") JedisPool pool) { logger.info("当当当当~~~~~Redis Client==Host={},Port={}", prop.getHost(), prop.getPort()); JedisClientSingle redisClient = new JedisClientSingle(); redisClient.setJedisPool(pool); return redisClient; } }
连接pool的操作类(这地方借鉴了很多帖子的方法,揉到一起了)
import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import java.util.List; /** * ClassName JedisClientSingle * Description TODO * * @Author * @Version **/ public class JedisClientSingle { private JedisPool jedisPool; public String get(String key) { Jedis jedis = jedisPool.getResource(); String string = jedis.get(key); jedis.close(); return string; } public String set(String key, String value) { Jedis jedis = jedisPool.getResource(); String string = jedis.set(key, value); jedis.close(); return string; } public String hget(String hkey, String key) { Jedis jedis = jedisPool.getResource(); String string = jedis.hget(hkey, key); jedis.close(); return string; } public long hset(String hkey, String key, String value) { Jedis jedis = jedisPool.getResource(); Long result = jedis.hset(hkey, key, value); jedis.close(); return result; } public long incr(String key) { Jedis jedis = jedisPool.getResource(); Long result = jedis.incr(key); jedis.close(); return result; } public long expire(String key, int second) { Jedis jedis = jedisPool.getResource(); Long result = jedis.expire(key, second); jedis.close(); return result; } public long ttl(String key) { Jedis jedis = jedisPool.getResource(); Long result = jedis.ttl(key); jedis.close(); return result; } public void deleteByKey(String key){ Jedis jedis = jedisPool.getResource(); jedis.del(key); jedis.close(); } /**SerializeUtil.serializeList(list) * 设置List集合 * @param key * @param list */ public void setList(String key ,List<?> list){ Jedis jedis = jedisPool.getResource(); try { if(list == null || list.size() == 0){ jedis.set(key.getBytes(), "".getBytes()); }else{//如果list为空,则设置一个空 jedis.set(key.getBytes(), SerializeUtil.serialize(list)); } } catch (Exception e) { e.printStackTrace(); } finally { jedis.close(); } } /** * 获取List集合 * @param key * @return */ public List<?> getList(String key){ Jedis jedis = jedisPool.getResource(); if(jedis == null || !jedis.exists(key)){ return null; } byte[] data = jedis.get(key.getBytes()); jedis.close(); return SerializeUtil.unserializeForList(data); } public JedisPool getJedisPool() { return jedisPool; } public void setJedisPool(JedisPool jedisPool) { this.jedisPool = jedisPool; } }
工具类(借鉴自其他帖子)
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; /** * ClassName SerializeUtil * Description redis工具类 序列化对象工具类,用于保存和读取redis数据使用 * * @Author * @Version **/ public class SerializeUtil { private static Logger log = LoggerFactory.getLogger(SerializeUtil.class); /** * 序列化对象 * @param object * @return */ public static byte[] serialize(Object object) { ObjectOutputStream oos = null; ByteArrayOutputStream baos = null; byte[] bytes = null; try { // 序列化 baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); oos.writeObject(object); bytes = baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (oos != null) { oos.close(); } if (baos != null) { baos.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return bytes; } /** * 反序列化对象 * @param bytes * @return */ public static Object unserialize(byte[] bytes) { Object obj = null; ByteArrayInputStream bais = null; try { // 反序列化 bais = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(bais); obj = ois.readObject(); ois.close(); bais.close(); } catch (Exception e) { e.printStackTrace(); } return obj; } /** * 关闭的数据源或目标。调用 close()方法可释放对象保存的资源(如打开文件) * 关闭此流并释放与此流关联的所有系统资源。如果已经关闭该流,则调用此方法无效。 * @param closeable */ public static void close(Closeable closeable) { if (closeable != null) { try { closeable.close(); } catch (Exception e) { log.info("Unable to close %s", closeable, e); } } } /** * 列表序列化(用于Redis整存整取) * @param value * @return */ public static <T> byte[] serialize(List<T> value) { if (value == null) { throw new NullPointerException("Can't serialize null"); } byte[] rv=null; ByteArrayOutputStream bos = null; ObjectOutputStream os = null; try { bos = new ByteArrayOutputStream(); os = new ObjectOutputStream(bos); for(T obj : value){ os.writeObject(obj); } os.writeObject(null); os.close(); bos.close(); rv = bos.toByteArray(); } catch (IOException e) { throw new IllegalArgumentException("Non-serializable object", e); } finally { close(os); close(bos); } return rv; } /** * 反序列化列表(用于Redis整存整取) * @param in * @return */ public static <T> List<T> unserializeForList(byte[] in) { List<T> list = new ArrayList<T>(); ByteArrayInputStream bis = null; ObjectInputStream is = null; try { if(in != null) { bis=new ByteArrayInputStream(in); is=new ObjectInputStream(bis); while (true) { T obj = (T) is.readObject(); if(obj == null){ break; }else{ list.add(obj); } } is.close(); bis.close(); } } catch (IOException e) { log.warn("Caught IOException decoding %d bytes of data", in == null ? 0 : in.length, e); } catch (ClassNotFoundException e) { log.warn("Caught CNFE decoding %d bytes of data", in == null ? 0 : in.length, e); } finally { close(is); close(bis); } return list; } }
在需要使用的类中注入或者创建类,有的地方注入会报错,需要给类添加@Component // @Autowired // private JedisClientSingle jedisClient; // // private JedisShardInfo jedisShardInfo; //Jedis版本 // if (CollectionUtils.isNotEmpty(list)) { // //放到redis,将查询的accountList // jedisClient.setList("getAccountList", list); // //设置过期(单位:秒) // jedisClient.expire("getAccountList",600); // } // redisTemplate.setConnectionFactory((RedisConnectionFactory) jedisClient.getJedisPool()); // //删除key // jedisClient.deleteByKey("getAccountList"); // //取redis // List<Map> listAccount = (List<Map>) jedisClient.getList("getAccountList");
删除key是测试时自用的,现在Jedis版本的是好用了,然后百度时发现现在已经是springboot2.0版本了,reids的使用和api也有更好的选择,我就全局搜了一下项目中竟然有,然后就开始了把这个版本的改成RedisTemplate版本的,这个是通过pom。xml引的一些架包,貌似是对Jedis进行了进一步的封装,不用在配置连接池它会自动去创建,只需要把连接池的一些属性配置好即可,和这个Jedis的一比简直是方便很多,贴下代码。
#Redis配置 spring.redis.database=0 spring.redis.host=666.6666.666 spring.redis.port=66666 spring.redis.timeout=3000 spring.redis.pool.max-active=8 spring.redis.pool.max-wait=-1 spring.redis.pool.max-idle=8 spring.redis.pool.min-idle=0
pom.xml(看着比较像的,因为是项目自带的可能会有遗漏建议你们再百度一下)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>1.5.13.RELEASE</version> </dependency>
应用
if (CollectionUtils.isNotEmpty(list)) { //放到redis,将查询的accountList(不分库) redisTemplate.opsForList().leftPush("getAccountList",list); //设置过期(单位:分钟) redisTemplate.expire("getAccountList",5, TimeUnit.MINUTES); } //取redis List<Map> listAccount = (List<Map>) redisTemplate.opsForList().leftPop("getAccountList");
if (stringRedisTemplate.hasKey(getAccountList)) {
}
这个redisTemplate里封装了对redis各个类型的方法,然后我是只用了list,这个list有left和right的区别是遍历时的区别,反正其他帖子的楼主是建议若是leftPush存的,就从leftPop去,尽量不要left和right混合使用。若是需要判断key是否为空就可以用下面的那个String的,是对redisTemplate的一个封装类,借鉴中的帖子解释的更好这里就不赘述了,下面贴上借鉴的帖子,谢谢这些楼主。
https://blog.csdn.net/u010473656/article/details/78838254
https://blog.csdn.net/bcqtt/article/details/72286359
https://www.cnblogs.com/superfj/p/9232482.html
https://blog.csdn.net/lichuangcsdn/article/details/80866182
//--redisTemplate对比stringRedisTemplate
https://blog.csdn.net/Abysscarry/article/details/80557347