SpringBoot使用RedisTemplate、StringRedisTemplate操作Redis

前言

本文实现了在SpringBoot中集成Redis,使用RedisTemplate对象操作并编写了一些常用方法的工具类。

RedisTemplate和StringRedisTemplate的区别:

1.  两者的关系是StringRedisTemplate继承RedisTemplate。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.data.redis.core;import org.springframework.data.redis.connection.DefaultStringRedisConnection;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializer;public class StringRedisTemplate extends RedisTemplate<String, String> {public StringRedisTemplate() {this.setKeySerializer(RedisSerializer.string());this.setValueSerializer(RedisSerializer.string());this.setHashKeySerializer(RedisSerializer.string());this.setHashValueSerializer(RedisSerializer.string());}public StringRedisTemplate(RedisConnectionFactory connectionFactory) {this();this.setConnectionFactory(connectionFactory);this.afterPropertiesSet();}protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) {return new DefaultStringRedisConnection(connection);}
}

2. 两者的数据是不共通的,也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管理RedisTemplate中的数据。

3. SDR默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略。

StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。

RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。

RedisTemplate默认使用的序列类在在操作数据的时候,比如说存入数据会将数据先序列化成字节数组然后在存入Redis数据库,这个时候打开Redis查看的时候,你会看到你的数据不是以可读的形式展现的,而是以字节数组显示。

那么就可以得出一个结论,如果你想使用默认的配置来操作redis,则如果操作的数据是字节数组,就是用RedisTemplate,如果操作的数据是明文,使用StringRedisTemplate。

当然在项目中真实使用时,一般是自定义RedisTemplate的Bean实例,来设置具体的序列化策略,说白了就是RedisTemplate通过自定义Bean可以实现和StringRedisTemplate一样的序列化,使用起来更加灵活。

一、Redis五种基础数据结构

首先对redis来说,所有的key(键)都是字符串。我们在谈基础数据结构时,讨论的是存储值的数据类型,主要包括常见的5种数据类型,分别是:String、List、Set、Zset、Hash。

结构类型结构存储的值结构的读写能力
String字符串可以是字符串、整数或浮点数对整个字符串或字符串的一部分进行操作;对整数或浮点数进行自增或自减操作
List列表一个链表,链表上的每个节点都包含一个字符串对链表的两端进行push和pop操作,读取单个或多个元素;根据值查找或删除元素
Set集合包含字符串的无序集合字符串的集合,包含基础的方法有看是否存在添加、获取、删除;还包含计算交集、并集、差集等
Hash散列包含键值对的无序散列表包含方法有添加、获取、删除单个元素
Zset有序集合和散列一样,用于存储键值对字符串成员与浮点数分数之间的有序映射;元素的排列顺序由分数的大小决定;包含方法有添加、获取、删除单个元素以及根据分值范围或成员来获取元素

        
        
        
        
        
        

二、RedisTemplate 概述

1、Redis 是一个缓存、消息代理和功能丰富的键值存储。Spring Boot 为 Lettuce 和 Jedis 客户端库提供基本的自动配置,并为 Spring Data Redis 提供抽象。官网传送。

2、spring-boot-starter-data-redis 启动器,整合了需要的依赖项,默认情况下,它使用 Lettuce 作为客户端。这个启动器同时处理传统应用程序和反应性应用程序(reactive applications)。

3、官方还提供了一个 spring-boot-starter-data-redis-reactive 启动器,用于与具有 reactive 支持的其他存储保持一致。

4、可以像注入任何其他 Spring Bean 一样注入一个自动配置的 RedisConnectionFactory、StringRedisTemplate 或普通的 RedisTemplate 实例。class StringRedisTemplate extends RedisTemplate<String, String>

5、默认情况下,Redis 实例尝试连接本地主机(localhost)端口为 6379 的 Redis 服务器,默认使用空密码,连接 0 号数据库:RedisProperties

6、可以实现 LettuceClientConfigurationBuilderCustomizer 接口,以实现更高级的定制。如果使用的是 Jedis 客户端,则实现 JedisClientConfigurationBuilderCustomizer 接口。

三、SpringBoot通过RedisTemplate连接Redis

一、引入依赖

<!-- redis 缓存操作 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- pool 对象池 -->
<!-- 使用lettuce客户端需要引入commons-pool2依赖 -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>

二、基础配置

1、配置application.yml文件

配置如下:

