当前位置: 首页 > news >正文

哈尔滨营销网站建设公司/深圳百度推广客服

哈尔滨营销网站建设公司,深圳百度推广客服,自己做一个网站难么,白石洲附近做网站公司这节记录下如何使用redis缓存数据库。 第一步: 先在服务器端安装redis, 下载地址:Releases tporadowski/redis GitHub。 第二步: 安装redis客户端可视化管理软件redisDesktopmanager Redis Desktop Manager - Download 第…

这节记录下如何使用redis缓存数据库。

第一步:

先在服务器端安装redis,

下载地址:Releases · tporadowski/redis · GitHub。

第二步:

安装redis客户端可视化管理软件redisDesktopmanager

Redis Desktop Manager - Download

第三步:

设置redis缓存服务器的密码。

方式一(临时密码):打开redis-server.exe,输入config set requirepass 密码
方式二:永久密码,修改redis的conf文件,在conf中搜索requirepass。记得修改了以后重启(先停止再启动)redis的服务,不然不生效。

第四步:Redis Desktop Manager管理软件,测试是否能连接上Redis服务器。

​​
在这里插入图片描述

第五步:开始配置Springboot中的redis

在application-local.yml文章中


spring:datasource:url: jdbc:mysql://localhost:3306/test123?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTCusername: rootpassword:driver-class-name: com.mysql.cj.jdbc.Drivertype: com.zaxxer.hikari.HikariDataSource# 连接池hikari:minimum-idle: 10maximum-pool-size: 20idle-timeout: 300000max-lifetime: 1800000connection-timeout: 30000pool-name: SpringHikariCPdata:redis:host: 127.0.0.1password: 123456

第六步:编写测试代码

 @PostMappingpublic void save(){List<Student> studentList =   studentService.list();stringRedisTemplate.opsForValue().set("studentList", JSONUtil.toJsonStr(studentList));}@GetMappingpublic List<Student> list(){List<Student> list = JSONUtil.toList(stringRedisTemplate.opsForValue().get("studentList"),Student.class);return list;}@PutMappingpublic void update(){List<Student> list = JSONUtil.toList(stringRedisTemplate.opsForValue().get("studentList"),Student.class);Student student1 = new Student();student1.setName("小王");student1.setAge(18);student1.setCreate_time(new Date());list.add(student1);stringRedisTemplate.opsForValue().set("studentList",JSONUtil.toJsonStr(list));return ;}@DeleteMappingpublic void delete(){stringRedisTemplate.delete("studentList");}

第七步:观察redis存储结果

在这里插入图片描述

上面记录了操作步骤。
那么接下来我们对代码进行分析。

一:redis是如何获取applocation.yml中的配置参数的?

Redis并不直接“获取”application.yml中的配置参数,而是Spring Boot框架在启动过程中读取这些配置参数,并据此配置Redis连接。应用程序通过Spring Boot提供的接口(如RedisTemplate)与Redis进行交互,而无需直接关心连接参数的配置。这种方式简化了应用程序与Redis的集成过程,提高了开发效率。

二:StringRedisTemplate类什么?

StringRedisTemplate类是Spring Data Redis提供的一个用于操作Redis的模板类。它专门用于处理Redis中的String类型数据,提供了一系列简化操作的方法,使开发者可以方便地进行数据的读取、写入和删除等操作,而无需关心底层Redis的连接和数据序列化等细节。
主要特点和用法
简化的操作方法:StringRedisTemplate封装了一系列简化的操作方法,如设置、获取、删除String类型数据等,开发者可以直接调用这些方法来进行操作,而无需关心Redis的底层实现。
与Spring集成:StringRedisTemplate是基于Spring框架提供的RedisTemplate实现的,因此可以与Spring应用程序无缝集成,通过依赖注入的方式进行使用。
支持事务:StringRedisTemplate支持在事务中进行操作,可以保证多个操作的原子性,确保数据的一致性。
支持序列化:StringRedisTemplate支持将Java对象序列化成Redis数据格式,以及将Redis数据反序列化成Java对象,方便开发者进行数据存取操作。
提供回调接口:StringRedisTemplate还提供了一些回调接口,如RedisCallback和SessionCallback,开发者可以通过这些接口来执行自定义的Redis操作,更灵活地控制Redis的使用。
构造方法
StringRedisTemplate提供了多种构造方法,通常开发者会通过配置Redis连接信息(如主机名、端口号等)来创建连接工厂,然后使用连接工厂来创建StringRedisTemplate实例。
常用操作方法
以下是一些常用的操作方法示例:

设置值:通过opsForValue().set(String key, String value)方法可以设置键值对。
获取值:通过opsForValue().get(String key)方法可以根据键获取对应的值。
删除值:通过delete(String key)方法可以删除指定的键值对。
追加字符串:通过opsForValue().append(String key, String value)方法可以向指定的键对应的字符串值的末尾追加值。
自增自减:通过opsForValue().increment(String key)和opsForValue().decrement(String key)方法可以实现字符串类型数据的自增和自减操作。
设置过期时间:在设置值时,可以指定过期时间,如opsForValue().set(String key, String value, long timeout, TimeUnit unit)方法。
注意事项
在使用StringRedisTemplate时,需要注意Redis服务器的连接信息配置,包括主机名、端口号、密码等。
对于数据类型为String的Redis操作,StringRedisTemplate提供了非常便捷的方法,但对于其他类型的数据(如Hash、List、Set等),则可能需要使用RedisTemplate或其他工具类进行操作。
在进行大量数据操作时,需要注意Redis的性能和内存使用情况,避免造成不必要的性能瓶颈或内存溢出等问题。

StringRedisTemplate 类源码

继承结构
在这里插入图片描述

//
// 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);}
}

源码分析:
StringRedisTemplate 继承自 RedisTemplate<String, String>,这意味着它是一个泛型类,其中键(Key)和值(Value)的类型都限定为 String。

StringRedisTemplate()这个构造函数通过调用 setKeySerializer、setValueSerializer、setHashKeySerializer 和 setHashValueSerializer 方法,将键、值、哈希键和哈希值的序列化器都设置为 RedisSerializer.string()。这意味着所有的键和值在存入 Redis 之前都会被转换成字符串,从 Redis 取出时也会从字符串转换回原来的类型(在这个场景下,由于本身就是字符串,所以实际上不需要转换)。

