Redis详解

使用redis遇到了 Could not connect to Redis at 127.0.0.1:6379: Connection refused 错误 当我们直接连接 redis 时,会遇到 Could not connect to Redis at 127.0.0.1:6379: Connection refused 这个问题,显示连接被拒绝。是因为没有启动 redis 的服务端,所以我们的 redis 连接不到他的服务,需要启动 redis服端。如图,这是 redis 目录,找到 redis-server 和 redis.conf 这两个目录。我们在命令行启动这两个文件,然后启动 redis 客户端就可以成功了。 阅读详情

Jedis

1. Jedis 是 Redis 官方首选的 Java 客户端开发包。

Jedis源码地址https://github.com/xetorthio/jedis/release

其相关jar可以从maven的中央仓库中下载:
http://central.maven.org/maven2/redis/clients/jedis/2.9.0/jedis-2.9.0.jar

2.jedis的相关jar包

在java中使用jedis中的api操作redis的时候所需jar包主要有俩个:
	jedis-2.x.jar
	commons-pool2-2.4.2.jar

另外需要一个junit的包进行单元测试:
	junit-4.x.jar

3.Jedis对象的使用

整个过程类似之前使用Connection对象一样,一个Jedis对象就是一个数据库连接对象,这不过这个数据库是Redis(内存数据库)

1)创建Jedis对象

	Jedis jedis = new Jedis();
	或者:
	Jedis jedis = new Jedis("127.0.0.1",6379);
	或者:
	Jedis jedis = new Jedis(new java.net.URI("redis://:passwd@127.0.0.1:6379/0"));
	注意:这里最后一个0代表的时候index为0的数据库
	
	如果没有密码的时候可以这样创建对象
	Jedis jedis = new Jedis(new java.net.URI("redis://127.0.0.1:6379/0"));

2)使用Jedis对象

	使用Jedis的API对redis进行操作,Jedis中的方法名和Redis中命令名基本上一模一样,所以只要了解Redis中命令的作用,那么Jedis中对应的方法的作用也是一样的.

3)关闭Jedis对象

	每个Jedis对象在内部都会建立一个Socket和Redis服务器连接,所以Jedis对象使用完毕后可以进行关闭。


所以在使用junit进行基本的jedis操作测试的时候,可以编写如下代码:
public class RedisTest {
	private Jedis jedis;
	@Before
	public void before(){
		jedis = new Jedis();
	}
	@After
	public void after(){
		jedis.close();
	}
	
	@Test
	public void test(){
		//使用jedis对进行操作
	}
	
}

意思是,在单元测试方法执行之前,junit先调用使用了@Before注解的方法,然后再调用使用了@Test注解的方法,最后再调用使用了@After注解的方法

4.Jedis对Redis中key的操作

@Test
	public void test_key(){
		//选择数据库 默认是0
		System.out.println(jedis.select(0));
		//查看当前数据库
		System.out.println(jedis.getDB());
		//查看当前数据库中所有key值
		System.out.println(jedis.keys("*"));
		//判断当前数据库中是否存在名字为name的key值
		System.out.println(jedis.exists("name"));
		//判断key值的在Redis中的数据类型
		System.out.println(jedis.type("name"));
		//查看key的过期时间 单位是毫秒 -1表示永不过期 -2表示已经过去
		System.out.println(jedis.pttl("name"));
		//查看key的过期时间 单位是秒   -1表示永不过期 -2表示已经过去
		System.out.println(jedis.ttl("name"));
		//修改key的名字 不管新名字是否被使用 如果老的key不存在会报错
		System.out.println(jedis.rename("name", "username"));
		//修改key的名字 新名字没有被使用的时候才生效 如果老的key不存在会报错
		System.out.println(jedis.renamenx("username", "name"));
		//把指定的key移动到指定的数据库中(数据库索引表示)
		System.out.println(jedis.move("name",3));
		//在当前数据库中随机获取一个key
		System.out.println(jedis.randomKey());
		//设置指定key的过期时间 单位是秒
		System.out.println(jedis.expire("name", 10));
		//设置指定key的过期时间 单位是毫秒
		System.out.println(jedis.pexpire("name", 5000L));
		//设置指定key的过期时间 时间用时间戳表示
		System.out.println(jedis.expireAt("name", 1000000L));
		//在指定的key过期之前,移除key上的过期时间
		System.out.println(jedis.persist("name"));
		
		//当前数据库中key的数量 返回值Long类型
		jedis.dbSize();
		//清空当前db
		jedis.flushDB();
		//清空所有db
		jedis.flushAll();
	}

5.Jedis对Redis中string的操作