spring:data:redis:mode: master# 地址host: 30.46.34.190# 端口,默认为6379port: 6379# 密码,没有不填password: ''# 几号库database: 1sentinel:master: masternodes: 30.46.34.190cluster:nodes: 30.46.34.190lettuce:pool:# 连接池的最大数据库连接数max-active: 200# 连接池最大阻塞等待时间(使用负值表示没有限制)max-wait: -1ms# 连接池中的最大空闲连接max-idle: 50# 连接池中的最小空闲连接min-idle: 8

2、RedisTemplate配置

代码如下:

/*
*自定义Redis配置类,进行序列化以及RedisTemplate设置
*/
@Configuration
@EnableConfigurationProperties({RedisProperties.class})
public class RedisConfig {@Value("${spring.data.redis.mode}")private String redisMode;private final RedisProperties properties;public RedisConfig(RedisProperties properties) {this.properties = properties;}@Beanpublic LettuceConnectionFactory redisConnectionFactory(ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers,ClientResources clientResources) {GenericObjectPoolConfig<?> config = new GenericObjectPoolConfig<>();config.setMaxTotal(this.properties.getLettuce().getPool().getMaxActive());config.setMaxIdle(this.properties.getLettuce().getPool().getMaxIdle());config.setMinIdle(this.properties.getLettuce().getPool().getMinIdle());config.setMaxWait(this.properties.getLettuce().getPool().getMaxWait());LettucePoolingClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();switch (redisMode) {case "master":RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();redisStandaloneConfiguration.setDatabase(this.properties.getDatabase());redisStandaloneConfiguration.setPassword(this.properties.getPassword());redisStandaloneConfiguration.setHostName(this.properties.getHost());redisStandaloneConfiguration.setPort(this.properties.getPort());return new LettuceConnectionFactory(redisStandaloneConfiguration, clientConfiguration);case "sentinel":RedisSentinelConfiguration redisSentinelConfig = new RedisSentinelConfiguration();redisSentinelConfig.setDatabase(this.properties.getDatabase());redisSentinelConfig.setPassword(this.properties.getPassword());redisSentinelConfig.setMaster(this.properties.getSentinel().getMaster());redisSentinelConfig.setSentinels(this.properties.getSentinel().getNodes().stream().map(RedisNode::fromString).collect(Collectors.toList()));return new LettuceConnectionFactory(redisSentinelConfig, clientConfiguration);case "cluster":RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();redisClusterConfiguration.setPassword(this.properties.getPassword());redisClusterConfiguration.setClusterNodes(this.properties.getCluster().getNodes().stream().map(RedisNode::fromString).collect(Collectors.toList()));return new LettuceConnectionFactory(redisClusterConfiguration, clientConfiguration);default:throw new IllegalArgumentException("无效的redis mode配置");}}@Beanpublic RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory){ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =new Jackson2JsonRedisSerializer<>(om, Object.class);RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);// 使用StringRedisSerializer序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());// 设置值(value)的序列化采用Jackson2JsonRedisSerializertemplate.setValueSerializer(serializer);// 使用StringRedisSerializer序列化和反序列化redis hash类型的key值template.setHashKeySerializer(new StringRedisSerializer());// 序列化和反序列化redis hash类型的value值template.setHashValueSerializer(serializer);template.afterPropertiesSet();return template;}}

3. 编写测试类

package com.zpli.web.test;/*** created at 2024/7/9 19:08** @author somnuszpli*/import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisTemplateTest {@Autowiredprivate RedisTemplate redisTemplate;// <1>@Testpublic void test() throws Exception {redisTemplate.opsForValue().set("student:1", "zpli"); // <2>Assertions.assertThat(redisTemplate.opsForValue().get("student:1")).isEqualTo("kirito");}
}

<1> 引入了 RedisTemplate,这个类是 spring-starter-data-redis 提供给应用直接访问 redis 的入口。从其命名就可以看出,其是模板模式在 spring 中的体现,与 restTemplate,jdbcTemplate 类似,而 springboot 为我们做了自动的配置,具体已在上文详解。

<2> redisTemplate 通常不直接操作键值,而是通过 opsForXxx() 访问,在本例中,key 和 value 均为字符串类型。绑定字符串在实际开发中也是最为常用的操作类型。

三、详解 RedisTemplate 的 API


RedisTemplate 为我们操作 Redis 提供了丰富的 API,可以将他们简单进行下归类。