三:StringRedisTemplate和RedisTemplate区别在哪里

StringRedisTemplate和RedisTemplate在Spring框架中都是用于操作Redis数据库的模板类,但它们之间存在一些明显的区别,主要体现在以下几个方面:

1. 序列化策略

  • StringRedisTemplate:采用的是String的序列化策略,即它将Java对象序列化为字符串形式存储在Redis中,同时也将Redis中的字符串反序列化为Java对象。这种方式简化了操作,因为字符串是Redis中最基本的数据类型,支持的操作简单高效。
  • RedisTemplate:默认采用的是JDK的序列化策略(JdkSerializationRedisSerializer),即它将Java对象序列化为字节数组存储在Redis中。这种方式虽然可以处理任意类型的Java对象,但在Redis-cli中查看时可能会显示为乱码。不过,RedisTemplate的序列化策略是可以自定义的,常用的还有Jackson2JsonRedisSerializer等,可以将对象序列化为JSON字符串存储在Redis中。

2. 存储数据类型

  • StringRedisTemplate:专注于处理Redis中的String类型数据,提供了一系列简化操作String类型数据的方法。
  • RedisTemplate:是一个泛型类,可以对Redis中的任意类型数据进行操作,包括但不限于String、Hash、List、Set和Sorted Set等。它提供了丰富的API来支持这些数据类型的操作。

3. 使用范围

  • StringRedisTemplate:由于其专注于String类型数据,因此适用于存储简单的键值对、缓存数据、计数器等场景。
  • RedisTemplate:由于其泛型特性和丰富的API,适用于需要存储复杂对象或进行复杂查询的场景。如果你需要存取复杂的对象,并且不想做额外的处理,那么RedisTemplate可能是一个更好的选择。

4. 继承关系

  • StringRedisTemplate:实际上是RedisTemplate的一个子类,它在继承RedisTemplate的基础上,将泛型类型指定为了String,从而限制了其只能处理String类型的键值对。

5. 示例

假设我们有一个User对象需要存储到Redis中:

  • 使用StringRedisTemplate时,如果直接尝试存储User对象,会报错,因为StringRedisTemplate的set方法只接受String类型的键和值。我们需要先将User对象转换为String(例如通过JSON序列化),然后再存储。
  • 使用RedisTemplate时,如果采用默认的JDK序列化策略,可以直接存储User对象,但在Redis-cli中查看时会是乱码。如果采用JSON序列化策略(如Jackson2JsonRedisSerializer),则可以将User对象序列化为JSON字符串后存储,这样在Redis-cli中查看时会是可读的JSON字符串。

综上所述,StringRedisTemplate和RedisTemplate在序列化策略、存储数据类型、使用范围、继承关系等方面存在明显的区别。在选择使用哪个模板类时,需要根据具体的应用场景和需求来决定。

