redis 乐观锁_什么时候用乐观锁

redis 乐观锁_什么时候用乐观锁文章目录GeospatialHyperloglogBitmapsRedis事务悲观锁和乐观锁JedisSpringboot继承RedisGeospatial存储地理位置的数据结构应用场景朋友的定位,附近的人,打车距离计算Geospatial底层使用的是Zset127.0.0.1:6379> geoadd city 116.23 40.22 beijing 添加一个数据127.0.0.1:6379> geoadd city 121.47 31.23 shanghai 118.77

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

Geospatial

存储地理位置的数据结构
应用场景
朋友的定位,附近的人,打车距离计算
Geospatial底层使用的是Zset

127.0.0.1:6379> geoadd city 116.23 40.22 beijing		添加一个数据
127.0.0.1:6379> geoadd city 121.47 31.23 shanghai 118.77 32.04 nanjing 113.28 23.13 guangzhou 114.09 22.55 shenzhen

127.0.0.1:6379> geodist city beijing tianjin		//计算距离
“157.7274”

127.0.0.1:6379> geopos city beijing tianjin shanghai nanjing guangzhou shenzhen		//返回指定城市的经纬度

127.0.0.1:6379> geohash city beijing tianjin	//返回一个或多个位置元素的 Geohash 表示
“wx4sucu47r0”
"wwgmftx1sz0"

127.0.0.1:6379> georadius city 120 20 1000 km //以120,20为中心,寻找方圆1000米的城市
"shenzhen"
"guangzhou"
127.0.0.1:6379> georadius city 120 20 1000 km withdist 	//返回位置元素的同时,将位置元素和中心之间的距离一并返回
"shenzhen"
"674.9271"
"guangzhou"
"777.2656"
127.0.0.1:6379> georadius city 120 20 1000 km withcoord		//将位置信息和经度纬度一并返回
127.0.0.1:6379> georadius city 120 20 1000 km withcoord count 1  	//	选取前1个匹配的元素		

127.0.0.1:6379> georadiusbymember city beijing 1000 km		//找出位于指定元素周围的其他元素

//GEO 底层的实现原理其实就是 Zset!我们可以使用Zset命令来操作geo!。
127.0.0.1:6379> zrange city 0 -1
127.0.0.1:6379> zrem city tianjin

Hyperloglog

什么是基数
A{1,3,5,7,8,7}
基数(不重复的元素) = 5

Hyperloglog简介
Hyperloglog就是做基数统计的一个算法。
Hyperloglog类型允许接受误差

应用场景
网页的浏览量:(一个人访问一个网站多次,当时还是算作一个人)
传统方法:使用set保存用户id,然后就可以统计set中的元素数量作为判断标准,但是这种方法需要保存大量的用户id,耗费内存。这时候需要用到Hyperloglog数据结构

Hyperloglog的优缺点:
优点:占用的内存是固定的,比如要放2^64不同的元素,则只需要固定的12KB的内存。
缺点:有0.81%的错误率。如果不允许出错,那么则只能使用set

linux命令

127.0.0.1:6379> PFADD mykey a b c d e f g h i j	//创建Hyperloglog
(integer) 1
127.0.0.1:6379> PFCOUNT mykey		//数量
(integer) 10
127.0.0.1:6379> PFADD mykey2 i j z x c v b n m
(integer) 1

127.0.0.1:6379> PFMERGE mykey3 mykey1 mykey2		//合并mykey1 喝  mykey2
OK
127.0.0.1:6379> PFCOUNT mykey3		//合并后 消除重复元素
(integer) 9

Bitmaps

位存储
32位机器上的自然数一共有2的32次方约42亿个,如果用一个bit来存放一个整数,1代表存在,0代表不存在,那么把全部自然数存储在内存只要4294967296 / (8 * 1024 * 1024) = 512MB(8bit = 一个字节),而这些自然数存放在文件中,一行一个数字,1个整数4个字节,48512MB需要16G的容量。可见,bitmap算法节约了非常多的空间。
应用场景:
比如统计用户信息,活跃或不活跃,打开,或者未打卡,登录,或者未登录。只要设计两个状态的都可以使用Bitmaps。

127.0.0.1:6379> SETBIT sign 0 1		//setbit sign offset status(0/1)
(integer) 0		
127.0.0.1:6379> SETBIT sign 2 1
(integer) 0
127.0.0.1:6379> BITCOUNT sign		//统计有多少位是1
(integer) 2
127.0.0.1:6379> 

Redis事务

Redis只是单条命令保证原子性,但是事务并不保证原子性
Redis的事务就是一组命令的集合
redis 是单线程的,也就意味着它总是以串行方式执行,同一时刻内不会有其他事务打断当前事务的执行。redis的事务具有隔离性,也就意味这Redis没有一堆脏读,不可重复读,等一些列问题。
命令
开启事务:multi
命令入队:众多Redis命令
执行事务:exec