API返回值类型说明
redisTemplate.opsForValue()      ValueOperations操作 String 类型 数据
redisTemplate.opsForHash()HashOperations操作 Hash 类型数据
redisTemplate.opsForList() ListOperations操作 List 类型数据
redisTemplate.opsForSet() SetOperations操作 Set 类型数据
redisTemplate.opsForZSet()ZSetOperations操作 SortedSet 类型数据
redisTemplate通用的命令

        

        
       
       
        
        

1 常用数据操作


这一类 API 也是我们最常用的一类。

众所周知,redis 存在 5 种数据类型:

  • 字符串类型(string)
  • 散列类型(hash)
  • 列表类型(list)
  • 集合类型(set)
  • 有序集合类型(zset)

而 redisTemplate 实现了 RedisOperations 接口,在其中,定义了一系列与 redis 相关的基础数据操作接口,数据类型分别与下面 API 对应:

//非绑定key操作
ValueOperations<K, V> opsForValue();


<HK, HV> HashOperations<K, HK, HV> opsForHash();


ListOperations<K, V> opsForList();


SetOperations<K, V> opsForSet();


ZSetOperations<K, V> opsForZSet();


//绑定key操作
BoundValueOperations<K, V> boundValueOps(K key);


<HK, HV> BoundHashOperations<K, HK, HV> boundHashOps(K key);


BoundListOperations<K, V> boundListOps(K key);


BoundSetOperations<K, V> boundSetOps(K key);


BoundZSetOperations<K, V> boundZSetOps(K key);

若以 bound 开头,则意味着在操作之初就会绑定一个 key,后续的所有操作便默认认为是对该 key 的操作,算是一个小优化。

2.几种数据结构操作的具体用法

操作 Redis 的 String 数据结构

设置当前的 key 以及 value 值

redisTemplate.opsForValue().set(key, value)
redisTemplate.opsForValue().set("num","123");

设置当前的 key 以及 value 值并且设置过期时间

redisTemplate.opsForValue().set(key, value, timeout, unit)
redisTemplate.opsForValue().set("num","123",10, TimeUnit.SECONDS);

  • TimeUnit.DAYS                           //天  
  • TimeUnit.HOURS                        //小时  
  • TimeUnit.MINUTES                     //分钟  
  • TimeUnit.SECONDS                   //秒
  • TimeUnit.MILLISECONDS          //毫秒


将旧的 key 设置为 value,并且返回旧的 key(设置 key 的字符串 value 并返回其旧值)

redisTemplate.opsForValue().getAndSet(key, value);


在原有的值基础上新增字符串到末尾

redisTemplate.opsForValue().append(key, value)


获取字符串的长度

redisTemplate.opsForValue().size(key)


重新设置 key 对应的值,如果存在返回 false,否则返回 true

redisTemplate.opsForValue().setIfAbsent(key, value)


设置 map 集合到 redis

Map valueMap = new HashMap();  
valueMap.put("valueMap1","map1");  
valueMap.put("valueMap2","map2");  
valueMap.put("valueMap3","map3");  
redisTemplate.opsForValue().multiSet(valueMap); 


如果对应的 map 集合名称不存在,则添加否则不做修改

Map valueMap = new HashMap();  
valueMap.put("valueMap1","map1");  
valueMap.put("valueMap2","map2");  
valueMap.put("valueMap3","map3");  
redisTemplate.opsForValue().multiSetIfAbsent(valueMap); 


通过 increment(K key, long delta) 方法以增量方式存储 long 值(正值则自增,负值则自减)

redisTemplate.opsForValue().increment(key, increment);


批量获取值

public List<String> multiGet(Collection<String> keys) {
    return redisTemplate.opsForValue().multiGet(keys);
}
返回传入 key 所存储的值的类型

修改 redis 中 key 的名称

public void renameKey(String oldKey, String newKey) {
    redisTemplate.rename(oldKey, newKey);
}


如果旧值 key 存在时,将旧值改为新值

public Boolean renameOldKeyIfAbsent(String oldKey, String newKey) { 
 return redisTemplate.renameIfAbsent(oldKey, newKey);
}


判断是否有 key 所对应的值,有则返回 true,没有则返回 false

redisTemplate.hasKey(key)


删除单个 key 值

redisTemplate.delete(key)


批量删除 key

redisTemplate.delete(keys) //其中keys:Collection<K> keys