四:RedisTemplate源码

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {private boolean enableTransactionSupport = false;private boolean exposeConnection = false;private boolean initialized = false;private boolean enableDefaultSerializer = true;@Nullableprivate RedisSerializer<?> defaultSerializer;@Nullableprivate ClassLoader classLoader;@Nullableprivate RedisSerializer keySerializer = null;@Nullableprivate RedisSerializer valueSerializer = null;@Nullableprivate RedisSerializer hashKeySerializer = null;@Nullableprivate RedisSerializer hashValueSerializer = null;private RedisSerializer<String> stringSerializer = RedisSerializer.string();@Nullableprivate ScriptExecutor<K> scriptExecutor;private final BoundOperationsProxyFactory boundOperations = new BoundOperationsProxyFactory();private final ValueOperations<K, V> valueOps = new DefaultValueOperations(this);private final ListOperations<K, V> listOps = new DefaultListOperations(this);private final SetOperations<K, V> setOps = new DefaultSetOperations(this);private final StreamOperations<K, ?, ?> streamOps = new DefaultStreamOperations(this, ObjectHashMapper.getSharedInstance());private final ZSetOperations<K, V> zSetOps = new DefaultZSetOperations(this);private final GeoOperations<K, V> geoOps = new DefaultGeoOperations(this);private final HyperLogLogOperations<K, V> hllOps = new DefaultHyperLogLogOperations(this);private final ClusterOperations<K, V> clusterOps = new DefaultClusterOperations(this);public RedisTemplate() {}public void afterPropertiesSet() {super.afterPropertiesSet();if (this.defaultSerializer == null) {this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());}if (this.enableDefaultSerializer) {if (this.keySerializer == null) {this.keySerializer = this.defaultSerializer;}if (this.valueSerializer == null) {this.valueSerializer = this.defaultSerializer;}if (this.hashKeySerializer == null) {this.hashKeySerializer = this.defaultSerializer;}if (this.hashValueSerializer == null) {this.hashValueSerializer = this.defaultSerializer;}}if (this.scriptExecutor == null) {this.scriptExecutor = new DefaultScriptExecutor(this);}this.initialized = true;}public boolean isExposeConnection() {return this.exposeConnection;}public void setExposeConnection(boolean exposeConnection) {this.exposeConnection = exposeConnection;}public boolean isEnableDefaultSerializer() {return this.enableDefaultSerializer;}public void setEnableDefaultSerializer(boolean enableDefaultSerializer) {this.enableDefaultSerializer = enableDefaultSerializer;}public void setEnableTransactionSupport(boolean enableTransactionSupport) {this.enableTransactionSupport = enableTransactionSupport;}public void setBeanClassLoader(ClassLoader classLoader) {this.classLoader = classLoader;}@Nullablepublic RedisSerializer<?> getDefaultSerializer() {return this.defaultSerializer;}public void setDefaultSerializer(RedisSerializer<?> serializer) {this.defaultSerializer = serializer;}public void setKeySerializer(RedisSerializer<?> serializer) {this.keySerializer = serializer;}public RedisSerializer<?> getKeySerializer() {return this.keySerializer;}public void setValueSerializer(RedisSerializer<?> serializer) {this.valueSerializer = serializer;}public RedisSerializer<?> getValueSerializer() {return this.valueSerializer;}public RedisSerializer<?> getHashKeySerializer() {return this.hashKeySerializer;}public void setHashKeySerializer(RedisSerializer<?> hashKeySerializer) {this.hashKeySerializer = hashKeySerializer;}public RedisSerializer<?> getHashValueSerializer() {return this.hashValueSerializer;}public void setHashValueSerializer(RedisSerializer<?> hashValueSerializer) {this.hashValueSerializer = hashValueSerializer;}public RedisSerializer<String> getStringSerializer() {return this.stringSerializer;}public void setStringSerializer(RedisSerializer<String> stringSerializer) {this.stringSerializer = stringSerializer;}public void setScriptExecutor(ScriptExecutor<K> scriptExecutor) {this.scriptExecutor = scriptExecutor;}@Nullablepublic <T> T execute(RedisCallback<T> action) {return this.execute(action, this.isExposeConnection());}@Nullablepublic <T> T execute(RedisCallback<T> action, boolean exposeConnection) {return this.execute(action, exposeConnection, false);}@Nullablepublic <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {Assert.isTrue(this.initialized, "template not initialized; call afterPropertiesSet() before using it");Assert.notNull(action, "Callback object must not be null");RedisConnectionFactory factory = this.getRequiredConnectionFactory();RedisConnection conn = RedisConnectionUtils.getConnection(factory, this.enableTransactionSupport);Object var11;try {boolean existingConnection = TransactionSynchronizationManager.hasResource(factory);RedisConnection connToUse = this.preProcessConnection(conn, existingConnection);boolean pipelineStatus = connToUse.isPipelined();if (pipeline && !pipelineStatus) {connToUse.openPipeline();}RedisConnection connToExpose = exposeConnection ? connToUse : this.createRedisConnectionProxy(connToUse);T result = action.doInRedis(connToExpose);if (pipeline && !pipelineStatus) {connToUse.closePipeline();}var11 = this.postProcessResult(result, connToUse, existingConnection);} finally {RedisConnectionUtils.releaseConnection(conn, factory);}return var11;}public <T> T execute(SessionCallback<T> session) {Assert.isTrue(this.initialized, "template not initialized; call afterPropertiesSet() before using it");Assert.notNull(session, "Callback object must not be null");RedisConnectionFactory factory = this.getRequiredConnectionFactory();RedisConnectionUtils.bindConnection(factory, this.enableTransactionSupport);Object var3;try {var3 = session.execute(this);} finally {RedisConnectionUtils.unbindConnection(factory);}return var3;}public List<Object> executePipelined(SessionCallback<?> session) {return this.executePipelined(session, this.valueSerializer);}public List<Object> executePipelined(SessionCallback<?> session, @Nullable RedisSerializer<?> resultSerializer) {Assert.isTrue(this.initialized, "template not initialized; call afterPropertiesSet() before using it");Assert.notNull(session, "Callback object must not be null");RedisConnectionFactory factory = this.getRequiredConnectionFactory();RedisConnectionUtils.bindConnection(factory, this.enableTransactionSupport);List var4;try {var4 = (List)this.execute((connection) -> {connection.openPipeline();boolean pipelinedClosed = false;List var7;try {Object result = this.executeSession(session);if (result != null) {throw new InvalidDataAccessApiUsageException("Callback cannot return a non-null value as it gets overwritten by the pipeline");}List<Object> closePipeline = connection.closePipeline();pipelinedClosed = true;var7 = this.deserializeMixedResults(closePipeline, resultSerializer, this.hashKeySerializer, this.hashValueSerializer);} finally {if (!pipelinedClosed) {connection.closePipeline();}}return var7;});} finally {RedisConnectionUtils.unbindConnection(factory);}return var4;}public List<Object> executePipelined(RedisCallback<?> action) {return this.executePipelined(action, this.valueSerializer);}public List<Object> executePipelined(RedisCallback<?> action, @Nullable RedisSerializer<?> resultSerializer) {return (List)this.execute((connection) -> {connection.openPipeline();boolean pipelinedClosed = false;List var7;try {Object result = action.doInRedis(connection);if (result != null) {throw new InvalidDataAccessApiUsageException("Callback cannot return a non-null value as it gets overwritten by the pipeline");}List<Object> closePipeline = connection.closePipeline();pipelinedClosed = true;var7 = this.deserializeMixedResults(closePipeline, resultSerializer, this.hashKeySerializer, this.hashValueSerializer);} finally {if (!pipelinedClosed) {connection.closePipeline();}}return var7;});}public <T> T execute(RedisScript<T> script, List<K> keys, Object... args) {return this.scriptExecutor.execute(script, keys, args);}public <T> T execute(RedisScript<T> script, RedisSerializer<?> argsSerializer, RedisSerializer<T> resultSerializer, List<K> keys, Object... args) {return this.scriptExecutor.execute(script, argsSerializer, resultSerializer, keys, args);}public <T extends Closeable> T executeWithStickyConnection(RedisCallback<T> callback) {Assert.isTrue(this.initialized, "template not initialized; call afterPropertiesSet() before using it");Assert.notNull(callback, "Callback object must not be null");RedisConnectionFactory factory = this.getRequiredConnectionFactory();RedisConnection connection = this.preProcessConnection(RedisConnectionUtils.doGetConnection(factory, true, false, false), false);return (Closeable)callback.doInRedis(connection);}private Object executeSession(SessionCallback<?> session) {return session.execute(this);}protected RedisConnection createRedisConnectionProxy(RedisConnection connection) {Class<?>[] ifcs = ClassUtils.getAllInterfacesForClass(connection.getClass(), this.getClass().getClassLoader());return (RedisConnection)Proxy.newProxyInstance(connection.getClass().getClassLoader(), ifcs, new CloseSuppressingInvocationHandler(connection));}protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) {return connection;}@Nullableprotected <T> T postProcessResult(@Nullable T result, RedisConnection conn, boolean existingConnection) {return result;}public Boolean copy(K source, K target, boolean replace) {byte[] sourceKey = this.rawKey(source);byte[] targetKey = this.rawKey(target);return (Boolean)this.doWithKeys((connection) -> {return connection.copy(sourceKey, targetKey, replace);});}public Boolean hasKey(K key) {byte[] rawKey = this.rawKey(key);return (Boolean)this.doWithKeys((connection) -> {return connection.exists(rawKey);});}public Long countExistingKeys(Collection<K> keys) {Assert.notNull(keys, "Keys must not be null");byte[][] rawKeys = this.rawKeys(keys);return (Long)this.doWithKeys((connection) -> {return connection.exists(rawKeys);});}public Boolean delete(K key) {byte[] rawKey = this.rawKey(key);Long result = (Long)this.doWithKeys((connection) -> {return connection.del(new byte[][]{rawKey});});return result != null && result.intValue() == 1;}public Long delete(Collection<K> keys) {if (CollectionUtils.isEmpty(keys)) {return 0L;} else {byte[][] rawKeys = this.rawKeys(keys);return (Long)this.doWithKeys((connection) -> {return connection.del(rawKeys);});}}public Boolean unlink(K key) {byte[] rawKey = this.rawKey(key);Long result = (Long)this.doWithKeys((connection) -> {return connection.unlink(new byte[][]{rawKey});});return result != null && result.intValue() == 1;}public Long unlink(Collection<K> keys) {if (CollectionUtils.isEmpty(keys)) {return 0L;} else {byte[][] rawKeys = this.rawKeys(keys);return (Long)this.doWithKeys((connection) -> {return connection.unlink(rawKeys);});}}public DataType type(K key) {byte[] rawKey = this.rawKey(key);return (DataType)this.doWithKeys((connection) -> {return connection.type(rawKey);});}public Set<K> keys(K pattern) {byte[] rawKey = this.rawKey(pattern);Set<byte[]> rawKeys = (Set)this.doWithKeys((connection) -> {return connection.keys(rawKey);});return this.keySerializer != null ? SerializationUtils.deserialize(rawKeys, this.keySerializer) : rawKeys;}public Cursor<K> scan(ScanOptions options) {Assert.notNull(options, "ScanOptions must not be null");return (Cursor)this.executeWithStickyConnection((connection) -> {return new ConvertingCursor(connection.scan(options), this::deserializeKey);});}public K randomKey() {byte[] rawKey = (byte[])this.doWithKeys(RedisKeyCommands::randomKey);return this.deserializeKey(rawKey);}public void rename(K oldKey, K newKey) {byte[] rawOldKey = this.rawKey(oldKey);byte[] rawNewKey = this.rawKey(newKey);this.doWithKeys((connection) -> {connection.rename(rawOldKey, rawNewKey);return null;});}public Boolean renameIfAbsent(K oldKey, K newKey) {byte[] rawOldKey = this.rawKey(oldKey);byte[] rawNewKey = this.rawKey(newKey);return (Boolean)this.doWithKeys((connection) -> {return connection.renameNX(rawOldKey, rawNewKey);});}public Boolean expire(K key, final long timeout, final TimeUnit unit) {byte[] rawKey = this.rawKey(key);long rawTimeout = TimeoutUtils.toMillis(timeout, unit);return (Boolean)this.doWithKeys((connection) -> {try {return connection.pExpire(rawKey, rawTimeout);} catch (Exception var8) {return connection.expire(rawKey, TimeoutUtils.toSeconds(timeout, unit));}});}public Boolean expireAt(K key, final Date date) {byte[] rawKey = this.rawKey(key);return (Boolean)this.doWithKeys((connection) -> {try {return connection.pExpireAt(rawKey, date.getTime());} catch (Exception var4) {return connection.expireAt(rawKey, date.getTime() / 1000L);}});}public Boolean persist(K key) {byte[] rawKey = this.rawKey(key);return (Boolean)this.doWithKeys((connection) -> {return connection.persist(rawKey);});}public Long getExpire(K key) {byte[] rawKey = this.rawKey(key);return (Long)this.doWithKeys((connection) -> {return connection.ttl(rawKey);});}public Long getExpire(K key, TimeUnit timeUnit) {byte[] rawKey = this.rawKey(key);return (Long)this.doWithKeys((connection) -> {try {return connection.pTtl(rawKey, timeUnit);} catch (Exception var4) {return connection.ttl(rawKey, timeUnit);}});}public Boolean move(K key, final int dbIndex) {byte[] rawKey = this.rawKey(key);return (Boolean)this.doWithKeys((connection) -> {return connection.move(rawKey, dbIndex);});}public byte[] dump(K key) {byte[] rawKey = this.rawKey(key);return (byte[])this.doWithKeys((connection) -> {return connection.dump(rawKey);});}public void restore(K key, byte[] value, long timeToLive, TimeUnit unit, boolean replace) {byte[] rawKey = this.rawKey(key);long rawTimeout = TimeoutUtils.toMillis(timeToLive, unit);this.doWithKeys((connection) -> {connection.restore(rawKey, rawTimeout, value, replace);return null;});}@Nullableprivate <T> T doWithKeys(Function<RedisKeyCommands, T> action) {return this.execute((connection) -> {return action.apply(connection.keyCommands());}, true);}public List<V> sort(SortQuery<K> query) {return this.sort(query, this.valueSerializer);}public <T> List<T> sort(SortQuery<K> query, @Nullable RedisSerializer<T> resultSerializer) {byte[] rawKey = this.rawKey(query.getKey());SortParameters params = QueryUtils.convertQuery(query, this.stringSerializer);List<byte[]> vals = (List)this.doWithKeys((connection) -> {return connection.sort(rawKey, params);});return SerializationUtils.deserialize(vals, resultSerializer);}public <T> List<T> sort(SortQuery<K> query, BulkMapper<T, V> bulkMapper) {return this.sort(query, bulkMapper, this.valueSerializer);}public <T, S> List<T> sort(SortQuery<K> query, BulkMapper<T, S> bulkMapper, @Nullable RedisSerializer<S> resultSerializer) {List<S> values = this.sort(query, resultSerializer);if (values != null && !values.isEmpty()) {int bulkSize = query.getGetPattern().size();List<T> result = new ArrayList(values.size() / bulkSize + 1);List<S> bulk = new ArrayList(bulkSize);Iterator var8 = values.iterator();while(var8.hasNext()) {S s = var8.next();bulk.add(s);if (bulk.size() == bulkSize) {result.add(bulkMapper.mapBulk(Collections.unmodifiableList(bulk)));bulk = new ArrayList(bulkSize);}}return result;} else {return Collections.emptyList();}}public Long sort(SortQuery<K> query, K storeKey) {byte[] rawStoreKey = this.rawKey(storeKey);byte[] rawKey = this.rawKey(query.getKey());SortParameters params = QueryUtils.convertQuery(query, this.stringSerializer);return (Long)this.doWithKeys((connection) -> {return connection.sort(rawKey, params, rawStoreKey);});}public void watch(K key) {byte[] rawKey = this.rawKey(key);this.executeWithoutResult((connection) -> {connection.watch(new byte[][]{rawKey});});}public void watch(Collection<K> keys) {byte[][] rawKeys = this.rawKeys(keys);this.executeWithoutResult((connection) -> {connection.watch(rawKeys);});}public void unwatch() {this.executeWithoutResult(RedisTxCommands::unwatch);}public void multi() {this.executeWithoutResult(RedisTxCommands::multi);}public void discard() {this.executeWithoutResult(RedisTxCommands::discard);}public List<Object> exec() {List<Object> results = this.execRaw();return this.getRequiredConnectionFactory().getConvertPipelineAndTxResults() ? this.deserializeMixedResults(results, this.valueSerializer, this.hashKeySerializer, this.hashValueSerializer) : results;}public List<Object> exec(RedisSerializer<?> valueSerializer) {return this.deserializeMixedResults(this.execRaw(), valueSerializer, valueSerializer, valueSerializer);}protected List<Object> execRaw() {List<Object> raw = (List)this.execute(RedisTxCommands::exec);return raw == null ? Collections.emptyList() : raw;}public List<RedisClientInfo> getClientList() {return (List)this.execute(RedisServerCommands::getClientList);}public void killClient(String host, int port) {this.executeWithoutResult((connection) -> {connection.killClient(host, port);});}public void replicaOf(String host, int port) {this.executeWithoutResult((connection) -> {connection.replicaOf(host, port);});}public void replicaOfNoOne() {this.executeWithoutResult(RedisServerCommands::replicaOfNoOne);}public Long convertAndSend(String channel, Object message) {Assert.hasText(channel, "a non-empty channel is required");byte[] rawChannel = this.rawString(channel);byte[] rawMessage = this.rawValue(message);return (Long)this.execute((connection) -> {return connection.publish(rawChannel, rawMessage);}, true);}private void executeWithoutResult(Consumer<RedisConnection> action) {this.execute((it) -> {action.accept(it);return null;}, true);}public ClusterOperations<K, V> opsForCluster() {return this.clusterOps;}public GeoOperations<K, V> opsForGeo() {return this.geoOps;}public BoundGeoOperations<K, V> boundGeoOps(K key) {return (BoundGeoOperations)this.boundOperations.createProxy(BoundGeoOperations.class, key, DataType.ZSET, this, RedisOperations::opsForGeo);}public <HK, HV> BoundHashOperations<K, HK, HV> boundHashOps(K key) {return (BoundHashOperations)this.boundOperations.createProxy(BoundHashOperations.class, key, DataType.HASH, this, (it) -> {return it.opsForHash();});}public <HK, HV> HashOperations<K, HK, HV> opsForHash() {return new DefaultHashOperations(this);}public HyperLogLogOperations<K, V> opsForHyperLogLog() {return this.hllOps;}public ListOperations<K, V> opsForList() {return this.listOps;}public BoundListOperations<K, V> boundListOps(K key) {return (BoundListOperations)this.boundOperations.createProxy(BoundListOperations.class, key, DataType.LIST, this, RedisOperations::opsForList);}public BoundSetOperations<K, V> boundSetOps(K key) {return (BoundSetOperations)this.boundOperations.createProxy(BoundSetOperations.class, key, DataType.SET, this, RedisOperations::opsForSet);}public SetOperations<K, V> opsForSet() {return this.setOps;}public <HK, HV> StreamOperations<K, HK, HV> opsForStream() {return this.streamOps;}public <HK, HV> StreamOperations<K, HK, HV> opsForStream(HashMapper<? super K, ? super HK, ? super HV> hashMapper) {return new DefaultStreamOperations(this, hashMapper);}public <HK, HV> BoundStreamOperations<K, HK, HV> boundStreamOps(K key) {return (BoundStreamOperations)this.boundOperations.createProxy(BoundStreamOperations.class, key, DataType.STREAM, this, (it) -> {return this.opsForStream();});}public BoundValueOperations<K, V> boundValueOps(K key) {return (BoundValueOperations)this.boundOperations.createProxy(BoundValueOperations.class, key, DataType.STRING, this, RedisOperations::opsForValue);}public ValueOperations<K, V> opsForValue() {return this.valueOps;}public BoundZSetOperations<K, V> boundZSetOps(K key) {return (BoundZSetOperations)this.boundOperations.createProxy(BoundZSetOperations.class, key, DataType.ZSET, this, RedisOperations::opsForZSet);}public ZSetOperations<K, V> opsForZSet() {return this.zSetOps;}private byte[] rawKey(Object key) {Assert.notNull(key, "non null key required");if (this.keySerializer == null && key instanceof byte[] bytes) {return bytes;} else {return this.keySerializer.serialize(key);}}private byte[] rawString(String key) {return this.stringSerializer.serialize(key);}private byte[] rawValue(Object value) {if (this.valueSerializer == null && value instanceof byte[] bytes) {return bytes;} else {return this.valueSerializer.serialize(value);}}private byte[][] rawKeys(Collection<K> keys) {byte[][] rawKeys = new byte[keys.size()][];int i = 0;Object key;for(Iterator var4 = keys.iterator(); var4.hasNext(); rawKeys[i++] = this.rawKey(key)) {key = var4.next();}return rawKeys;}private K deserializeKey(byte[] value) {return this.keySerializer != null ? this.keySerializer.deserialize(value) : value;}@Nullableprivate List<Object> deserializeMixedResults(@Nullable List<Object> rawValues, @Nullable RedisSerializer valueSerializer, @Nullable RedisSerializer hashKeySerializer, @Nullable RedisSerializer hashValueSerializer) {if (rawValues == null) {return null;} else {List<Object> values = new ArrayList();Iterator var6 = rawValues.iterator();while(true) {while(var6.hasNext()) {Object rawValue = var6.next();if (rawValue instanceof byte[]) {byte[] bytes = (byte[])rawValue;if (valueSerializer != null) {values.add(valueSerializer.deserialize(bytes));continue;}}if (rawValue instanceof List) {List list = (List)rawValue;values.add(this.deserializeMixedResults(list, valueSerializer, hashKeySerializer, hashValueSerializer));} else {if (rawValue instanceof Set) {Set set = (Set)rawValue;if (!set.isEmpty()) {values.add(this.deserializeSet(set, valueSerializer));continue;}}if (rawValue instanceof Map) {Map map = (Map)rawValue;if (!map.isEmpty() && map.values().iterator().next() instanceof byte[]) {values.add(SerializationUtils.deserialize(map, hashKeySerializer, hashValueSerializer));continue;}}values.add(rawValue);}}return values;}}}private Set<?> deserializeSet(Set rawSet, @Nullable RedisSerializer valueSerializer) {if (rawSet.isEmpty()) {return rawSet;} else {Object setValue = rawSet.iterator().next();if (setValue instanceof byte[] && valueSerializer != null) {return SerializationUtils.deserialize(rawSet, valueSerializer);} else {return setValue instanceof Tuple ? this.convertTupleValues(rawSet, valueSerializer) : rawSet;}}}private Set<ZSetOperations.TypedTuple<V>> convertTupleValues(Set<Tuple> rawValues, @Nullable RedisSerializer valueSerializer) {Set<ZSetOperations.TypedTuple<V>> set = new LinkedHashSet(rawValues.size());Tuple rawValue;Object value;for(Iterator var4 = rawValues.iterator(); var4.hasNext(); set.add(new DefaultTypedTuple(value, rawValue.getScore()))) {rawValue = (Tuple)var4.next();value = rawValue.getValue();if (valueSerializer != null) {value = valueSerializer.deserialize(rawValue.getValue());}}return set;}
}