@Test
	public void test_String(){
		//设置k-v的值,如果k已经则会覆盖旧值,且无视数据类型
		System.out.println(jedis.set("name", "zhangsan"));
		//获得指定key的值
		System.out.println(jedis.get("name"));
		//通过下标截取指定key的值
		System.out.println(jedis.getrange("name", 0, 3));
		//替换key值,并且返回旧值
		System.out.println(jedis.getSet("name", "briup"));
		//可以连续设置多组K-V
		System.out.println(jedis.mset("name","briup","age","20"));
		//获得多个key分别对应的值
		System.out.println(jedis.mget("name","age"));
		//设置K-V的同时设置一下过期时间,单位是秒
		System.out.println(jedis.setex("password", 10, "123"));
		//设置K-V的同时设置一下过期时间,单位是毫秒
		System.out.println(jedis.psetex("myname", 10000L, "test"));
		//设置K-V,只有指定的key没有被使用的时候才生效
		System.out.println(jedis.setnx("name","tom"));
		//连续设置多组K-V,只有在所有指定的key都没有被使用的时候才生效
		System.out.println(jedis.msetnx("a","testA","b","testB"));
		//使用第三个参数的值,从下标为3的位置开始覆盖指定key的值
		System.out.println(jedis.setrange("name", 3, "aaaa"));
		//返回指定key的值的长度
		System.out.println(jedis.strlen("name"));
		//指定的值自增1 num的值必须是整数
		System.out.println(jedis.incr("num"));
		//指定的值自增5 num的值必须是整数
		System.out.println(jedis.incrBy("num",5));
		//指定的值自减1 num的值必须是整数
		System.out.println(jedis.decr("num"));
		//指定的值自减5 num的值必须是整数
		System.out.println(jedis.decrBy("num", 5));
		//指定的值自增10.5 
		System.out.println(jedis.incrByFloat("num", 10.5));
		//指定的key的值后面进行追加
		System.out.println(jedis.append("name", "gogogo"));
	}

6.Jedis对Redis中hash的操作

@Test
	public void test_Hash(){
		//为哈希表中的字段赋值
		//给key为user的hash表中的name字段赋值为briup
		System.out.println(jedis.hset("user", "name", "briup"));
		//为哈希表中的字段赋值 字段name不存在是才生效
		System.out.println(jedis.hsetnx("user", "name", "tom"));
		//连续为哈希表中的多个字段赋值
		Map<String,String> map = new HashMap<>();
		map.put("age", "20");
		map.put("dob", "2016-11-11");
		System.out.println(jedis.hmset("user",map));
		//获得名字为user的hash表中指定字段的值
		System.out.println(jedis.hget("user", "name"));
		//连续获得名字为user的hash表中多个字段的值
		System.out.println(jedis.hmget("user", "age","dob"));
		//获得名字为user的hash表中所有字段的值
		System.out.println(jedis.hgetAll("user"));
		//检查名字为user的hash表中指定字段是否存在
		System.out.println(jedis.hexists("user", "name"));
		//获得名字为user的hash表中字段的个数
		System.out.println(jedis.hlen("user"));
		//删除名字为user的hash表中的指定字段,同时忽略掉不存在的字段
		System.out.println(jedis.hdel("user", "dob","f1","f2"));
		//获得名字为user的hash表中所有的字段名
		System.out.println(jedis.hkeys("user"));
		//获得名字为user的hash表中所有的字段值
		System.out.println(jedis.hvals("user"));
		//名字为user的hash表中的age字段值自增1
		System.out.println(jedis.hincrBy("user", "age", 1L));
		//名字为user的hash表中的age字段值自增10.5
		System.out.println(jedis.hincrByFloat("user", "age", 10.5));
	}

7.Jedis对Redis中其他类型的操作

Jedis对Redis中list的操作
Jedis对Redis中set的操作
Jedis对Redis中zset的操作
和Redis中的命令名字及用户一样,这里就不再一一列举

8.Jedis处理Redis中的事务

Transaction tx = jedis.multi();

	//操作数据

	//List集合中是每个操作返回的执行结果
	List<Object> results = tx.exec();

	例如:

	@Test
	public void test_List(){
		//开启事务之后 要是tx来操作,而不是jedis对象
		Transaction tx = jedis.multi();
		tx.set("age", "20");
		tx.set("test", "test");
		Response<String> response = tx.get("name");
		
		//返回值是List集合,里面是每个操作的执行结果
		tx.exec();
		
		//事务中查询到的数据 要到事务结束后再拿出结果
		System.out.println(response.get());
	}

9.JedisPool的使用(连接池)