设置过期时间

public Boolean expire(String key, long timeout, TimeUnit unit){
 return redisTemplate.expire(key, timeout, unit);
}

public Boolean expireAt(String key, Date date) { 
 return redisTemplate.expireAt(key, date);
}


返回当前 key 所对应的剩余过期时间

redisTemplate.getExpire(key);


返回剩余过期时间并且指定时间单位

public Long getExpire(String key, TimeUnit unit) {
    return redisTemplate.getExpire(key, unit);
}


查找匹配的 key 值,返回一个 Set 集合类型

public Set<String> getPatternKey(String pattern) { 
    return redisTemplate.keys(pattern);
}


将 key 持久化保存

public Boolean persistKey(String key) {
    return redisTemplate.persist(key);
}


将当前数据库的 key 移动到指定 redis 中数据库当中

public Boolean moveToDbIndex(String key, int dbIndex) {
    return redisTemplate.move(key, dbIndex);
}


Hash 类型

Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。Redis 中每个 hash 可以存储 2^32 - 1 键值对(40多亿)。

获取变量中的指定 map 键是否有值,如果存在该 map 键则获取值,没有则返回 null。

redisTemplate.opsForHash().get(key, field)


获取变量中的键值对

public Map<Object, Object> hGetAll(String key) {
    return redisTemplate.opsForHash().entries(key);
}


新增 hashMap 值

redisTemplate.opsForHash().put(key, hashKey, value)


以 map 集合的形式添加键值对

public void hPutAll(String key, Map<String, String> maps) {
    redisTemplate.opsForHash().putAll(key, maps);
}


仅当 hashKey 不存在时才设置

public Boolean hashPutIfAbsent(String key, String hashKey, String value) { 
    return redisTemplate.opsForHash().putIfAbsent(key, hashKey, value);
}


删除一个或者多个 hash 表字段

public Long hashDelete(String key, Object... fields) {
    return redisTemplate.opsForHash().delete(key, fields);
}


查看 hash 表中指定字段是否存在

public boolean hashExists(String key, String field) { 
    return redisTemplate.opsForHash().hasKey(key, field);
}


给哈希表 key 中的指定字段的整数值加上增量 increment

public Long hashIncrBy(String key, Object field, long increment) {
    return redisTemplate.opsForHash().increment(key, field, increment);
}

public Double hIncrByDouble(String key, Object field, double delta) {
    return redisTemplate.opsForHash().increment(key, field, delta);
}


获取所有 hash 表中字段

redisTemplate.opsForHash().keys(key)


获取 hash 表中存在的所有的值

public List<Object> hValues(String key) {
    return redisTemplate.opsForHash().values(key);
}


获取 hash 表中字段的数量

redisTemplate.opsForHash().size(key)


匹配获取键值对,ScanOptions.NONE 为获取全部键对

public Cursor<Entry<Object, Object>> hashScan(String key, ScanOptions options) {
    return redisTemplate.opsForHash().scan(key, options);
}


List 类型

通过索引获取列表中的元素

redisTemplate.opsForList().index(key, index)
获取列表指定范围内的元素(start 开始位置, 0 是开始位置,end 结束位置, -1返回所有)

redisTemplate.opsForList().range(key, start, end)
存储在 list 的头部,即添加一个就把它放在最前面的索引处

redisTemplate.opsForList().leftPush(key, value)
把多个值存入 List 中(value 可以是多个值,也可以是一个 Collection value)

redisTemplate.opsForList().leftPushAll(key, value)
List 存在的时候再加入

redisTemplate.opsForList().leftPushIfPresent(key, value)
按照先进先出的顺序来添加(value 可以是多个值,或者是 Collection var2)

redisTemplate.opsForList().rightPush(key, value)
redisTemplate.opsForList().rightPushAll(key, value)
设置指定索引处元素的值

redisTemplate.opsForList().set(key, index, value)
移除并获取列表中第一个元素(如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止)

redisTemplate.opsForList().leftPop(key)
redisTemplate.opsForList().leftPop(key, timeout, unit)
移除并获取列表最后一个元素

redisTemplate.opsForList().rightPop(key)
redisTemplate.opsForList().rightPop(key, timeout, unit)
从一个队列的右边弹出一个元素并将这个元素放入另一个指定队列的最左边