127.0.0.1:6379> multi		//开启事务
OK
127.0.0.1:6379> set k1 v1		//命令入队
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec			//执行事务
1) OK
2) OK
3) "v2"
4) OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> DISCARD		//放弃事务
OK
127.0.0.1:6379> get k1
(nil)

事务不保证原子性 实例
编译型异常(代码有问题,命令有错),事务中所有的命令都不会被执行

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> getset k3		//命令语法错误
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> EXEC		//不能执行事务,所有的命令都不会执行
(error) EXECABORT Transaction discarded because of previous errors.

运行时异常(代码没问题,但是实际运行的时候发现不对),那么执行命令的时候,其他命令是可以正常执行的。

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> INCR k1		//这条命令运行时错误
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> EXEC
1) (error) ERR value is not an integer or out of range		//虽然事务中有一条运行时错误的命令,但是第二条命令还是会执行
2) OK
127.0.0.1:6379> get k2
"v2"

悲观锁和乐观锁

悲观锁:认为什么时候都会有问题,无论做什么都会加锁
乐观锁:认为什么时候都不会有问题,无论做什么都不会上锁。但是需要机制去判断一下再次期间是否有人更改了数据
乐观锁version版本
使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据

//更新商品信息1 
    Goods goods1 = this.goodsDao.getGoodsById(goodsId);  //获取了version值
    goods1.setStatus(2);
    int updateResult1 = this.goodsDao.updateGoodsUseCAS(goods1);  //version值并没有被更改
    System.out.println("修改商品信息1"+(updateResult1==1?"成功":"失败"));  
      
    goods1.setStatus(2);
    int updateResult2 = this.goodsDao.updateGoodsUseCAS(goods1);  //version值早已经被更改,所以更新失败
    System.out.println("修改商品信息2"+(updateResult2==1?"成功":"失败"));

Redis使用监控机制来实现乐观锁

127.0.0.1:6379> set mymoney 100
OK
127.0.0.1:6379> set yourmoney 0
OK

# 线程1先开启监控		这时相当于线程1拿到version
127.0.0.1:6379> watch mymoney
OK

# 线程2开始对进行转账操作修改值 这时候相当于线程2更改version
127.0.0.1:6379> INCRBY mymoney -50
(integer) 50
127.0.0.1:6379> INCRBY yourmoney 50
(integer) 50


#	线程1 开始进行转账,发现这时的version和之前拿到的version不相等,执行失败
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECRBY mymoney 10
QUEUED
127.0.0.1:6379> INCRBY yourmoney 10
QUEUED
127.0.0.1:6379> EXEC
(nil)
# 如果修改失败,重新unwatch然后watch拿到最新的值
# 可以先撤销监控 在重新监控 这样拿到的就是最新值
127.0.0.1:6379> UNWATCH
OK
127.0.0.1:6379> WATCH mymoney
OK
.....继续执行命令

Jedis

Jedis是Redis官方推荐的java链接开发工具,使用java操作Redis中间件,那么一定要对jedis十分熟悉
1.windows下 启动jedis服务器

redis-server.exe redis.windows.conf
  1. 导入对应依赖
<dependencies>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.2.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>
    </dependencies>
  1. 连接数据库并操作
public static void main(String[] args) {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        System.out.println(jedis.ping());
        System.out.println(jedis.set("key1","value1"));
        System.out.println(jedis.get("key1"));
        System.out.println(jedis.select(2));
        System.out.println(jedis.flushDB());
        jedis.close();
        ...
    }

自定义RedisTemplate

public void test() throws JsonProcessingException { 
   
        User user = new User("user",22);
        String json = new ObjectMapper().writeValueAsString(user);
        redisTemplate.opsForValue().set("user",json);
        System.out.println(redisTemplate.opsForValue().get("user"));//结果{"name":"user","age":22}
    }

查看Linux

127.0.0.1:6379> keys *
1) "\xac\xed\x00\x05t\x00\x04user"		# 乱码

直接传对象需要对象序列化

public void test() throws JsonProcessingException {
        User user = new User("user",22);	//对象需要序列化
        redisTemplate.opsForValue().set("user",user);
        System.out.println(redisTemplate.opsForValue().get("user"));
    }
127.0.0.1:6379> keys *
1) "\xac\xed\x00\x05t\x00\x04user"		//仍然乱码

自定义RedisTemplate

@Bean
    @ConditionalOnMissingBean(
        name = { 
   "redisTemplate"}
    )	//我们可以自定义RedisTemplate
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { 
   
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

		//默认序列化是jdk序列化 我们需要更改这个才能使得传递的key value显示正常字符串,否则默认的序列化是二进制
	if (this.defaultSerializer == null) { 
   
            this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());
        }

自定义RedisTemplate

@Configuration
public class RedisConfig { 
   
    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){ 
   
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // Jackson序列化配置
        Jackson2JsonRedisSerializer 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);
        // 字符串序列化配置
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        
        //redisTemplate配置key value的序列化方实
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