在不同的线程中使用相同的Jedis实例会发生并发访问问题。但是创建太多的Jedis实例也不好,因为这意味着会建立很多Socket连接。单一Jedis实例不是线程安全的。为了避免这些问题,可以使用JedisPool, JedisPool是一个线程安全的网络连接池。可以用JedisPool创建一些可靠Jedis实例,可以从池中拿到Jedis的实例。 这种方式可以解决那些问题并且会实现高效的性能

1)创建JedisPool

JedisPool pool = new JedisPool();
		或者
		JedisPool pool = new JedisPool("127.0.0.1",6379);
		或者
		JedisPoolConfig config = new JedisPoolConfig();  
		//设置最大连接数
		config.setMaxTotal(80);
		//设置最大空闲数
		config.setMaxIdle(20);
		//设置超时时间
		config.setMaxWaitMillis(3000);
		JedisPool jedisPool = new JedisPool(config, "127.0.0.1", 6379); 

2)使用JedisPool获得Jedis对象

JedisPool pool = new JedisPool();
		Jedis jedis = pool.getResource();

3)从JedisPool获得的Jedis对象再使用后调用close方法即可

	通过查看源码可知,close方法内部会把这个jedis对象进回收
public void close(){
			if (this.dataSource != null) {
				if (this.client.isBroken())
					this.dataSource.returnBrokenResource(this);
				else
					this.dataSource.returnResource(this);
			}else{
				this.client.close();
			}
		}

10.使用Jedis存储java对象

Jedis类继承了BinaryJedis类
Jedis中的方法的参数基本上全都是String类型,BinaryJedis类中的方法参数基本全都是byte[]类型的,所以Jedis对象也可以调用那些可以接受byte[]类型参数的方法,而且java中的任何可以被序列化的对象都可以转换为字节数组.

1)创建工具类SerializingUtils

负责把对象和byte[]之间进行转换
public class SerializingUtils {
	
		public static byte[] serialize(Object obj) {
			ByteArrayOutputStream bos = null;
			ObjectOutputStream out = null;
			try {
				bos = new ByteArrayOutputStream();
				out = new ObjectOutputStream(bos);
				out.writeObject(obj);
				out.flush();
			}
			catch (IOException e) {
				e.printStackTrace();
			}finally {
				try {
					if(out!=null)out.close();
				}catch (IOException e) {
					e.printStackTrace();
				}
			}
			return bos.toByteArray();
		}
		
		public static Object deserialize(byte[] data) {
			ObjectInputStream in = null;
			Object obj = null;
			try {
				ByteArrayInputStream bis = new ByteArrayInputStream(data);
				in = new ObjectInputStream(bis);
				obj = in.readObject();
			}catch (Exception e) {
				e.printStackTrace();
			}finally {
				try {
					if(in!=null)in.close();
				}catch (IOException e) {
					e.printStackTrace();
				}
			}
			return obj;
		}
		
	}

2)创建工具类JedisUtils

把Jedis对Redis的操作进行封装,使其更加方便使用,例如可以直接存/取java对象,要求对象实现序列化接口,同时也可以使用之前的Jedis相关方法

src下面的资源文件redis.properties
redis.pool.maxTotal=100
	redis.pool.maxIdle=20
	redis.pool.maxWait=3000
	redis.ip=127.0.0.1
	redis.port=6379

	封装的工具类:
	注意:这里只时封装了几个方法,可以根据自己的实现需求而进一步的封装扩展
	public class JedisUtils {
		public static JedisPool jedisPool;

		static {
			//ResourceBundle会查找classpath下的xxx.properties的文件,xxx是方法中指定的
			ResourceBundle resourceBundle = ResourceBundle.getBundle("redis");
			int maxTotal = Integer.parseInt(resourceBundle.getString("redis.pool.maxTotal"));
			int maxIdle = Integer.parseInt(resourceBundle.getString("redis.pool.maxIdle"));
			int maxWait = Integer.parseInt(resourceBundle.getString("redis.pool.maxWait"));
			String ip = resourceBundle.getString("redis.ip");
			int port = Integer.parseInt(resourceBundle.getString("redis.port"));

			JedisPoolConfig config = new JedisPoolConfig();
			// 设置最大连接数
			config.setMaxTotal(maxTotal);
			// 设置最大空闲数
			config.setMaxIdle(maxIdle);
			// 设置超时时间
			config.setMaxWaitMillis(maxWait);
			// 初始化连接池
			jedisPool = new JedisPool(config, ip, port);

		}
		
		public static void set(Object key, Object value) {
			Jedis jedis = null;
			try {
				jedis = jedisPool.getResource();
				jedis.set(SerializingUtils.serialize(key), SerializingUtils.serialize(value));
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				jedis.close();
			}
		}

		
		public static Object get(Object key) {
			Jedis jedis = null;
			try {
				jedis = jedisPool.getResource();
				byte[] keyBytes = SerializingUtils.serialize(key);
				if(jedis.exists(keyBytes)){
					return SerializingUtils.deserialize(jedis.get(keyBytes));
				}
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				jedis.close();
			}
			return null;
		}
		
		public static void del(Object key) {
			Jedis jedis = null;
			try {
				jedis = jedisPool.getResource();
				jedis.del(SerializingUtils.serialize(key));
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				jedis.close();
			}
		}
		
		public static void clear() {
			Jedis jedis = null;
			try {
				jedis = jedisPool.getResource();
				jedis.flushDB();
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				jedis.close();
			}
		}
		public static int getSize() {
			Jedis jedis = null;
			try {
				jedis = jedisPool.getResource();
				
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				jedis.close();
			}
			return jedis.dbSize().intValue();
		}
		
		public static Jedis getResource(){
			return jedisPool.getResource();
		}

	}