继承结构
在这里插入图片描述
很明显StringRedisTemplate和RedisTemplate是父类和子类关系。

在上面源码里看到,StringRedisTemplate并无重写RedisTemplate的任何方法。所以拥有RedisTemplate的所有方法。

五:StringRedisTemplate的主要方法有哪些?怎么设置缓存过期时间?

StringRedisTemplate是Spring Framework提供的一个用于操作Redis数据库中String类型数据的模板类。它基于RedisTemplate实现,并专注于处理Redis中的String类型数据,提供了一系列简化操作的方法。以下是StringRedisTemplate的一些常用方法讲解:

1. 字符串操作

设置和获取值
  • opsForValue().set(String key, String value):向Redis中存入一个字符串类型的键值对。
  • opsForValue().get(Object key):根据键获取对应的值。
设置带有过期时间的值
  • opsForValue().set(String key, String value, long timeout, TimeUnit unit):向Redis中存入一个字符串类型的键值对,并设置过期时间。timeout是过期时长,unit是时间单位(如秒、分钟等)。
递增和递减
  • opsForValue().increment(String key):将存储在键中的数字值增加1。
  • opsForValue().increment(String key, long delta):将存储在键中的数字值增加指定的增量值delta
  • opsForValue().decrement(String key)opsForValue().decrement(String key, long delta):与递增操作类似,但用于减少数字值。