这下再用我们自定义的redisTemplate进行Redis传递数据


    @Qualifier("redisTemplate")
    @Autowired
    RedisTemplate redisTemplate;
	@Test
    public void test() throws JsonProcessingException { 
   
        User user = new User("user",22);
        redisTemplate.opsForValue().set("user",user);
        System.out.println(redisTemplate.opsForValue().get("user"));
    }

这下使用我们自定义的RedisTemplate就不会出现二进制了

127.0.0.1:6379> keys *
1) "user"

Redis.conf详解

# Redis单位
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes

# units are case insensitive so 1GB 1Gb 1gB are all the same.		# 对大小写不敏感

# include .\path\to\local.conf	//可以包含其他Redis配置文件
# include c:\path\to\other.conf

bind 127.0.0.1	#默认绑定本地ip  可以填 * 让所有网络连接

port 6379		# 端口设置

# GENERAL通用配置
daemonize yes	#默认是No,以守护进程的方实打开。一推出,进程就结束
pidfile /var/run/redis_6379.pid   	# 如果以后台的方实运行,我们就需要指定一个pid文件
# 日志级别
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice

logfile ""		# 日志文件位置

databases 	# 默认数据库数量

save 900 1		# 900s 内如果至少有一个key进行修改,则进行持久化操作
save 300 10	# 300s 内如果至少10个key 进行修改,则进行持久化
save 60 10000

stop-writes-on-bgsave-error yes		# 持久化出错后是否还让redis继续工作

rdbcompression yes 	# 是否压缩rdb文件	需要消耗一些cpu资源

rdbchecksum	yes	#保存rdb文件的时候,进行错误的检查校验

dir ./		# rdb文件保存的目录

# SERCURITY		安全
required password 	# 配置登录redis密码	可以使用Linux命令	config set requiredpass

# Clients 客户端配置
# maxclients 10000		最大的客户端数量

# maxmemory <bttes>	#redis 占用最大内存
# maxmemory-policy noeviction	#内存达到上限之后的处理策略


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/168969.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • k3s集群安装_hadoop跨集群配置

    k3s集群安装_hadoop跨集群配置文章目录一、k3s离线部署准备工作1.准备节点2.安装Docker3.[k3s官网](https://github.com/k3s-io/k3s/releases/tag/v1.18.6%2Bk3s1)中下载部署文件。部署步骤1.导入镜像:2.修改文件权限:3.安装4.检查是否安装成功:5.卸载k3s问题解决:1.出现kubernetesclusterunreachable:2.出现Theconnectiontotheserverlocalhost:8080wasrefu

    2025年6月9日
    27
  • linux卸载已安装的jdk_linux卸载tomcat

    linux卸载已安装的jdk_linux卸载tomcat卸载JDK1、先输入java-version查看是否安装了jdk2、如果安装了,检查下安装的路径whichjava(查看JDK的安装路径)3、卸载rm-rfJDK地址(卸载JDK)rm-rf/usr/java/jdk/jdk1.8.0_172/4、vim命令编辑文件profilevim/etc/profile删除配置的环境变量,至此JDK卸载完毕5、检查下自带的jdk命令:rpm-qa|grepjavarpm-qa|grep…

    2022年10月1日
    2
  • R-L模型算法的优缺点_审计重要性特征

    R-L模型算法的优缺点_审计重要性特征1.特征重要性的意义LR模型也就是逻辑回归模型,作为一个简单的常用的模型,其有非常多的有点,除了模型简单,容易实现分布式,还有一个重要的优点就是模型的可解释性非常好。因为每个特征都对应一个模型参数wiw_{i}wi​,该参数越大,那么该特征对模型预测结果的影响就会越大,我们就说该特征就越重要,因此LR模型的特征重要性评估方式就是wiw_{i}wi​的大小。2.逻辑回归模型特征重要性及排序Ta…

    2022年10月8日
    3
  • 周鸿祎

    周鸿祎文/周鸿祎来自微信公共号:财经十一人在BAT的光芒下,在美团、小米构造的互联网第二阵营中,特别是在猎豹上市之后,360多次欲言又止,一反常态。360公关团队告诉财经十一人,老周在闭关思考3

    2022年7月1日
    26
  • MyBatis的通俗理解:SqlSession.getMapper()源码分析

    MyBatis的通俗理解:SqlSession.getMapper()源码分析一、什么是MyBatis?直接看官方文档:https://mybatis.org/mybatis-3/zh/index.html。从上面我们了解到:1、MyBatis是一款优秀的持久层框架2、MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。3、MyBatis避免了几乎所有的JD…

    2022年6月15日
    28
  • 求图的连通分量

    求图的连通分量题目 输出无向连通图各个连通分量 输入描述 输入文件中包含多个测试数据 每个测试数据的格式为 第 1 行为两个整数 n 和 m 分别表示顶点个数和边数 然后有 m 行 每行表示一条边 为这条边的两个顶点的序号 顶点序号从 1 开始计起 假定无向图是连通的 可能存在割点 也可能没有割点 n m 0 时表示输入结束 输出描述 对每个测试数据 以 uv 的形式依次输出各连通分量中的每条边 每

    2025年7月30日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号