redisTemplate.opsForList().rightPopAndLeftPush(sourceKey, destinationKey)
redisTemplate.opsForList().rightPopAndLeftPush(sourceKey, destinationKey, timeout, unit)
删除集合中值等于 value 的元素(index=0, 删除所有值等于 value 的元素; index>0, 从头部开始删除第一个值等于 value 的元素; index<0, 从尾部开始删除第一个值等于 value 的元素)

redisTemplate.opsForList().remove(key, index, value)
将 List 列表进行剪裁

redisTemplate.opsForList().trim(key, start, end)
获取当前 key 的 List 列表长度

redisTemplate.opsForList().size(key)


Set 类型

添加元素

redisTemplate.opsForSet().add(key, values)
移除元素(单个值、多个值)

redisTemplate.opsForSet().remove(key, values)
获取集合的大小

redisTemplate.opsForSet().size(key)
判断集合是否包含 value

redisTemplate.opsForSet().isMember(key, value)
获取两个集合的交集(key 对应的无序集合与 otherKey 对应的无序集合求交集)

redisTemplate.opsForSet().intersect(key, otherKey)
获取多个集合的交集(Collection var2)

redisTemplate.opsForSet().intersect(key, otherKeys)
key 集合与 otherKey 集合的交集存储到 destKey 集合中(其中 otherKey 可以为单个值或者集合)

redisTemplate.opsForSet().intersectAndStore(key, otherKey, destKey)
key 集合与多个集合的交集存储到 destKey 无序集合中

redisTemplate.opsForSet().intersectAndStore(key, otherKeys, destKey)
获取两个或者多个集合的并集(otherKeys 可以为单个值或者是集合)

redisTemplate.opsForSet().union(key, otherKeys)
key 集合与 otherKey 集合的并集存储到 destKey 中(otherKeys 可以为单个值或者是集合)

redisTemplate.opsForSet().unionAndStore(key, otherKey, destKey)
获取两个或者多个集合的差集(otherKeys 可以为单个值或者是集合)

redisTemplate.opsForSet().difference(key, otherKeys)
差集存储到 destKey 中(otherKeys 可以为单个值或者集合)

redisTemplate.opsForSet().differenceAndStore(key, otherKey, destKey)
获取集合中的所有元素

redisTemplate.opsForSet().members(key)
随机获取集合中 count 个元素

redisTemplate.opsForSet().randomMembers(key, count)
随机获取集合中的一个元素

redisTemplate.opsForSet().randomMember(key)
遍历 set 类似于 Interator(ScanOptions.NONE 为显示所有的)

redisTemplate.opsForSet().scan(key, options)


zset 类型

ZSetOperations 提供了一系列方法对有序集合进行操作,添加元素(有序集合是按照元素的 score 值由小到大进行排列)。

redisTemplate.opsForZSet().add(key, value, score)
删除对应的 value,value 可以为多个值

redisTemplate.opsForZSet().remove(key, values)
增加元素的 score 值,并返回增加后的值

redisTemplate.opsForZSet().incrementScore(key, value, delta)
返回元素在集合的排名,有序集合是按照元素的 score 值由小到大排列

redisTemplate.opsForZSet().rank(key, value)
返回元素在集合的排名,按元素的 score 值由大到小排列

redisTemplate.opsForZSet().reverseRank(key, value)
获取集合中给定区间的元素(start 开始位置,end 结束位置, -1 查询所有)

redisTemplate.opsForZSet().reverseRangeWithScores(key, start,end)
按照 Score 值查询集合中的元素,结果从小到大排序

redisTemplate.opsForZSet().reverseRangeByScore(key, min, max)
从高到低的排序集中获取分数在最小和最大值之间的元素

redisTemplate.opsForZSet().reverseRangeByScore(key, min, max, start, end)
根据 score 值获取集合元素数量

redisTemplate.opsForZSet().count(key, min, max)
获取集合的大小

redisTemplate.opsForZSet().size(key)
获取集合中 key、value 元素对应的 score 值

redisTemplate.opsForZSet().score(key, value)
移除指定索引位置处的成员

redisTemplate.opsForZSet().removeRange(key, start, end)
移除指定 score 范围的集合成员

redisTemplate.opsForZSet().removeRangeByScore(key, min, max)
获取 key 和 otherKey 的并集并存储在 destKey 中(其中 otherKeys 可以为单个字符串或者字符串集合)