2. 哈希操作

  • opsForHash().put(String key, Object hashKey, Object value):向哈希表中添加一个字段。
  • opsForHash().entries(String key):获取存储在哈希表中指定键的所有字段和值。

3. 列表操作

  • opsForList().leftPush(String key, String value):将一个或多个值插入到列表头部。
  • opsForList().rightPush(String key, String value):将一个或多个值插入到列表尾部。
  • opsForList().range(String key, long start, long end):通过索引区间返回列表中的一部分元素。

4. 集合操作

  • opsForSet().add(String key, String... values):向集合添加一个或多个成员。
  • opsForSet().members(String key):返回集合中的所有成员。

5. 有序集合操作

  • opsForZSet().add(String key, double score, String value):将一个或多个成员及其分数加入到有序集合中。
  • opsForZSet().range(String key, long start, long end):通过索引区间返回有序集合中指定区间的成员。

6. 其他常用方法

  • delete(String key, Object... keys):根据提供的键删除缓存中的数据。
  • hasKey(String key):检查键是否存在。
  • getExpire(String key, TimeUnit unit):获取键的剩余生存时间,并转换成指定的时间单位。

注意事项

  • 使用StringRedisTemplate时,通常不需要额外配置序列化器,因为它默认使用String序列化策略。但如果需要存储复杂对象,可能需要自定义序列化器。
  • StringRedisTemplate提供的方法非常丰富,这里只列举了一些常用方法。更多方法可以通过查看官方文档或源码来了解。