11.Redis和mybatis结合

注意:Jedis是用来操作Redis的

mybatis缓存分为一级缓存和二级缓存

一级缓存,又叫本地缓存,是PerpetualCache类型的永久缓存,保存在执行器中(BaseExecutor),而执行器又在SqlSession(DefaultSqlSession)中,所以一级缓存的生命周期与SqlSession是相同的。

二级缓存,又叫自定义缓存,实现了Cache接口的类都可以作为二级缓存,所以可配置如encache等的第三方缓存。二级缓存以namespace名称空间为其唯一标识,被保存在Configuration核心配置对象中。

所以我们可以自定义缓存类,实现Mybatis提供的缓存接口Cache,其中的方法使用Jedis来实现,然后把这个缓存实现类配置为Mybatis的二级缓存提供者即可

1)建表语句及实体类

create table t_user(
		id number primary key,
		name varchar2(50) not null,
		age number,
		dob date
	);

	public class User implements Serializable{
		private static final long serialVersionUID = 1L;
		private long id;
		private String name;
		private int age;
		private Date dob;
		

		get/set
	}

2)Mybatis配置文件及config.properties文件

src下面的mybatis-config.xml文件:


	<?xml version="1.0" encoding="UTF-8"?>
	<!DOCTYPE configuration PUBLIC 
		"-//mybatis.org//DTD Config 3.0//EN" 
		"http://mybatis.org/dtd/mybatis-3-config.dtd">
	<configuration>
		<properties resource="config.properties"></properties>
		
		<settings>
			<!-- 开启二级缓存 -->
			<setting name="cacheEnabled" value="true"/>
			<!-- 禁止延迟加载 -->
			<setting name="lazyLoadingEnabled" value="false" />  
		</settings>
		
		<typeAliases>
			<package name="com.briup.bean"/>
		</typeAliases>
		
		<environments default="development">
			<environment id="development">
				<transactionManager type="JDBC"></transactionManager>
				<dataSource type="POOLED">
					<property name="driver" value="${driver}" /> 
					<property name="url" value="${url}" /> 
					<property name="username" value="${username}" />
					<property name="password" value="${password}" />
				</dataSource>
			</environment>
		</environments>
		
		<mappers>
			<mapper resource="com/briup/dao/UserMapper.xml"/>
		</mappers>
		
	</configuration>

src下面的config.properties文件

driver=oracle.jdbc.driver.OracleDriver
	url=jdbc:oracle:thin:@127.0.0.1:1521:XE
	username=zld
	password=zld
3)Mybatis映射接口和映射文件
映射接口:
public interface UserMapper {
		public void insertUser(User user);
		public List<User> findAllUsers();
	}

映射文件:

<?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.briup.dao.UserMapper">
		<cache type="com.briup.cache.MybatisRedisCache"></cache>
		
		<insert id="insertUser" parameterType="User">
			<selectKey resultType="long" keyProperty="id" order="BEFORE">
				select my_seq.nextval from dual
			</selectKey>
			insert into t_user(id,name,age,dob) 
			values(#{id},#{name},#{age},#{dob})
		</insert>
		
		<select id="findAllUsers" resultType="User">
			select id,name,age,dob
			from t_user
		</select>
		
	</mapper>

4)Jedis相关配置文件和工具类

src下面的config.properties

封装Jedis的工具类
JedisUtils.java
SerializingUtils.java
封装MyBatis的工具类
MyBatisSqlSessionFactory.java

5)自定义cache接口实现类MybatisRedisCache.java

