Redis单条命令是原子性的,但是事务不保证原子性
Redis事务没有隔离级别的概念,所有的命令在事务中没有被直接执行,只有发起执行命令的时候才会执行 Exec
Redis事务本质:一组命令的集合,一个事务中的所有的命令都会被序列化,在事务执行过程中,会按照顺序执行。
三个特性
一次性、顺序性、排他性
Redis事务
- 开启事务(multi)
- 命令入队(…)
- 执行事务(exec)
执行完一组就要重新开启
放弃事务
编译型异常(代码有问题!命令有错! ),事务中所有的命令都不会被执行!
运行时异常(1/0),如果事务队列中存在语法性错误,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常!
原子性定义:1.要么全部执行成功,要么异常全不执行;2.异常发生后,可以回滚,就像没执行过一样;Redis事务异常以后其他命令依旧执行,没有发生回滚,Redis大部分是命令语法错误引发异常。
监控(Watch)
悲观锁:
很悲观,无论执行什么操作都会出现问题,所以会对所有的操作加锁
乐观锁
很乐观,任何情况下都不会出问题,所以不会加锁!但是在数据更新时需要判断在此之前是否有人修改过这个数据
可以添加一个字段叫version用来查询(标记号)
在进行数据更新时对version进行比较
测试多线程修改值,使用watch可以当做redis的乐观锁操作!
Redis监视测试
127.0.0.1:6379> WATCH money
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECRBY money 30
QUEUED
127.0.0.1:6379> INCRBY out 30
QUEUED
# 这个时候开始模拟另外一个客户端恶意修改被监控的key
# =======================================================表示另一个客户端==============================================================
127.0.0.1:6379> get money
"80"
127.0.0.1:6379> INCRBY money 200 # 修改被监控的数据
(integer) 280
127.0.0.1:6379> get money
"280"
# ===================================================================================================================================
# 再次执行事务,会直接返回nil,代表执行失败
127.0.0.1:6379> EXEC
(nil)
127.0.0.1:6379> get money # 再次查看,当前监控的key已经被修改
"280"
# 多聊一嘴:实际上关于WATCH,还有一个命令,UNWATCH,意思是解除所有监控,但是官网的原话是,一旦你执行了DISCARD或者EXEC,就没必要在执行UNWATCH
127.0.0.1:6379> MGET money out
1) "280"
2) "20"
127.0.0.1:6379> WATCH money
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECRBY money 30
QUEUED
127.0.0.1:6379> INCRBY out 30
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 250
2) (integer) 50
如果修改失败获取最新的值
Jedis
什么是Jedis
Jedis是Redis官方推荐的Java连接Redis的连接开发工具!使用Java操作Redis的中间件
<!--导入Jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
编码测试
- 连接数据库
- 操作命令
- 断开连接
先在服务器中开放安全组6379端口,之后
2.xshell连接服务器。然后输入ifconfig
得到以下的图片
这两个ip请记住,尤其第一个,第二个是默认的。
3.使用vim打开redis.conf (文件目录自己清楚)
然后找到bind 配置第二步找到的ip地址。
如图
运行:wq!保存
之后重启redis
import redis.clients.jedis.Jedis;
public class TestPing {
public static void main(String[] args) {
// new一个Jedis对象
Jedis jedis = new Jedis("121.4.127.10", 6379);
// Jedis中的API就是之前学习的命令
System.out.println(jedis.ping());
System.out.println("清空数据"+jedis.flushDB());
// String
System.out.println(jedis.set("k1", "v1"));
System.out.println(jedis.get("k1")); // v1
System.out.println(jedis.append("k1", "+value"));
System.out.println(jedis.get("k1")); // v1+value
System.out.println(jedis.strlen("k1")); // 8
System.out.println("=====================================================");
// List
System.out.println(jedis.lpush("listKey", "l1", "l2", "l3"));
System.out.println(jedis.lrange("listKey", 0, -1)); // [l3, l2, l1]
System.out.println(jedis.llen("listKey"));
System.out.println("=====================================================");
// Hash
System.out.println(jedis.hset("hashKey", "k1", "v1"));
System.out.println(jedis.hset("hashKey", "k2", "v2"));
System.out.println(jedis.hset("hashKey", "k3", "v3"));
System.out.println(jedis.hmget("hashKey", "k1", "k2", "k3")); // [v1, v2, v3]
System.out.println(jedis.hgetAll("hashKey")); // {k3=v3, k2=v2, k1=v1}
System.out.println("=====================================================");
// Set
System.out.println(jedis.sadd("setKey", "s1", "s2", "s3", "s4"));
System.out.println(jedis.smembers("setKey")); // [s2, s1, s4, s3]
System.out.println(jedis.scard("setKey"));
System.out.println("=====================================================");
// ZSet
System.out.println(jedis.zadd("ZKey", 90, "z1"));
System.out.println(jedis.zadd("ZKey", 80, "z2"));
System.out.println(jedis.zadd("ZKey", 85, "z3"));
System.out.println(jedis.zrange("ZKey", 0, -1)); // [z2, z3, z1]
}
}
PONG
清空数据OK
OK
v1
8
v1+value
8
=====================================================
3
[l3, l2, l1]
3
=====================================================
1
1
1
[v1, v2, v3]
{k3=v3, k1=v1, k2=v2}
=====================================================
4
[s4, s1, s3, s2]
4
=====================================================
1
1
1
[z2, z3, z1]
Process finished with exit code 0
事务
import com.alibaba.fastjson.JSONObject;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
public class TestTx {
public static void main(String[] args) {
Jedis jedis = new Jedis("192.168.1.107", 6379);
jedis.flushDB();
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", "xiaohuang");
jsonObject.put("age", "21");
jsonObject.put("sex", "boy");
Transaction multi = jedis.multi(); // 开启事务
String user = jsonObject.toJSONString();
try {
multi.set("user1", user);
multi.set("user2", user);
multi.exec();
} catch (Exception e) {
multi.discard(); // 出现问题,放弃事务
e.printStackTrace();
} finally {
System.out.println(jedis.mget("user1", "user2"));
jedis.close(); // 关闭连接
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/152862.html