总的来说,StringRedisTemplate是Spring Data Redis中一个非常实用的工具类,它简化了Redis的操作,使开发者能够更轻松地将Redis集成到Spring应用程序中。

六:opsForSet()和opsForZSet()有什么区别?

opsForSet()opsForZSet()RedisTemplate类中提供的两个方法,它们分别用于操作Redis中的SET和ZSET(Sorted Set)数据结构。以下是这两个方法的主要区别:

1. 数据结构特性

  • opsForSet():用于操作SET数据结构。SET是一个无序的、不包含重复元素的字符串集合。SET中的元素没有特定的顺序,且每个元素都是唯一的。
  • opsForZSet():用于操作ZSET数据结构。ZSET是一个有序的、不包含重复元素的字符串集合,每个元素都会关联一个分数(score),Redis会根据这个分数对元素进行排序。

2. 支持的操作

  • opsForSet():支持的操作包括添加元素(SADD)、删除元素(SREM)、判断元素是否存在(SISMEMBER)、获取集合中的所有元素(SMEMBERS)、获取集合大小(SCARD)等。SET主要用于存储不需要排序的、唯一的元素集合。
  • opsForZSet():除了支持类似SET的添加(ZADD)、删除(ZREM)和查找(ZSCORE)操作外,还支持根据分数范围查询元素(ZRANGEBYSCORE、ZREVRANGEBYSCORE)、获取元素的排名(ZRANK、ZREVRANK)、计算分数范围内的元素数量(ZCOUNT)等高级功能。ZSET主要用于需要根据分数进行排序或统计的场景。

3. 排序与分数

  • opsForSet():由于SET是无序的,因此不支持根据任何特定顺序对元素进行排序或检索。
  • opsForZSet():ZSET中的元素会根据关联的分数进行排序。可以通过分数范围或排名来检索元素,这使得ZSET非常适合用于实现排行榜、评分系统等需要排序或统计的场景。