package com.briup.cache;
	import java.util.concurrent.locks.ReadWriteLock;
	import org.apache.ibatis.cache.Cache;
	import org.apache.ibatis.cache.CacheException;
	import com.briup.util.JedisUtils;
	import redis.clients.jedis.Jedis;
	/**
	 * Cache为缓存接口,给缓存供应商的SPI(Service Provider Interface)
	 * Cache接口的实现类必须有一个具有String类型参数的构造方法,该参数作为实现类对象的id,对其进行唯一标识
	 */
	public class MybatisRedisCache implements Cache{

		private String id;
		
		public MybatisRedisCache(String id) {
			this.id = id;
		}
		
		/**
		 * 清空缓存
		 */
		@Override
		public void clear() {
			JedisUtils.clear();
		}
		
		/**
		 * 获取缓存对象的唯一标识
		 */
		@Override
		public String getId() {
			return this.id;
		}
		
		/**
		 * 从缓存对象中获取key对应的value
		 */
		@Override
		public Object getObject(Object key) {
			return JedisUtils.get(key);
		}
		
		
		/**
		 * 获取读写锁
		 * 可选的方法,从3.2.6起这个方法不再被框架核心调用
		 * 任何需要的锁,都必须由缓存供应商提供
		 */
		@Override
		public ReadWriteLock getReadWriteLock() {
			
			return null;
		}
		
		/**
		 * 获取缓存对象中存储的键/值对的数量
		 * 可选的方法,没有被框架核心调用
		 */
		@Override
		public int getSize() {
			return JedisUtils.getSize();
		}
		
		/**
		 * 保存key/value到缓存对象中
		 * key可以是任何对象
		 */
		@Override
		public void putObject(Object key, Object value) {
			JedisUtils.set(key, value);
		}
		
		
		/**
		 * 可选的方法,没有被核心框架调用,移除key对应的value
		 */
		@Override
		public Object removeObject(Object key) {
			
			return null;
		}
		
		/**
		 * 重新equals方法
		 */
		@Override
		public boolean equals(Object o) {
			if (getId() == null)
				throw new CacheException("Cache instances require an ID.");
			if (this == o)
				return true;
			if (!(o instanceof Cache))
				return false;

			Cache otherCache = (Cache) o;
			return getId().equals(otherCache.getId());
		}
		
		/**
		 * 重新hashCode方法
		 */
		@Override
		public int hashCode() {
			if (getId() == null)
				throw new CacheException("Cache instances require an ID.");
			return getId().hashCode();
		}

	}

注意:在mybatis中开启二级缓存(虽然默认也是开启的)

<settings>
		<setting name="cacheEnabled" value="true"/>
	</settings>

6)配置 标签

在需要缓冲的映射文件中加入标签,并且指定提供缓存功能的cache实现类的全限定名

<cache type="com.briup.cache.MybatisRedisCache"></cache>

7)测试方法

@Test
	public void findAllUsers(){
		SqlSession session = null;
		try {
			session = MyBatisSqlSessionFactory.openSession();
			
			UserMapper dao = session.getMapper(UserMapper.class);
			
			List<User> list = dao.findAllUsers();
			System.out.println(list);
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(session!=null)session.close();
		}
	}

	第一次运行,mybatis【发出】对应select进行查询数据库,然后在redis中查看key可知,已经把数据存进了redis中,
	之后再运行,mybatis【不发出】sql语句,数据直接从redis中取出

8)注意事项

注意1
在MyBatis中标签中有flushCache、useCache这两个配置属性
如果属性是在select标签中设置: 
	flushCache默认为false,表示任何时候此标签中的sql语句被调用,都不会去清空本地缓存和二级缓存。 
	useCache默认为true,表示会将本条语句的查询结果进行二级缓存。 
如果属性是在insert、update、delete标签中设置
	flushCache默认为true,表示任何时候语句被调用,都会导致本地缓存和二级缓存被清空。 
	useCache属性在该情况下不存在。

注意2
<settings>
	<!-- 开启二级缓存 -->
	<setting name="cacheEnabled" value="true"/>

	<!-- 禁用延迟加载 --> 
	<!-- 因为不应该把一个代理对象缓存到Redis里面 --> 
	<setting name="lazyLoadingEnabled" value="false" />  
</settings>

12.Redis和Spring结合(同时还要加上Mybatis)

主要依赖的核心jar为:
	spring-data-redis-1.x.x.RELEASE.jar
注意:
	spring3.2.4需要结合使用spring-data-redis-1.6.2.RELEASE.jar

	spring4.3.7可以结合使用spring-data-redis-1.6.2.RELEASE.jar或者更高的版本

