在Windows端开发连接需要进行配置文件的配置:
在redis.conf配置文件中
将protected-mode yes,修改为protected-mode no;不保护redis
# By default protected mode is enabled. You should disable it only if # you are sure you want clients from other hosts to connect to Redis # even if no authentication is configured, nor a specific set of interfaces # are explicitly listed using the "bind" directive. protected-mode no
将bind 127.0.0.1加上注释,(#bind 127.0.0.1),允许出本机外的IP访问redis
# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES # JUST COMMENT THE FOLLOWING LINE. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #bind 0.0.0.0: #bind 127.0.0.1
将daemonize no,修改为daemonize yes;允许redis服务后台运行
简单来说我们不用看到点心的那个页面
# By default Redis does not run as a daemon. Use ‘yes‘ if you need it. # Note that Redis will write a pid file in /var/run/redis.pid when daemonized. daemonize yes
修改防火墙端口号
命令:/sbin/iptables -I INPUT -p tcp --dport 6379 -j ACCEPT 保存防火墙修改命令:/etc/rc.d/init.d/iptables save
修改完成后,需要重新启动redis服务。
redis-server /xxxx/redis.conf
通过iptables 允许指定的外网ip访问
修改 Linux 的防火墙(iptables),开启你的redis服务端口,默认是6379
//只允许127.0.0.1访问6379 iptables -A INPUT -s 127.0.0.1 -p tcp --dport 6379 -j ACCEPT //其他ip访问全部拒绝 iptables -A INPUT -p TCP --dport 6379 -j REJECT
一些命令的代码测试:
使用maven工程进行
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.7.2.RELEASE</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.5.0</version> </dependency>
Redis的使用
1.默认直接使用
//首次进行册数的测试 @Test public void testSpeed(){ Jedis jedis = new Jedis("192.168.42.153", 6379);try { jedis.set("key", "value"); } } finally { jedis.close(); } }
2.使用连接池
@Test public void RedisConfigPool(){ JedisPoolConfig pool = new JedisPoolConfig(); //最大空闲数 pool.setMaxIdle(50); //连接数 pool.setMaxTotal(100); //等待毫秒数 pool.setMaxWaitMillis(20000); //使用配置的连接池 JedisPool jedisPool = new JedisPool(pool, "192.168.42.153"); //从连接池中获取单个连接 Jedis jedis = jedisPool.getResource(); jedis.set("ts","1234"); }
使用spring:
基本配置条件如下
User类
//对象需要可序列化,实现接口 public class User implements Serializable{ private static final long serialVersionUID = 6977402643848374753L; private long id; private String name; //........}
spring的配置类
<!-- 连接池 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!-- 空闲数 --> <property name="maxIdle" value="50"></property> <!-- 连接数 --> <property name="maxTotal" value="100"></property> <!-- 最大等待时间 --> <property name="maxWaitMillis" value="20000"></property> </bean> <!-- 连接配置 --> <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName" value="192.168.42.153"></property> <property name="port" value="6379"></property> <!-- 连接池 --> <property name="poolConfig" ref="poolConfig"></property> </bean> <!-- 配置spring-date-Template --> <!-- 序列化 --> <bean id="jdkSerializationRedisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"></bean> <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="connectionFactory"></property> <property name="keySerializer" ref="stringRedisSerializer"></property> <property name="valueSerializer" ref="jdkSerializationRedisSerializer"></property> </bean> <bean id="redisTemplate1" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="connectionFactory"></property> <property name="keySerializer" ref="stringRedisSerializer"></property> <property name="valueSerializer" ref="stringRedisSerializer"></property> </bean> <bean id="redisTemplate2" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="connectionFactory"></property> <property name="keySerializer" ref="stringRedisSerializer"></property> <property name="defaultSerializer" ref="stringRedisSerializer"></property> <property name="valueSerializer" ref="stringRedisSerializer"></property> </bean>
1.
@Test public void testResisString(){ ApplicationContext app = new ClassPathXmlApplicationContext("classpath:/applicationContext.xml"); RedisTemplate redisTemplate = (RedisTemplate) app.getBean("redisTemplate"); User user = new User(); user.setId(1L); user.setName("Mr"); //设置键值对 redisTemplate.opsForValue().set("user", user); //获取键值对 User u = (User) redisTemplate.opsForValue().get("user"); System.out.println(u); }
//以上的使用都是基于 RedisTemplate 基于连接池的操作,换句话说,并不能保
//证每次使用 RedisTemplate 是操作同一个对 Redis 连接
2.
为了使得 操作都来自于同 连接 可以使用 SessionCallback & RedisCallback
RedisCallback是比较底层 封装 使用不是很友好
更多 的时候会使SessionCallback 接口
Redis 同时执行多个命令,那么还是采用 SessionCallback 接口进行操作,从而保证多个命令在同 Redis接操作中。
前后使用的都是同 个连接,对资源消耗小
@Test public void testResisString1(){ ApplicationContext app = new ClassPathXmlApplicationContext("classpath:/applicationContext.xml"); RedisTemplate redisTemplate = (RedisTemplate) app.getBean("redisTemplate"); User user = new User(); user.setId(1L); user.setName("Mr"); SessionCallback callback = new SessionCallback() { @Override public Object execute(RedisOperations operations) throws DataAccessException { //设置 key = user1 值 = user operations.boundValueOps("user1").set(user); return (User)operations.boundValueOps("user1").get(); } }; //获取键值对 User u = (User) redisTemplate.execute(callback); System.out.println(u); }
数据类型:
1.String
//注意此时的RedisTemplate的配置序列化
//首先配置 Spring关于 Redis 字符串 运行环境
//这里给 Spring RedisTemplate 的键值序列 器设置为了 String 类型
//所以就是种字符串的操作
@Test public void StringTest(){ ApplicationContext app = new ClassPathXmlApplicationContext("classpath:/applicationContext.xml"); RedisTemplate redisTemplate = (RedisTemplate) app.getBean("redisTemplate1"); //设置值 //set key name 设置键值对 redisTemplate.opsForValue().set("k1", "v1"); redisTemplate.opsForValue().set("k2", "v2"); //通过key获取值 //get key 通过键获取值 String value1 = (String) redisTemplate.opsForValue().get("k1"); System.out.println("value1" + value1); //删除键值对 redisTemplate.delete("k1"); //字符串长度 //strlen key Long length = redisTemplate.opsForValue().size("k2"); System.out.println("length:" + length); //设置新值返回旧值 String oldVal = (String) redisTemplate.opsForValue().getAndSet("k2", "k222333444"); System.out.println("oldVal:"+ oldVal); String value2 = (String) redisTemplate.opsForValue().get("k2"); System.out.println("value2" + value2); //求子串 //getrange key st end [0 ...] String rangString = redisTemplate.opsForValue().get("k2", 2, 4); System.out.println("rangString:"+rangString); //追加内容在末尾 //append key value 返回新字符串的长度 int newSize = redisTemplate.opsForValue().append("k2", "_new"); System.out.println("newSize:" + newSize); String newVal = (String) redisTemplate.opsForValue().get("k2"); System.out.println("value1" + newVal); }
//redisTemplate.opsForValu() 所返回的对象可以操作简单的键值对
//可以是字符串,也可以是对象,具体依据你所配置的序列化方案
//关于运算 @Test public void StringTestCal(){ ApplicationContext app = new ClassPathXmlApplicationContext("classpath:/applicationContext.xml"); RedisTemplate redisTemplate = (RedisTemplate) app.getBean("redisTemplate1"); //设值 redisTemplate.opsForValue().set("cal", "6"); //初始化的值 String initValue = (String) redisTemplate.opsForValue().get("cal"); System.out.println("initValue:" + initValue); //加1 //还可以加其他的数 redisTemplate.opsForValue().increment("cal", 1); String AddOneVal = (String) redisTemplate.opsForValue().get("cal"); System.out.println("AddOneVal:" + AddOneVal); //减一 redisTemplate.getConnectionFactory().getConnection().decr(redisTemplate. getKeySerializer().serialize("cal")); String MinOneVal = (String) redisTemplate.opsForValue().get("cal"); System.out.println("MinOneVal:" + MinOneVal); //减3 redisTemplate.getConnectionFactory().getConnection().decrBy( redisTemplate.getKeySerializer().serialize("cal"), 3); String MinThreeVal = (String) redisTemplate.opsForValue().get("cal"); System.out.println("MinThreeVal:" + MinThreeVal); //加浮点数 redisTemplate.opsForValue().increment("cal", 4.2); String floatVal = (String) redisTemplate.opsForValue().get("cal"); System.out.println("floatVal:" + floatVal); }
// increment 方法可 支持长整形 long 双精度double的加法
//对于减法而言,RedisTemplate 并没有进行支持
//通过获得连接工厂再获得连接从而得到底 Redis 连接对象
//redisTemplate.getConnectionFactory().getConnection().decr(redisTemplate.
// getKeySerializer().serialize("cal"));
//所有关于减法的方法,原有值都必须是整数,否则就会引发异常
2.Set
//集合不是 个线性结构
//它的内部会根据 hash 分子来存储和查找数据
// Redis 集合的插入、删除和查找的复杂度都是 0(1 )
//对于集合而言,它的每 个元素都是不能重复的,当插入相同记录的时候都会失败
//集合是无序的。
//集合的每 个元素都是 String 数据结构类型。
@Test public void test(){ ApplicationContext app = new ClassPathXmlApplicationContext("classpath:/applicationContext.xml"); RedisTemplate redisTemplate = (RedisTemplate) app.getBean("redisTemplate2"); Set set = null; //将元素加入列表 //sadd key menber [menber1 ...] 给键为key的集合添加成员 redisTemplate.boundSetOps("set1").add("v1","v2","v3","v4","v5","v6"); redisTemplate.boundSetOps("set2").add("v0","v5","v6","v7","v8","v9"); //求集合长度 Long size = redisTemplate.opsForSet().size("set1"); System.out.println("size:" + size); //求差集 //sdif key key2 set = redisTemplate.opsForSet().difference("set1", "set2"); System.out.println("差集:" + set); //并集 //sunion key1 [key2] 求两个集合的并集 set =redisTemplate.opsForSet().intersect("set1", "set2"); System.out.println("并集:" + set); //判断集合中的元素 //sismember key menber 判断menber是否为键为key的集合成员 boolean exist = redisTemplate.opsForSet().isMember("set1", "v3"); System.out.println("exist:" + exist); //获取集合所有元素 //smembers key 返回集合所有成员 set =redisTemplate.opsForSet().members("set1"); System.out.println("集合所有元素:" + set); //随机从集合中弹出一个元素 //spop key 随机弹出一个元素 String val = (String)redisTemplate.opsForSet().pop("set1"); System.out.println("随机弹出:" + val); //随机获取一个集合的元素 //srandmember key [count] 随机返回一个或多个 val = (String)redisTemplate.opsForSet().randomMember("set1"); System.out.println("随机返回一个数:" + val); //随机返回两个 List list = redisTemplate.opsForSet().randomMembers("set1", 2); System.out.println("随机获取集合中两个数:" + list); //删除一个集合的元素,参数可以是多个 //srem key member[member2 ...] 移除集合中的元素,可以多个 // redisTemplate.opsForSet().remove("set1", "v3","v2"....); Long e = redisTemplate.opsForSet().remove("set1", "v3"); System.out.println("e:" + e); //并集 //sunion key [key1] set = redisTemplate.opsForSet().union("set1", "set2"); System.out.println("并集:" + set); //求差集并且保存到新的集合中 //sdiffstore des key1 [key2] 保存到des中 redisTemplate.opsForSet().differenceAndStore("set1", "set2", "new_set"); System.out.println("new_set"+redisTemplate.opsForSet().members("new_set")); //求两个集合的交集,并保存到集合 inter_set //sinterstore des key1 key2 redisTemplate.opsForSet().intersectAndStore("set1", "set2", "inter_set"); System.out.println("新集合交集:"+ redisTemplate.opsForSet().members("inter_set")); //求两个集合的并集,并保存到集合 union_set redisTemplate.opsForSet().unionAndStore("set1", "set2", "union_set"); System.out.println("新并集集合union_set:" + redisTemplate.opsForSet().members("union_set")); }
3.链表
//可以存储多个字符串
//它是有序的
//Redis 链表是双向的
//使用链表结构就意味着读性能的丧失
//链表结构的优势在于插入和删除的便利:,因为链表的数据节点是分配在不同的内存域的,并不连续
//由此可见,链表结构的使用是需要注意场景的,对于那些经常需要对数据进行插入和
//删除的列表数据使用它是十分方便的,因为它可以在不移动其他节点的情况下完成插入和
//删除。而对于需要经常查找的,使用它性能并不佳,它只能从左到右或者从右到左的查找
//和比对。
@Test public void test() throws Exception{ ApplicationContext app = new ClassPathXmlApplicationContext("classpath:/applicationContext.xml"); RedisTemplate redisTemplate = (RedisTemplate) app.getBean("redisTemplate2"); //删除链表 redisTemplate.delete("list"); //创建新的链表 //lpush key node1[node2...] 把节点从左边插入 此时单个节点插入 redisTemplate.opsForList().leftPush("list","node3"); //测试同时插入多个节点 List<String> nodeList = new ArrayList<String>(); for(int i = 2;i >=1;i--){ nodeList.add("node"+i); } //lpush key node1[node2...] 此时同时插入多个节点 从左边插入到key中 redisTemplate.opsForList().leftPushAll("list", nodeList); //rpush key node1[node2...] //从右侧插入节点可一个或多个 redisTemplate.opsForList().rightPush("list", "node4"); //获取链表的长度 Long size = redisTemplate.opsForList().size("list"); System.out.println("size:" + size); List listValue = redisTemplate.opsForList().range("list", 0, size); System.out.println("listValue:" + listValue); //获取下表为0的节点 //index key index index从0开始,返回节点的字符串,读取下表为index的节点 String indexZero = (String)redisTemplate.opsForList().index("list", 0); System.out.println("下表为0的节点:" + indexZero); //从左边弹出一个节点 //lpop key 删除左边的一个节点,并且返回给节点 String leftPop = (String)redisTemplate.opsForList().leftPop("list"); System.out.println("leftpop:" + leftPop); //从右边弹出一个节点 //rpop key 删除左边的一个节点,并且返回给节点 String rightPop = (String)redisTemplate.opsForList().rightPop("list"); System.out.println("rightPop:" + rightPop); //插入节点 //linsert key before | after pivot node 插入一个节点,并且可以指定在职位pivot的前面或者后面 //若list不存在,则报错,没有对应的pivot值,也会插入失败返回 -1 //在node2的前后各插入一个节点 //注意,需要使用更为底层的命令才能操 linsert 命令 //redisTemplate.getConnectionFactory().getConnection().lInsert(key, where, pivot, value); redisTemplate.getConnectionFactory().getConnection().lInsert( "list".getBytes("utf-8"), RedisListCommands.Position.BEFORE, "node2".getBytes("utf-8"), "before_node2".getBytes("utf-8")); redisTemplate.getConnectionFactory().getConnection().lInsert( "list".getBytes("utf-8"), RedisListCommands.Position.AFTER, "node2".getBytes("utf-8"), "after_node2".getBytes("utf-8")); //lpushx list node 若存在key为list的链表, 则插入节点node 否则失败 从左边插入 redisTemplate.opsForList().leftPushIfPresent("list", "head"); //rpushx list node 若存在key为list的链表, 则插入节点node 否则失败 从右边插入 redisTemplate.opsForList().rightPushIfPresent("list", "end"); //lrange list start end 获取从start-end下边的节点值 [start ,end] listValue = redisTemplate.opsForList().range("list", 0, 10); System.out.println("listValue:" + listValue); //lrem list count value count=0删除所有的值为value的节点,否则删除绝对值为count个value的节点值 nodeList.clear(); for(int i = 0 ;i <= 5;i++){ nodeList.add("node"); } //左边插入nodeList redisTemplate.opsForList().leftPushAll("list", nodeList); System.out.println("删除node节点之前的list:"); size = redisTemplate.opsForList().size("list"); listValue = redisTemplate.opsForList().range("list", 0, size); System.out.println("listValue:" + listValue); //从左到右删除6个node节点 redisTemplate.opsForList().remove("list", 6, "node"); System.out.println(""); System.out.println("删除node节点之后的list:"); size = redisTemplate.opsForList().size("list"); listValue = redisTemplate.opsForList().range("list", 0, size); System.out.println("listValue:" + listValue); //修改下表指定节点的值,设置新值 //lset key index value 设置index节点处的新值,设为value redisTemplate.opsForList().set("list", 0, "new_head"); indexZero = (String)redisTemplate.opsForList().index("list", 0); System.out.println("index=0处的新值:" + indexZero); }
//上面这些操作链表的命令都是进程不安全的,因为 我们操作这些命令的时候,
//其他 Redis 的客户端也可能操作同 个链表,这样就会造成并发数据安全和一致性的问题
//Redis 提供了链表的阻塞命令,它 在运行的时候 会给链表加锁,以保证操作链表的命令安全性
//加锁的结果就是其他的进程不能再读取或者写入该链 ,只能等待命令结束
@Test public void testBlock(){ ApplicationContext app = new ClassPathXmlApplicationContext("classpath:/applicationContext.xml"); RedisTemplate redisTemplate = (RedisTemplate) app.getBean("redisTemplate2"); //清空数据 //redisTemplate.delete("list1"); //redisTemplate.delete("list2"); List<String> nodeList = new ArrayList<String>(); for(int i = 1;i <= 5;i++){ nodeList.add("node"+i); } //放入数据 redisTemplate.opsForList().leftPushAll("list1", nodeList); //blpop移除并获取列表的第一个元素,如果没有元素会阻塞列表直到等待超时或者发现可弹出元素 //Spring 使用参数超时时间作为阻塞命令区分,等价于 blpop 命令,并且可以设置时间参数 //redisTemplate.opsForList().leftPop(key, timeout, unit) redisTemplate.opsForList().leftPop("list1", 10, TimeUnit.SECONDS); //Spring 使用参数超时时间作为阻塞命令区分,等价于 brpop 命令,并且可以设置时间参数 redisTemplate.opsForList().rightPop("list1", 3, TimeUnit.SECONDS); Long size = redisTemplate.opsForList().size("list1"); List listValue = redisTemplate.opsForList().range("list1", 0, size); System.out.println("listValue:" + listValue); System.out.println(""); nodeList.clear(); for(int i = 1;i <= 3;i++){ nodeList.add("date"+i); } redisTemplate.opsForList() .leftPushAll ("list2", nodeList); //rpoplpush key src dest 将src的最右边的删除,然后将src追加在dest后面 //不可设置时间 //相当于 rpoplpush 命令,弹出 listl 最右边的节点,插入到 list2 最左边 redisTemplate .opsForList().rightPopAndLeftPush("list1", "list2"); size = redisTemplate.opsForList().size("list2"); listValue = redisTemplate.opsForList().range("list2", 0, size); System.out.println("listValue:" + listValue); //brpoplpush key src dest timeout //相当于 brpoplpush 命令,注意在 Spring 中使用超时参数区分 redisTemplate.opsForList().rightPopAndLeftPush("list1", "list2", 1, TimeUnit.SECONDS); size = redisTemplate.opsForList().size("list2"); listValue = redisTemplate.opsForList().range("list2", 0, size); System.out.println("listValue:" + listValue); }
4.Hash
//Redis中哈希结构就如同 Java的 map 一样
//一个对象里面有许多键值对
//特别适合存储对象的
// 要对 RedisTemplate 的配置项进行修改
//Spring 提供的RedisTemplate 序列 defaultSerializer的默认修改为了字符串序列 器
//因为在 Spring对hash结构的 作中会涉及 map 等其 类的操作 所以需要明确它的规则
//如果想为 hash 结构指定序列化器,可以使用 di mplate 提供的两个
//属性 hashKeySerializer和hashValueSerializer ,来为 hash 结构的 field和value 指定序列化器。
@Test public void testHash(){ ApplicationContext app = new ClassPathXmlApplicationContext("classpath:/applicationContext.xml"); RedisTemplate redisTemplate = (RedisTemplate) app.getBean("redisTemplate2"); //设置key String key = "hash"; Map<String,String> map = new HashMap<String,String>(); map.put("name", "MrChengs"); map.put("age","22"); //hmset 设置键值对(可多个) //hmset key filed1[filed2....] redisTemplate.opsForHash().putAll(key, map); //hset 在结构体中键值对 //hset key filed redisTemplate.opsForHash().put(key, "hobby", "game"); pringtValehash(redisTemplate, key, "hobby"); //hexists key field //判断是否存在field字段 boolean exists = redisTemplate.opsForHash().hasKey(key, "hobby"); System.out.println("exitsts:" + exists); //hgetall key //获取key中的所有字段 map=redisTemplate.opsForHash().entries(key); System.out.println("hgetall:" + map); //hincrby key field increment //给某一字段加以整数 //还可以double redisTemplate.opsForHash().increment(key, "age", 3); pringtValehash(redisTemplate, key, "age"); //hvals key //获取hash结构中的所有值 List keyList = new ArrayList(); keyList = redisTemplate.opsForHash().values(key); System.out.println("value:"+ keyList); //hkeys key 返回key中的所有键 Set set = redisTemplate.opsForHash().keys(key); System.out.println("keys:" + set); //hmget key filed1[2...] //返回指定键中的值 List listVal = redisTemplate.opsForHash().multiGet(key, set); System.out.println("listVal:" + listVal); //hmsetnx key field value //设置键值对,在不存在field时才进行设置 boolean su = redisTemplate.opsForHash().putIfAbsent(key, "wight", "125"); System.out.println(su); pringtValehash(redisTemplate, key, "wight"); //hdel Long size = redisTemplate.opsForHash().delete(key, "age"); System.out.println("size" + size); } private static void pringtValehash(RedisTemplate redisTemplate , String key ,String field){ //hget 获取属性值 单个 Object value = redisTemplate.opsForHash().get(key, field); System.out.println(value); }
//hmset在 JavaAPI中,是使用 map保存多个键值对在先的。
//getall 命令会返回所有的键值对,并保存到 map 对象中,如果 hash 结构很大,那么要考虑它对JVM 的内存影响。
// hincrby hincrbyFloat 令都采用 ncrement 方法, Spring 会识别它具体使用何种方法。
原文地址:https://www.cnblogs.com/Mrchengs/p/10066973.html