4. 性能考虑

  • opsForSet():由于SET是无序的,且每个元素都是唯一的,因此其操作时间复杂度一般为O(1),即常数时间复杂度,这使得它在处理大量数据时具有较高的效率。
  • opsForZSet():虽然ZSET提供了排序功能,但其操作时间复杂度一般为O(logN),其中N是集合中元素的数量。这意味着随着集合大小的增加,操作所需的时间也会相应增加,但仍然保持较高的效率。

综上所述,opsForSet()opsForZSet()的主要区别在于它们操作的数据结构特性、支持的操作、排序与分数以及性能考虑等方面。在选择使用哪个方法时,应根据实际需求进行权衡和选择。

相关文章:

第二十节:学习Redis缓存数据库实现增删改查(自学Spring boot 3.x的第五天)

这节记录下如何使用redis缓存数据库。 第一步&#xff1a; 先在服务器端安装redis&#xff0c; 下载地址&#xff1a;Releases tporadowski/redis GitHub。 第二步&#xff1a; 安装redis客户端可视化管理软件redisDesktopmanager Redis Desktop Manager - Download 第…...

Android SQLite的基本使用、生成Excel文件保存到本地

1. Android SQLite的基本使用 1.1. SQLiteOpenHelper Android 底层已经通过一个SQLiteOpenHelper的抽象类将数据库的创建&#xff0c;以及修改&#xff0c;更新等都放在了里面。 要使用它必须实现它的OnCreate(SQLiteDatabase db)&#xff0c;onUpgrade(SQLiteDatabase db, int…...

记一次因视频编码无法在浏览器播放、编码视频报错问题

起因 ... f cv2.VideoWriter_fourcc(*h264) ...我这边使用h264编码会提示 OpenCV: FFMPEG: tag 0x34363268/h264 is not supported with codec id 27 and format mp4 / MP4 (MPEG-4 Part 14) OpenCV: FFMPEG: fallback to use tag 0x31637661/avc1 [ERROR:02.711] global /i…...

【深度学习】深度卷积神经网络(AlexNet)

在 LeNet 提出后&#xff0c;卷积神经网络在计算机视觉和机器学习领域中很有名气&#xff0c;但并未起到主导作用。 这是因为 LeNet 在更大、更真实的数据集上训练的性能和可行性还有待研究。 事实上&#xff0c;在 20 世纪 90 年代到 2012 年之间的大部分时间里&#xff0c;…...

C语言扫盲

文章目录 C版本C语言特征GCCprintf数据类型函数指针内存管理void指针 Struct结构和Union结构typedef预处理器make工具cmake工具Projectintegral of sinc functionemulator embedded systeman event schedule 补充在线Linux终端安装Linux参考 建议还是国外教材学习…人家的PPT比…...

视频融合共享平台LntonAIServer视频智能分析抖动检测算法和过亮过暗检测算法

LntonAIServer作为一款智能视频监控平台&#xff0c;集成了多种先进的视频质量诊断功能&#xff0c;其中包括抖动检测和过暗检测算法。这些算法对于提升视频监控系统的稳定性和图像质量具有重要意义。 以下是对抖动检测算法和过暗检测算法的应用场景及优势的详细介绍。 一、L…...

【笔记篇】Davinci Configurator OS模块(上)

目录 1 简介1.1 架构概览2 功能描述2.1 特性2.2 规范偏离2.2.1 API 函数的泛型偏离2.2.2 可信函数 API 偏离2.2.3 服务保护偏离2.2.4 代码保护2.2.5 SyncScheduleTable API 偏差2.2.6 CheckTask/ISRMemoryAccess API 偏差2.2.7 中断 API 偏差2.2.8 Cross Core Getter API2.2.9 …...

19.3 打镜像部署到k8s中,prometheus配置采集并在grafana看图

本节重点介绍 : 打镜像&#xff0c;导出镜像&#xff0c;传输到各个节点并导入运行该项目配置prometheus和grafana 打镜像 本地build docker build -t ink8s-pod-metrics:v1 .build过程 导出镜像 docker save ink8s-pod-metrics > ink8s-pod-metrics.tar 传输到各个node…...

如何让系统u盘重新可用

目录 引言开始操作遇到的错误 引言 我们将 u 盘制作为系统 U 盘后&#xff0c;U 盘就没法在电脑中正常识别出了。当装完系统&#xff0c;不再需要 u 盘充当系统 U 盘想要正常使用该 U 盘&#xff0c;这时候就需要有些操作&#xff0c;让这个 U 盘正常化。 上图就是充当系统盘的…...

14.安卓逆向-frida基础-编写hook脚本2

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;图灵Python学院 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要盲目相信。 工…...

车辆零部件检测和分割数据集-车体数据集-yolo格式-yolov5-yolov10可用

这些标签是用于实例分割任务中的类别&#xff0c;通常在汽车图像识别或自动驾驶技术中使用。以下是这些类别&#xff1a; back_bumper - 后保险杠back_glass - 后挡风玻璃back_left_door - 后左车门back_left_light - 后左灯back_right_door - 后右车门back_right_light - 后右…...

甄选范文“论分布式存储系统架构设计”,软考高级论文,系统架构设计师论文

论文真题 分布式存储系统(Distributed Storage System)通常将数据分散存储在多台独立的设备上。传统的网络存储系统采用集中的存储服务器存放所有数据,存储服务器成为系统性能的瓶颈,也是可靠性和安全性的焦点,不能满足大规模存储应用的需要。分布式存储系统采用可扩展的…...

第十四章:html和css做一个心在跳动,为你而动的表白动画

💖 让心跳加速,传递爱意 💖 在这个特别的时刻,让爱在跳动中绽放!🌟 无论是初次相遇的心动,还是陪伴多年的默契,我们的心总在为彼此跳动。就像这颗炙热的爱心,随着每一次的跳动,传递着满满的温暖与期待。 在这个浪漫的季节,让我们一同感受爱的律动!无论你是在…...

poetry安装

文章目录 前言1. 为什么pip install poetry 会造成依赖冲突1.1 全局环境依赖混淆&#xff1a;1.2 工具和项目之间的冲突&#xff1a;1.3 缺乏依赖隔离&#xff1a;1.4 多出很多额外依赖&#xff1a; 2. 不推荐pipx安装3. poetry高级安装3.1 默认安装路径3.2自定义安装 4. 安装p…...