从3.1开始,spring引入了对Cache的支持。当我们在调用一个方法时会把该方法参数和返回结果作为一个键值对存放在缓存中,等到下次利用同样的参数来调用该方法时将不再执行该方法,而是直接从缓存中获取结果进行返回。
	使用Spring Cache需要我们做的事情:
		1.配置Spring对Cache的支持
		2.配置jedis工厂、redis模板、cache管理器
		3.声明哪些方法要使用缓存

1)配置Spring对Cache的支持

	配置Spring对基于注解的Cache的支持,首先我们需要在Spring的配置文件中引入cache命名空间,其次通过<cache:annotation-driven />就可以启用Spring对基于注解的Cache的支持。

	<cache:annotation-driven/>有一个cache-manager属性用来指定当前所使用的CacheManager对应的bean的名称,默认值是cacheManager,所以当我们的CacheManager的id为cacheManager时我们可以不指定该参数,否则就需要我们指定了。

	<cache:annotation-driven/>还可以指定一个mode属性,可选值有proxy和aspectj。默认是使用proxy。当mode为proxy时,只有缓存方法在外部被调用的时候Spring Cache才会发生作用,这也就意味着如果一个缓存方法在其声明对象内部被调用时Spring Cache是不会发生作用的。而mode为aspectj时就不会有这种问题。另外使用proxy时,只有public方法上的@Cacheable等标注才会起作用,如果需要非public方法上的方法也可以使用Spring Cache时把mode设置为aspectj。

	<cache:annotation-driven/>还可以指定一个proxy-target-class属性,表示是否要代理class,默认为false。缓存注解@Cacheable、@cacheEvict等是可以标注在接口上,这对于基于接口的代理来说是没有什么问题的,但是需要注意的是当我们设置proxy-target-class为true或者mode为aspectj时,是直接基于class进行操作的,定义在接口上的@Cacheable等Cache注解不会被识别到,那对应的Spring Cache也不会起作用了。
	同时注意<aop:config proxy-target-class="false">这里设置为false才行

2)配置jedis工厂、redis模板、cache管理器

<!-- 配置jedis工厂 -->
		<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
			<property name="hostName" value="127.0.0.1"></property>
			<property name="port" value="6379"></property>
			<property name="usePool" value="true"></property>
			<property name="database" value="0"></property>
		</bean>
		
		<!-- 配置redis模板 -->
		<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
			<property name="connectionFactory" ref="jedisConnectionFactory"></property>
		</bean>
		
		<!-- 配置cache管理器 -->
		<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
			<constructor-arg index="0" ref="redisTemplate"></constructor-arg>
		</bean>

3)声明某些方法要使用缓存

1)@Cacheable

		标记在一个方法上,表示该方法是支持缓存的.对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法
		@Cacheable中常用的有三个属性,value、key和condition。

		value属性是必须指定的,其表示当前方法的返回值是会被缓存在哪个Cache上的,对应Cache的名称。注意是cache的名称,而不是cache中的key,key值会默认生成也可以是自己指定的。cache的名称是我们操作时用的,cache的key是redis中存储value时用的。

		key属性是用来指定Spring缓存方法的返回结果时对应的key的。该属性支持SpringEL表达式。当我们没有指定该属性时,Spring将使用默认策略生成key。
			例如:使用user的id值作为缓存的key值
			@Cacheable(value="users", key="#user.id")
			public User find(User user) {..}

		condition属性指定缓存发生的条件,有的时候我们可能希望满足一定条件才进行缓存。其值是通过SpringEL表达式来指定的,当为true时表示进行缓存处理;当为false时表示不进行缓存处理
			例如:user的id值大于等于100的时候才进行缓存
			@Cacheable(value="users",condition="#user.id>=100")
			public User find(User user) {..}

2)@CachePut

		对于使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是,使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。

3)@CacheEvict

		该注解是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。

		@CacheEvict可以指定的属性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的意思与@Cacheable对应的属性类似。

		allEntries属性
		allEntries是boolean类型,表示是否需要清除缓存中的所有元素。默认为false。
		@CacheEvict(value="users", allEntries=true)
		public void delete(Integer id) {...}

		beforeInvocation属性
		清除操作默认是在对应方法成功执行之后触发的,但是方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用beforeInvocation可以改变触发清除操作的时间,当我们指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素
		@CacheEvict(value="users", beforeInvocation=true)
		public void delete(Integer id) {...}
【Redis】Could not connect to Redis at 127.0.0.1:6379: Connection refused not connected报错解决方案 【Redis】Could not connect to Redis at 127.0.0.1:6379: Connection refused not connected报错解决方案 寸铁手把手带你解决bug ! 阅读详情