redisTemplate.opsForZSet().unionAndStore(key, otherKey, destKey)
获取 key 和 otherKey 的交集并存储在 destKey 中(其中 otherKeys 可以为单个字符串或者字符串集合)

redisTemplate.opsForZSet().intersectAndStore(key, otherKey, destKey)
遍历集合(和 iterator 一模一样)

Cursor<TypedTuple<Object>> scan = opsForZSet.scan("test3", ScanOptions.NONE); while (scan.hasNext()){
ZSetOperations.TypedTuple<Object> item = scan.next();
System.out.println(item.getValue() \+ ":" + item.getScore());
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3226541.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

电脑突然出现“由于找不到msvcp140.dll”要怎么处理?教你科学的msvcp140.dll修复方法

电脑出现由于找不到msvcp140.dll的程序故障&#xff0c;请不要紧张&#xff0c;要解决这个问题还是比较简单的&#xff0c;当然前提是你要了解msvcp140.dll这个文件&#xff0c;只有了解了你解决起这个msvcp140.dll才会更简单&#xff01;下面我们一起来聊聊找不到msvcp140.dll…

springboot定制化书籍销售系统-计算机毕业设计源码71193

摘要 随着电子商务的快速发展和图书市场的不断变革&#xff0c;定制化书籍销售系统的需求日益凸显。本文介绍了一种基于SpringBoot框架的定制化书籍销售系统的设计与实现。该系统旨在满足用户对于个性化、专业化的书籍需求&#xff0c;为用户提供高效、便捷的定制化购书体验。 …

Spring Web MVC入门(1)(建立连接)

一.什么是Spring Web MVC? Spring Web MVC是基于ServletAPI构建的原始Web框架,从一开始就包含在Spring框架中.它的正式名称"Spring Web MVC"来自其源模块的名称(Spring-webmvc),但它通常被称为"Spring MVC". 二.MVC的定义 MVC是Model View Controller的缩…

fastadmin框架后台列表固定第一行列表固定头部

在列表中,如果列表字段很多,并且每页数量很多,往下拉的时候就不好辨别数据是哪个字段的,对用户造成不好的浏览体验。 通过以下方法,可以实现将列表的第一行,也就是头部,固定在第一行显示,这样就能轻松辨别每个数据对应是哪个字段的,增加用户的使用体验。 打开项目的…

UML图书管理系统用例图示例

新书速览|《UML 2.5基础、建模与设计实践》新书速览|《UML 2.5基础、建模与设计实践 【例4.4】图书管理系统用例图。 图书管理系统按其业务功能分成借阅者管理、图书管理、借书、还书和用户管理等几部分&#xff0c;这些职能对应于系统的不同组织部门。 1&#xff09;系统参…

即时设计初学者指南,零基础入门必看

1.1下载 即时设计目前支持个人免费使用&#xff0c;用户可以自由创建项目和文件&#xff0c;并邀请团队成员在线合作。即时设计支持网页端、macOS、Windows、Linux、iOS、Android 和微信小程序 1.2 安装 进入即时设计官网&#xff0c;点击免费使用即时设计或进入工作台&#…

基于conda包的环境创建、激活、管理与删除

Conda 是一个开源的包管理和环境管理系统。 很多不同的项目可能需要使用不同的环境。例如某个项目需要使用pytorch1.6&#xff0c;另一个项目需要使用pytorch1.8&#xff0c;那么conda包就可以创建两个虚拟环境&#xff0c;分别配置不同的资源&#xff0c;需要使用哪些资源就去…

14-52 剑和诗人26 - RAG 和 VectorDB 简介

检索增强生成 (RAG) 和 VectorDB 是自然语言处理 (NLP) 中的两个重要概念&#xff0c;它们正在突破 AI 系统所能实现的界限。 在这篇博文中&#xff0c;我将深入探讨 RAG&#xff0c;探索其工作原理、应用、优势和局限性。 我们还将研究 VectorDB&#xff0c;这是一种专用于向…

9月Sui Builder House新加坡站开启报名

本次以建设者为主的活动包括&#xff1a; 与Sui社区互动的机会庆祝Sui生态成就的时刻公布和发布新产品建设者学习、网络交流、分享和启动新项目的机会 该活动与Token2049新加坡同期进行&#xff0c;Token2049是一个全球性会议系列&#xff0c;汇集加密货币的决策者们交换想法…

RAGFlow开源Star量破万,是时候思考下RAG的未来是什么了

搜索技术是计算机科学中最难的技术挑战之一&#xff0c;迄今只有很少一部分商业化产品可以把这个问题解决得很好。大多数商品并不需要很强的搜索&#xff0c;因为这和用户体验并没有直接关系。然而&#xff0c;随着 LLM 的爆炸性增长&#xff0c;每家使用 LLM 的公司都需要内置…

CentOS 8升级gcc版本

1、查看gcc版本 gcc -v发现gcc版本为8.x.x&#xff0c;而跑某个项目的finetune需要gcc-9&#xff0c;之前搜索过很多更新gcc版本的方式&#xff0c;例如https://blog.csdn.net/xunye_dream/article/details/108918316?spm1001.2014.3001.5506&#xff0c;但执行指令 sudo yu…

为什么使用 Lumion 3D 渲染软件进行建筑可视化?

如今&#xff0c;建筑可视化的需求量很大。一些报告指出&#xff0c;到 2025 年&#xff0c;建筑可视化作品的市场规模可能达到 57.2 亿美元。这只能说明 3D 渲染和建筑可视化在当今的重要性日益增加。如今&#xff0c;它已成为广告、营销、沟通等诸多领域前所未有的工具。 Lu…

先进电机拓扑及控制算法介绍(1)——串联绕组电机拓扑极其控制

1.前言 在这个专栏&#xff0c;我会介绍一些比较先进的电机拓扑及控制算法&#xff0c;并且会做仿真来验证这些电机拓扑及控制算法的先进性。什么叫做“比较先进的电机拓扑及控制算法”呢&#xff1f; 在我看来&#xff0c;这些电机拓扑及控制算法被提出不久&#xff0c;知道…

【排序 - 冒泡排序】

当我们谈论经典的排序算法时&#xff0c;冒泡排序&#xff08;Bubble Sort&#xff09;往往是最先被提及的一种。尽管它在实际应用中不太常见&#xff0c;但冒泡排序的简单易懂&#xff0c;有助于理解排序算法的基本原理和思想。 冒泡排序的基本原理 冒泡排序是一种基础的交换…

武汉迈信EP5-TLO8与博途1200通讯

目录 一、伺服调试软件安装二、USB连接软件,参数设置三、专业软件设置IP和名称四、博途组态配置一、伺服调试软件安装 自己去看 二、USB连接软件,参数设置 三、专业软件设置IP和名称

软件测试实习生面试一般都问啥啊?

在软件测试面试中&#xff0c;高频被问的问题通常涵盖了多个方面&#xff0c;包括个人背景、技能水平、对测试的理解、测试方法和技术等。以上是高频被问软件测试面试题视频教程&#xff0c;以下是一些常见的问题&#xff1a; 个人背景与经验&#xff1a; 请简单介绍一下你自己…

Nginx -Web服务器/反向代理/负载均衡

文章目录 一、web服务1.1 nginx安装1.2 配置文件1.3 Nginx处理Web机制 二、反向代理三、负载均衡3.1 分类3.2 负载相关配置文件3.3 keepalive 提高吞吐量3.4 配置浏览器缓存 附、JMeter性能测试工具 以赛促学内容,因不只考题,而大概率感觉会使用nginx做web服务,特对nginx做总结…

数据迁移探索

概念 数据迁移是指将数据从一个计算环境或存储系统移动到另一个计算环境或存储系统。 随着公司业务的发展&#xff0c;出于成本优化、系统升级、分库分表、整合数据等原因。数据迁移工作在日常工作中会陆续出现。 我们可以将数据迁移分成两个部分&#xff0c;第一部分是数据…

借助钡铼经济型网关实现台达PLC设备与OPC UA的连接

随着工业自动化的发展&#xff0c;将传统的PLC设备接入现代化的网络通信系统变得越来越重要。OPC UA&#xff08;Open Platform Communications Unified Architecture&#xff09;作为工业领域通信的开放标准&#xff0c;提供了安全、可靠且跨平台的数据传输能力&#xff0c;因…

淘宝商品历史价格查询(免费)

当前资料来源于网络&#xff0c;禁止用于商用&#xff0c;仅限于学习。 淘宝联盟里面就可以看到历史价格 并且没有加密 淘宝商品历史价格查询可以通过以下步骤进行&#xff1a; 先下载后&#xff0c;登录app注册账户 打开淘宝网站或淘宝手机App。在搜索框中输入你想要查询的商…