Proteus如何添加数码管

1、打开安装好的Proteus&#xff0c;点击上方菜单栏中的“库”&#xff0c;再选择“从库选取零件”&#xff0c;或者在左侧元件列表中单击鼠标右键&#xff0c;再点击右键菜单中的“从库中挑选”选项。 2、之后在元器件库中&#xff0c;点击类别中的“Optoelectronics”&#…...

5 apache poi实现excel的动态下拉框功能

excel下拉框 RequestMapping("xiala")public void xiala(HttpServletResponse response){String fileName "僵尸表";try{response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharact…...

深度对比:etcd、Consul、Zookeeper 和 Nacos 作为注册中心和配置中心的优势与劣势

在现代分布式系统和微服务架构中&#xff0c;服务注册中心 和 配置中心 是系统稳定运行的关键组成部分。服务注册中心负责服务的动态注册与发现&#xff0c;而配置中心用于集中管理配置&#xff0c;确保系统在变化的环境中保持一致性。本文将对比 etcd、Consul、Zookeeper 和 N…...

Android webview拦截H5的接口请求并返回处理好的数据

Android webview拦截H5的接口请求并返回处理好的数据 Android 可以通过 WebView 的 shouldInterceptRequest 方法拦截到 H5 中的网络请求。这是一个 WebViewClient 中的回调方法&#xff0c;允许开发者在 WebView 发起网络请求时对其进行处理和修改。 具体使用方法如下&#…...

vue echarts tooltip使用动态模板

先上代码 tooltip: {// 这里是车辆iconshow: true,// trigger: "item",// backgroundColor: "transparent",appendToBody: true,textStyle: {color: "#ffffff" //设置文字颜色},formatter: (params) > {return formatHtml(params.data)},}, …...

網路本地連接沒有有效的IP配置:原因與解決方法

網路本地連接顯示“沒有有效的IP配置”。這通常意味著你的電腦無法從路由器或其他網路設備獲取有效的IP地址&#xff0c;從而導致無法上網。本文將從原因和解決方法兩個方面&#xff0c;詳細解析這個問題。 一、問題的原因 路由器或數據機問題&#xff1a; 路由器或數據機出…...

如何使用ssm实现基于web的学生就业管理系统的设计与实现+vue

TOC ssm726基于web的学生就业管理系统的设计与实现vue 第1章 绪论 1.1 课题背景 二十一世纪互联网的出现&#xff0c;改变了几千年以来人们的生活&#xff0c;不仅仅是生活物资的丰富&#xff0c;还有精神层次的丰富。在互联网诞生之前&#xff0c;地域位置往往是人们思想上…...

TCP三次握手四次挥手详解

TCP三次握手建立连接的过程&#xff1a; 一次握手&#xff1a;客户端发送带有 SYN&#xff08;seqx&#xff09;标志的数据包到服务端&#xff0c;然后客户端进入 SYN_SEND 状态&#xff0c;等待服务端的确认。二次握手&#xff1a;服务端收到 SYN 包后&#xff0c;发送带有 S…...

了解 如何使用同快充充电器给不同设备快速充电

在这科技发展迅速的时代&#xff0c;快充技术已经走进了我们生活&#xff0c;不得不说有了快充技术的对比&#xff0c;传统的充电模式已经满足不了人们对充电速度的要求。就比如用华为输出100 W快充充电器为手机充电大概需要23分钟充满100%电量&#xff0c;而传统的充电器则需要…...

AGI interior designer丨OPENAIGC开发者大赛高校组AI创作力奖

在第二届拯救者杯OPENAIGC开发者大赛中&#xff0c;涌现出一批技术突出、创意卓越的作品。为了让这些优秀项目被更多人看到&#xff0c;我们特意开设了优秀作品报道专栏&#xff0c;旨在展示其独特之处和开发者的精彩故事。 无论您是技术专家还是爱好者&#xff0c;希望能带给…...

Centos安装docker(linux安装docker)——超详细小白可操作手把手教程,包好用!!!

&#x1f9f8;本篇博客重在讲解Centos安装docker&#xff0c;经博主多次在不同服务器上测试&#xff0c;极其的稳定&#xff0c;尤其是阿里的服务器&#xff0c;一路复制命令畅通无阻 &#x1f4dc;后续会退出ububtu安装docker教程&#xff0c;敬请期待 &#x1f4dc;作者首页&…...

QT day01

自定义实现登录界面&#xff1a; #include "widget.h" #include "ui_widget.h" #include<QPushButton> #include<QLineEdit> #include<QLabel>Widget::Widget(QWidget *parent) //定义有参构造函数: QWidget(parent), ui(new Ui::Widge…...

如何从飞机、电报中提取数据

电报&#xff0c;通常简称TG&#xff0c;是一个跨平台的即时通讯软件。客户端是开源的&#xff0c;而服务器是专有的。用户可以交换加密的、自毁的信息&#xff08;类似于“阅读后烧伤”&#xff09;&#xff0c;并共享各种文件&#xff0c;包括照片和视频。它的安全性很高&…...

【算法篇】二叉树类(2)(笔记)

目录 一、Leetcode 题目 1. 左叶子之和 &#xff08;1&#xff09;迭代法 &#xff08;2&#xff09;递归法 2. 找树左下角的值 &#xff08;1&#xff09;广度优先算法 &#xff08;2&#xff09;递归法 3. 路径总和 &#xff08;1&#xff09;递归法 &#xff08;2…...

Flask学习之项目搭建

一、项目基本结构 1、 exts.py 存在的目的&#xff1a;在Python中&#xff0c;如果两个或更多模块(文件)相互导入对方&#xff0c;就会形成导入循环。例如&#xff0c;模块A导入了模块B&#xff0c;同时模块B又导入了模块A&#xff0c;这就会导致导入循环。 比如在这个项目中…...

**CentOS7安装Maven**

CentOS7安装Maven 首先先解压压缩包apache-maven-3.9.9-bin.tar.gz tar -xvf apache-maven-3.9.9-bin.tar.gz解压完毕后配置环境变量 vim /etc/profile在环境变量配置文件中加入这句话 #Maven export MAVEN_HOME/opt/soft/maven362 //换成自己的路径 export PATH$PATH:$JAVA…...