相关推荐

2024最新Redis 哨兵模式搭建详解

在现代应用程序中,数据的高可用性和可靠性至关重要。Redis 的哨兵模式(Sentinel)是实现高可用性的一个强大解决方案,它不仅仅提供高可用性,还能进行实时监控及故障自动恢复。这篇文章将深入探讨 Redis 哨兵模式的工作原理,详细的搭建步骤,以及各项配置的深度解析,旨在帮助读者全面掌握 Redis 哨兵架构。

6842

完美解决方案 redis Could not connect to Redis at 127.0.0.1:6379: Connection refused

问题描述: 在Linux系统安装Redis后, 经过一番折腾后 ,启动了服务端后, 在启动客户端,出现了 redis Could not connect to Redis at 127.0.0.1:6379: Connection refused 考虑存在的问题: 1.redis.conf 可能配置出错 2.防火墙没有开放6379 解决方案: 恢复快照 重装redis 下面地址包含软件, 包含详细文档 「Redis安装包」https://www.aliyundrive.com/s/QHwShMSiafV

xujunming668的博客 3万+

【数学建模技术】基于A*算法的路径规划研究与优化应用

A算法(A-star Algorithm)是一种广泛应用于路径规划的启发式搜索算法。它结合了广度优先搜索和贪心算法的优点,能够高效地找到从起点到终点的最优路径,广泛应用于导航系统、机器人路径规划、游戏AI等领域。本篇文章将详细介绍A算法的基本原理,并通过代码实例展示其在路径规划中的实现。

一键难忘的博客 2240

Could not connect to Redis at 127.0.0.1:6379:由于目标计算机积极拒绝,无法连接。

刚开始用redis,不知道redis的真正启动方式。

MarryLinDa的博客 2万+

BERTopic模型入门教程(附代码+参数调节)

BERTopic 是一种用于从文本数据中提取主题模型的新型方法。通过结合 BERT嵌入和传统的主题模型来生成语义丰富的主题。传统的主题模型(如LDA)主要依赖于词频矩阵,而 BERTopic 通过预训练语言模型生成高维语义嵌入来捕捉词语间的复杂关系,因此可以更好地处理上下文信息。BERTopic模型可以看作是创建其主题表示的一系列步骤。核心原理如下:就本质而言,BERTopic就是一个拼装框架,可以把每部分都替换成其他模型,只要完成任务即可。

m0_52069102的博客 1万+

dq轴坐标系下的电路方程

dq轴坐标系下的电路方程 dq轴坐标系是一种常见的电路方程,但是再dq轴坐标系下电路元件的电压电流dq轴存在一定的耦合,本文针对三相电路推导了dq轴坐标系下的电路电路方程进行一个推导,首先先列出来派克变换的公式 派克变换 [AdAqA0]=23[cos⁡(θ)cos⁡(θ−2π/3)cos⁡(θ+2π/3)−sin⁡(θ)−sin⁡(θ−2π/3)−sin⁡(θ+2π/3)1/21/21/2][AaAbAc]\left[\begin{array}{c}A_d\\A_q\\A_0 \end{array}\ri

Mr.Young的博客 1万+

Redis原理详解

Redis 基础详解 一、Redis 是什么 Redis 是一个使用 C 语言写成的,开源的、key-value 结构的、非关系型数据库。它支持存储的 value 类型相对更多,包括 String(字符串)、List(列表)、Set(集合)、Sorted Set(有序集合) 和 Hash(哈希),而且这些操作都是原子性的。在此基础上,Redis 支持各种不同方式的排序。为了保证效率,数据都是缓存在内存中。Redis 可以周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了m

qq1344691727的博客 6819

airodump-ng、aircrack-ng使用教程

wifi破解、airodump-ng、aircrack-ng脚本

ssmbyss的博客 2231

Redis 详解

Redis 详解1. 什么是 Redis2. Redis 基本使用3. Redis 数据结构2.1 String2.2 List2.3 Hash(字典)2.4 Set(集合)2.5 zset(有序集合)4. Redis 持久化5. Redis 集群6. Redis 经典运用6.1 分布式锁 1. 什么是 Redis   Redis 是一个基于内存的高性能 key-value 数据库。是完全开源免费的,用C语言编写的,遵守BSD协议。   Redis 特定: Redis 是基于内存操作的,吞吐量非常高,可以

weixin_44981707的博客 1万+

《机器学习》周志华_自学记录

第一章绪论## 1.1引言机器学习所研究的主要内容,是关于在计算机上从数据中产生"模型"(model)的算法,即"学习算法"(learning algorithm).在面对新的情况时(例如看到一个没剖开的西瓜),模型会给我们提供相应的判断(例如好瓜).如果说计算机科学是研究关于"算法"的学问,那么类似的,可以说机器学习是研究关于"学习算法"的学问.## 1.2基本术语:用于预测离散值,例如将样本分为“好瓜”或“坏瓜”。:用于预测连续值,例如西瓜的成熟度(如0.95、0.37)。

2201_75296678的博客 2530

保姆级教程:用Qlib和LightGBM从零搭建你的第一个AI量化选股策略(附完整代码)

本文提供了一份详细的教程,教你如何使用Qlib和LightGBM从零搭建AI量化选股策略。教程涵盖了环境配置、数据获取、特征工程、模型训练和策略回测等关键步骤,并附有完整代码和常见问题解决方案,适合量化投资初学者快速上手。

weixin_29191081的博客 443

Redis的安装及详解

1.Redis介绍? 1.1 Redis是什么? Redis(Remote Dictionary Server,远程字典服务器)是一个开源免费的,用C语言编写的一个高性能的分布式内存数据库,基于内存运行并支持持久化的NoSQL数据库。是当前最热门的NoSql服务器之一,也被人们成为数据结构服务器(redis的所有功能就是将数据以其固有的几种结构保存,并提供给用户操作这几种结构的接口)。 1.2 R...

tlovet_1314的博客 1411

基于Spring Security 6的OAuth2 系列之二 - 客户端--非代码演示授权码模式

至此,我们就使用浏览器+postman工具演示了通过授权码模式去获取Gitee的用户信息。这过程中,我们只是遵循OAuth2的流程,就能够实现授权方法。那么接下来,我们采用代码方式来实现这个流程。

代码让AI扣 1812

Redis集群详解

Redis集群详解 Redis有三种集群模式,分别是: * 主从模式 * Sentinel模式 * Cluster模式 三种集群模式各有特点,关于Redis介绍可以参考这里:NoSQL(二)——Redis Redis官网:https://redis.io/ ,最新版本5.0.4 主从模式 主从模式介绍 主从模式是三种模式中最简单的,在主从复制中,数据库分为两类:主数据库(master)和从...

变成习惯 22万+

Qt Creator配置MSVC编译环境、调试环境

获取和安装:cdb.exe 在 Debugging tools for Windows 中,而现在已经不单独提供下载,只在Windows SDK 或者Windows Driver Kit里面包含 所以需要下载微软的调试工具,最少需要下载 Windows SDK。在windows上开发,一般使用Qt Creator自带mingw编译器,编译和调试都很方便,安装Qt时勾选后,自动配置完毕。但是有时候我们需要使用MSVC的编译器,这个时候我们没法直接使用,需要配置环境才能使用,以下是配置方案。

希望能帮助大家,希望大家多多支持,你们的支持是我前进的动力。 6986

基于YOLO系列的安全帽检测系统:从理论到实现的完整指南

安全帽检测作为计算机视觉在工业安全领域的重要应用,近年来得到了广泛关注。本文详细介绍了基于YOLOv5、YOLOv6、YOLOv7和YOLOv8的安全帽检测系统的完整实现方案,包括算法原理、数据集构建、模型训练、性能优化以及完整的UI界面设计。通过对比分析不同YOLO版本的性能差异,本文为工业安全检测系统的开发提供了全面的技术参考和实践指导。

YOLO 362

Windows 安装Redis(图文详解)

Windows 安装Redis(图文详解)

shihao的博客 207

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

【Redis】Redis入门详解(一)

一、Redis概述 ①.Redis简介 Redis是一个使用C语言编写的key-value开源的NOSQL存储系统。(区别于MySQL的二维表格的形式存储) ②.Redis特点 高效性:Redis读取的速度是110000次/s,写的速度是81000次/s 原子性:Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。 支持多种数据结构:string(字符串);lis...

Together 1万+

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

超全面Redis详解

目录一、Redis 是什么二、Redis 的特点和功能三、Redis 缓存的使用四、Redis 为什么能这么快五、Redis 缓存的淘汰策略六、Redis 持久化1.为什么需要持久化2.Redis 的持久化策略的两种方式3.RDB的特点4.AOF的特点5.项目中如何选择这两种方式七、Redis 高可用部分的主从复制八、Redis 哨兵的基本原理九、Redis缓存雪崩、穿透、击穿概念及解决办法一、Redis 是什么 Redis 是Remote Dictionary Server(Redis) 的

zxljsbk的博客 2万+

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

上一篇: Redis的概念及基本命令
下一篇: 电脑浏览器无法浏览页面
平平无奇的编码小天才
博客等级 码龄6年 15粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值