Redis【实践篇】之RedisTemplate基本操作

这篇具有很好参考价值的文章主要介绍了Redis【实践篇】之RedisTemplate基本操作。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Redis 从入门到精通【应用篇】之RedisTemplate详解


Redis【实践篇】之RedisTemplate基本操作,Redis从入门到精通2023版,redis,数据库,缓存,java,后端

0. 前言

在SpringBoot中,可以使用RedisTemplate来操作Redis数据库。RedisTemplate是Spring Data Redis提供的一个强大的Redis客户端,它支持各种Redis数据结构,并提供了许多方便的方法来操作这些数据结构。下面是一些RedisTemplate的用法示例:

1. RedisTemplate 方法

1. 设置RedisTemplate的序列化方式

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        // 设置key和value的序列化方式
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));

        // 设置hash key和value的序列化方式
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));

        return redisTemplate;
    }
}

在此示例中,创建了一个RedisTemplate对象,并设置了key和value的序列化方式为StringRedisSerializer和Jackson2JsonRedisSerializer。同时,还设置了hash key和value的序列化方式。

2. RedisTemplate的基本操作

其实在项目中我们通常会将RedisTemplate 再封装一层,作为一个Redis操作类处理,相当于提供了一层语法糖。

@Service
public class RedisService {

    // RedisTemplate是Spring提供的对Redis的操作模板类,使用泛型限定key和value的类型为String和Object
    private final RedisTemplate<String, Object> redisTemplate;

    // 构造函数,注入RedisTemplate对象
    public RedisService(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    // 设置key-value键值对
    public void set(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    // 根据key获取value
    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    // 根据key删除键值对
    public void delete(String key) {
        redisTemplate.delete(key);
    }

    // 判断key是否存在
    public boolean exists(String key) {
        return redisTemplate.hasKey(key);
    }

    // 将key对应的value增加delta
    public long increment(String key, long delta) {
        return redisTemplate.opsForValue().increment(key, delta);
    }

    // 获取hash结构中所有键值对
    public Map<Object, Object> hashGetAll(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    // 向hash结构中添加键值对
    public void hashPut(String key, Object hashKey, Object value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    // 根据hash结构中的key获取对应的value
    public Object hashGet(String key, Object hashKey) {
        return redisTemplate.opsForHash().get(key, hashKey);
    }

    // 根据hash结构中的key删除对应的hashKey
    public void hashDelete(String key, Object... hashKeys) {
        redisTemplate.opsForHash().delete(key, hashKeys);
    }

    // 判断hash结构中是否存在hashKey
    public boolean hashExists(String key, Object hashKey) {
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }

    // 获取set结构中所有元素
    public Set<Object> setGetAll(String key) {
        return redisTemplate.opsForSet().members(key);
    }

    // 向set结构中添加元素
    public void setAdd(String key, Object... values) {
        redisTemplate.opsForSet().add(key, values);
    }

    // 判断set结构中是否存在某个元素
    public boolean setExists(String key, Object value) {
        return redisTemplate.opsForSet().isMember(key, value);
    }

    // 根据value删除set结构中的元素
    public void setDelete(String key, Object... values) {
        redisTemplate.opsForSet().remove(key, values);
    }

    // 获取list结构中所有元素
    public List<Object> listGetAll(String key) {
        return redisTemplate.opsForList().range(key, 0, -1);
    }

    // 向list结构中左侧插入元素
    public void listPush(String key, Object value) {
        redisTemplate.opsForList().leftPush(key, value);
    }

    // 从list结构中左侧弹出元素
    public Object listPop(String key) {
        return redisTemplate.opsForList().leftPop(key);
    }

    // 获取list结构中元素的数量
    public long listSize(String key) {
        return redisTemplate.opsForList().size(key);
    }
}

2. 源码浅析

2.1. 构造方法

RedisTemplate的构造方法需要一个RedisConnectionFactory对象作为参数,它通过这个对象来获取Redis连接。RedisConnectionFactory 是 Spring Data Redis 提供的一个接口,用于创建和管理 Redis 连接。它是将 Redis 连接池(连接 Redis 数据库的客户端)与 Spring 应用程序集成的关键。

public RedisTemplate() {
    RedisConnectionFactory redisConnectionFactory = RedisConnectionConfiguration.determineConnectionFactory(redisSentinelConfiguration, redisClusterConfiguration, connectionFactory, jedisConnectionFactory);
    setConnectionFactory(redisConnectionFactory);
    afterPropertiesSet();
}

2.2. 序列化方式

RedisTemplate支持各种数据类型的序列化和反序列化,它提供了以下四种序列化方式:

  • keySerializer:key的序列化方式。
  • valueSerializer:value的序列化方式。
  • hashKeySerializer:hash key的序列化方式。
  • hashValueSerializer:hash value的序列化方式。

RedisTemplate默认使用JdkSerializationRedisSerializer作为序列化方式,但是在实际使用中,通常需要根据实际情况选择更加高效的序列化方式,如StringRedisSerializer、Jackson2JsonRedisSerializer等。

public void setKeySerializer(RedisSerializer<?> keySerializer) {
    Assert.notNull(keySerializer, "RedisSerializer must not be null!");
    this.keySerializer = keySerializer;
}

public void setValueSerializer(RedisSerializer<?> valueSerializer) {
    Assert.notNull(valueSerializer, "RedisSerializer must not be null!");
    this.valueSerializer = valueSerializer;
}

public void setHashKeySerializer(RedisSerializer<?> hashKeySerializer) {
    Assert.notNull(hashKeySerializer, "RedisSerializer must not be null!");
    this.hashKeySerializer = hashKeySerializer;
}

public void setHashValueSerializer(RedisSerializer<?> hashValueSerializer) {
    Assert.notNull(hashValueSerializer, "RedisSerializer must not be null!");
    this.hashValueSerializer = hashValueSerializer;
}

2.3. RedisTemplate的操作方法

RedisTemplate提供了各种操作方法,如opsForValue()、opsForList()、opsForSet()、opsForZSet()、opsForHash()等,它们返回的是具体数据结构的操作对象,如ValueOperations、ListOperations、SetOperations、ZSetOperations、HashOperations等。这些操作对象提供了各种操作方法,如get()、set()、push()、pop()、add()、remove()、score()、range()、increment()等,它们对应了Redis的各种操作。

public ValueOperations<K, V> opsForValue() {
    if (valueOps == null) {
        valueOps = new DefaultValueOperations<>(this);
    }
    return valueOps;
}

public ListOperations<K, V> opsForList() {
    if (listOps == null) {
        listOps = new DefaultListOperations<>(this);
    }
    return listOps;
}

public SetOperations<K, V> opsForSet() {
    if (setOps == null) {
        setOps = new DefaultSetOperations<>(this);
    }
    return setOps;
}

public ZSetOperations<K, V> opsForZSet() {
    if (zSetOps == null) {
        zSetOps = new DefaultZSetOperations<>(this);
    }
    return zSetOps;
}

public HashOperations<K, HK, HV> opsForHash() {
    if (hashOps == null) {
        hashOps = new DefaultHashOperations<>(this);
    }
    return hashOps;
}

2.4. RedisTemplate的事务

RedisTemplate支持事务,它提供了multi()、exec()和discard()三个方法来实现事务。multi()方法用于开启事务,exec()方法用于提交事务,discard()方法用于回滚事务。

public void multi() {
    RedisConnectionUtils.bindConnection(getRequiredConnectionFactory(), true);
    try {
        RedisConnectionUtils.getRequiredConnection(getConnectionFactory()).multi();
    } catch (RuntimeException ex) {
        RedisConnectionUtils.unbindConnection(getRequiredConnectionFactory());
        throw ex;
    }
}

public List<Object> exec() {
    RedisConnectionUtils.unbindConnectionIfPossible(getConnectionFactory());
    return execute((RedisCallback<List<Object>>) connection -> {
        List<Object> results = connection.exec();
        return results != null ? results : Collections.emptyList();
    }, true);
}

public void discard() {
    RedisConnectionUtils.unbindConnectionIfPossible(getConnectionFactory());
    execute(RedisConnectionUtils::discard, true);
}

2.5. RedisTemplate的执行方法

RedisTemplate提供了execute()方法来执行Redis操作,它需要传入一个RedisCallback对象作为参数,RedisCallback是一个函数式接口,它定义了一个回调函数,用于执行具体的Redis操作。execute()方法会获取一个Redis连接,执行RedisCallback对象的回调函数,并返回回调函数的结果。

public <T> T execute(RedisCallback<T> action, boolean exposeConnection) {
    Assert.notNull(action, "Callback object must not be null");

    RedisConnection conn = null;
    try {
        conn = getConnection(exposeConnection);
        boolean existingConnection = TransactionSynchronizationManager.hasResource(getConnectionFactory());
        RedisConnection connToUse = preProcessConnection(conn, existingConnection);
        T result = action.doInRedis(connToUse);
        return postProcessResult(result, conn, existingConnection);
    } catch (RuntimeException ex) {
        releaseConnection(conn, existingConnection);
        throw ex;
    } finally {
        if (!exposeConnection) {
            RedisConnectionUtils.releaseConnection(conn, getConnectionFactory(), false);
        }
    }
}

在execute()方法中,首先获取Redis连接,然后调用preProcessConnection()方法进行预处理,接着执行RedisCallback对象的回调函数,最后调用postProcessResult()方法进行后处理,并返回结果。如果执行过程中发生异常,会调用releaseConnection()方法释放Redis连接。

2.6. RedisTemplate的回调方法

RedisTemplate的回调方法主要有以下三个:

这里有三个方法:

  1. execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline):执行Redis操作的核心方法。接受一个RedisCallback对象,该对象封装了要在Redis上执行的操作。还有两个布尔类型的参数,一个表示是否暴露连接(exposeConnection),另一个表示是否启用pipeline(pipeline)。如果启用pipeline,将使用Redis连接对象的openPipeline()和closePipeline()方法执行操作。

  2. execute(SessionCallback<T> session):执行Redis事务的方法。接受一个SessionCallback对象,该对象封装了在 Redis 事务中执行的操作。该方法会绑定 Redis 连接并执行 SessionCallback 对象的 execute() 方法,最后解除绑定。

  3. executePipelined(SessionCallback<?> session, @Nullable RedisSerializer<?> resultSerializer):执行 Redis pipeline 的方法。接受一个SessionCallback对象,该对象封装了要在 Redis pipeline 中执行的操作,以及一个可选的 RedisSerializer 对象,用于反序列化结果。该方法会绑定 Redis 连接并执行 SessionCallback 对象的 execute() 方法,在执行期间使用 Redis 连接对象的 openPipeline() 和 closePipeline() 方法开启和关闭 Redis pipeline。

常用场景:第一个方法执行单个Redis操作,第二个方法执行Redis事务,第三个方法执行Redis
pipeline。此外,第二个方法是为了执行多个 Redis 操作而设计的,而第一个方法和第三个方法只执行单个 Redis 操作。第三个方法需要额外的参数,用于反序列化 Redis pipeline 的结果。


    @Nullable
    public <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, this.enableTransactionSupport);
        }

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

代码示例

  1. 使用 execute(RedisCallback<T> action) 执行 Redis 命令
 
// 使用 execute() 方法执行 Redis 命令
String key = "myKey";
String value = redisTemplate.execute((RedisCallback<String>) connection -> {
    connection.set(redisTemplate.getStringSerializer().serialize(key), redisTemplate.getStringSerializer().serialize("Hello"));
    return redisTemplate.getStringSerializer().deserialize(connection.get(redisTemplate.getStringSerializer().serialize(key)));
});

// 输出 Redis 命令执行结果
System.out.println(value); // 输出 "Hello"

在上面的示例中, 我们使用 execute(RedisCallback<T> action) 方法将 Redis 命令封装在一个 RedisCallback 对象中,并将其传递给 execute() 方法。该命令使用 set() 方法将一个 key-value 对写入 Redis 中,然后使用 get() 方法从 Redis 中读取该 key 对应的值。

  1. 使用 execute(SessionCallback<T> session) 执行 Redis 事务
// 使用 execute(SessionCallback<T> session) 方法执行 Redis 事务
String key1 = "myKey1";
String key2 = "myKey2";
String value1 = "myValue1";
String value2 = "myValue2";
List<Object> results = redisTemplate.execute((SessionCallback<List<Object>>) session -> {
    session.multi();
    session.opsForValue().set(key1, value1);
    session.opsForValue().set(key2, value2);
    return session.exec();
});

// 输出 Redis 事务的结果
System.out.println(results); // 输出 "[true, true]"

使用 execute(SessionCallback<T> session) 方法将 Redis 事务封装在一个 SessionCallback<T> 对象中,并将其传递给 execute() 方法。该事务使用 multi() 方法开启事务,在事务中使用 opsForValue() 对象的 set() 方法将两个 key-value 对写入 Redis 中,最后使用 exec() 方法提交事务。事务执行完成后,我们可以通过 execute() 方法返回的结果列表查看每个 Redis 命令的执行结果。在上面的示例中,我们可以看到结果列表为 [true, true],表示两个 Redis 命令都成功执行。

  1. 使用 executePipelined(SessionCallback<?> session) 执行 Redis pipeline
 

// 使用 executePipelined(SessionCallback<?> session) 方法执行 Redis pipeline
String key1 = "myKey1";
String key2 = "myKey2";
List<Object> results = redisTemplate.executePipelined((SessionCallback<List<Object>>) session -> {
    session.opsForValue().get(key1);
    session.opsForValue().get(key2);
    return null;
});

// 输出 Redis pipeline 的结果
System.out.println(results); // 输出 "[Hello1, Hello2]"

使用 executePipelined(SessionCallback<?> session) 方法将 Redis pipeline 封装在一个 SessionCallback<?> 对象中,并将其传递给 executePipelined() 方法。该 pipeline 使用 opsForValue() 对象的 get() 方法获取两个 key 的值,并返回一个结果列表。在执行期间,该方法将使用 Redis 连接对象的 openPipeline()closePipeline() 方法开启和关闭 Redis pipeline,以便可以批量执行多个命令。

3.总结

看完这些基本上行只是学会了增删查看和批量操作。也就是只学会了RedisTemplate 的皮毛。其实在项目中还有更多的复杂需求,需要重新实现。

比如以下这些问题,也是很常见的,需要我们处理实际的问题。我大概做一个简答,后面将详细输出示例

3.1. 项目中如何使用 RedisTemplate 支持多个 Redis 数据库?

可以通过配置 RedisConnectionFactory 来支持多个 Redis 数据库,其中可以使用 JedisConnectionFactory 或 LettuceConnectionFactory 来创建不同的 RedisConnectionFactory 实例。详细教程可以参考我的其他博客《SpringBoot 项目配置多数据源》

3.2. 如何使用 RedisTemplate 支持 Redis 集群?

可以使用 RedisTemplate 的 ClusterRedisConnectionFactory 来支持 Redis 集群,通过配置 Redis 集群中的多个节点来实现高可用性和负载均衡。详细教程参考我的其他博客《SpringBoot 项目配置 Redis 集群》

3.3. 如何使用 RedisTemplate 实现 Redis 事务的乐观锁?

可以使用 RedisTemplate 的 watch() 方法和 multi() 方法来实现 Redis 事务的乐观锁,通过在事务开始前使用 watch() 方法监视 Redis 中的某个 key,然后在事务中使用 multi() 方法执行多个 Redis 命令,并使用 exec() 方法提交事务,如果在事务执行期间,被监视的 key 被修改,则事务会失败,从而实现乐观锁。
详细教程可以参考我的其他博客《SpringBoot 项目配置 Redis 集群》

3.4. 如何使用 RedisTemplate 实现 Redis 的分布式锁重入?

可以使用 RedisTemplate 的 ThreadLocal 方式来实现 Redis 的分布式锁重入,即在每个线程中保存一个 Redis 分布式锁的状态,并在需要重入时,检查当前线程是否已经获取了分布式锁。

3.5. 如何使用 RedisTemplate 实现 Redis 的分布式事务?

可以使用 RedisTemplate 的 execute(SessionCallback session) 方法来实现 Redis 的分布式事务,其中 SessionCallback 接口可以用来执行多个 Redis 命令,并保证这些命令以原子方式执行。

3.6. 如何使用 RedisTemplate 实现 Redis 的分布式限速?

可以使用 RedisTemplate 的 incr() 方法和 expire() 方法来实现 Redis 的分布式限速,通过在 Redis 中设置一个计数器和过期时间来实现分布式限速。

3.7. 如何使用 RedisTemplate 实现 Redis 的分布式锁可重入性?

可以使用 RedisTemplate 的 ReentrantRedisLock 类来实现 Redis 的分布式锁可重入性,该类可以在 Redis 中保存一个计数器来记录锁的重入次数,并在释放锁时,检查当前线程是否已经完全释放了锁,从而实现分布式锁的可重入性。

3.8. 如何使用 RedisTemplate 实现 Redis 的分布式信号量?

可以使用 RedisTemplate 的 RedisSemaphore 类来实现 Redis 的分布式信号量,该类可以在 Redis 中保存一个计数器来记录当前已经获得信号量的数量,并在释放信号量时,将计数器减一。

3.9. 如何使用 RedisTemplate 实现 Redis 的分布式缓存穿透?

可以使用 RedisTemplate 的缓存注解(例如 @Cacheable、@CachePut、@CacheEvict)和布隆过滤器来实现 Redis 的分布式缓存穿透,其中布隆过滤器可以用来过滤掉不存在的 key,从而避免缓存穿透的问题。

3.10. 如何使用 RedisTemplate 实现 Redis 的分布式缓存击穿?

可以使用 RedisTemplate 的缓存注解(例如 @Cacheable、@CachePut、@CacheEvict)和 Redis 分布式锁来实现 Redis 的分布式缓存击穿,其中 Redis 分布式锁可以用来防止缓存击穿,即在缓存不存在的情况下,使用 Redis 分布式锁来避免多个线程同时访问数据库。文章来源地址https://www.toymoban.com/news/detail-602371.html

4. Redis从入门到精通系列文章

  • 《Redis【应用篇】之RedisTemplate基本操作》
  • 《Redis 从入门到精通【实践篇】之SpringBoot配置Redis多数据源》
  • 《Redis 从入门到精通【进阶篇】之三分钟了解Redis HyperLogLog 数据结构》
  • 《Redis 从入门到精通【进阶篇】之三分钟了解Redis地理位置数据结构GeoHash》
  • 《Redis 从入门到精通【进阶篇】之高可用哨兵机制(Redis Sentinel)详解》
  • 《Redis 从入门到精通【进阶篇】之redis主从复制详解》
  • 《Redis 从入门到精通【进阶篇】之Redis事务详解》
  • 《Redis从入门到精通【进阶篇】之对象机制详解》
  • 《Redis从入门到精通【进阶篇】之消息传递发布订阅模式详解》
  • 《Redis从入门到精通【进阶篇】之持久化 AOF详解》
  • 《Redis从入门到精通【进阶篇】之持久化RDB详解》
  • 《Redis从入门到精通【高阶篇】之底层数据结构字典(Dictionary)详解》
  • 《Redis从入门到精通【高阶篇】之底层数据结构快表QuickList详解》
  • 《Redis从入门到精通【高阶篇】之底层数据结构简单动态字符串(SDS)详解》
  • 《Redis从入门到精通【高阶篇】之底层数据结构压缩列表(ZipList)详解》
  • 《Redis从入门到精通【进阶篇】之数据类型Stream详解和使用示例》
    Redis【实践篇】之RedisTemplate基本操作,Redis从入门到精通2023版,redis,数据库,缓存,java,后端大家好,我是冰点,今天的Redis【实践篇】之RedisTemplate基本操作详解,全部内容就是这些。如果你有疑问或见解可以在评论区留言。

到了这里,关于Redis【实践篇】之RedisTemplate基本操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【实践篇】基于CAS的单点登录实践之路

    作者:京东物流 赵勇萍 上个月我负责的系统SSO升级,对接京东ERP系统,这也让我想起了之前我做过一个单点登录的项目。想来单点登录有很多实现方案,不过最主流的还是基于CAS的方案,所以我也就分享一下我的CAS实践之路。 单点登录的英文名叫做:Single Sign On(简称SSO)

    2023年04月13日
    浏览(68)
  • 【实践篇】推荐算法PaaS化探索与实践

    作者:京东零售 崔宁 目前,推荐算法部支持了主站、企业业务、全渠道等20+业务线的900+推荐场景,通过梳理大促运营、各垂直业务线推荐场景的共性需求,对现有推荐算法能力进行沉淀和积累,并通过算法PaaS化打造通用化的推荐能力,提升各业务场景推荐赋能效率,高效赋

    2024年02月15日
    浏览(68)
  • 安卓与串口通信-实践篇

    在上一篇文章中我们讲解了关于串口的基础知识,没有看过的同学推荐先看一下,否则你可能会不太理解这篇文章所述的某些内容。 这篇文章我们将讲解安卓端的串口通信实践,即如何使用串口通信实现安卓设备与其他设备例如PLC主板之间数据交互。 需要注意的是正如上一

    2024年02月16日
    浏览(48)
  • 「ML 实践篇」模型训练

    在训练不同机器学习算法模型时,遇到的各类训练算法大多对用户都是一个黑匣子,而理解它们实际怎么工作,对用户是很有帮助的; 快速定位到合适的模型与正确的训练算法,找到一套适当的超参数等; 更高效的执行错误调试、错误分析等; 有助于理解、构建和训练神经

    2023年04月16日
    浏览(54)
  • 【MySql】11- 实践篇(九)

    主机内存只有 100G,现在要对一个 200G 的大表做全表扫描,会不会把数据库主机的内存用光了? 1.1 全表扫描对 server 层的影响 现在要对一个 200G 的 InnoDB 表 db1. t,执行一个全表扫描。当然,你要把扫描结果保存在客户端,会使用类似这样的命令: InnoDB 的数据是保存在主键索

    2024年02月06日
    浏览(55)
  • 程序员职业规划-实践篇

    你是否认真思考过3-5年、10年: 你想成为什么样的人 ? 作为一名技术人,我们应认真规划自己的职业发展,不再焦虑、为自己加速~ 一块留言来聊聊吧~ 你该去什么样的公司、做什么样的事情、拿多少钱,都取决于一个问题: 你想成为什么样的人 ? 你是否认真思考过3-5年、

    2024年02月05日
    浏览(93)
  • 【实践篇】推荐算法PaaS化探索与实践 | 京东云技术团队

    作者:京东零售 崔宁 目前,推荐算法部支持了主站、企业业务、全渠道等20+业务线的900+推荐场景,通过梳理大促运营、各垂直业务线推荐场景的共性需求,对现有推荐算法能力进行沉淀和积累,并通过算法PaaS化打造通用化的推荐能力,提升各业务场景推荐赋能效率,高效赋

    2024年02月15日
    浏览(42)
  • 微服务实战系列之ZooKeeper(实践篇)

    关于 ZooKeeper ,博主已完整的通过庖丁解牛式的 “解法” ,完成了概述。我想掌握了这些基础原理和概念后,工作的问题自然迎刃而解,甚至offer也可能手到擒来,真实一举两得,美极了。 为了更有直观的体验,强化概念,博主特别献上一篇实践文章。理论联系实践,才能学

    2024年01月21日
    浏览(83)
  • 「ML 实践篇」分类系统:图片数字识别

    目的 :使用 MNIST 数据集,建立数字图像识别模型,识别任意图像中的数字; MNIST ,一组由美国高中生和人口调查局员工手写的 70000 个数字图片;每张图片都用其代表的数字标记;因广泛被应用于机器学习入门,被称作机器学习领域的 Hello World ;也可用于测试新分类算法的

    2023年04月08日
    浏览(86)
  • 【实践篇】领域驱动设计:DDD工程参考架构

    不同团队落地DDD所采取的应用架构风格可能不同,并没有统一的、标准的DDD工程架构。有些团队可能遵循经典的DDD四层架构,或改进的DDD四层架构,有些团队可能综合考虑分层架构、整洁架构、六边形架构等多种架构风格,有些在实践中可能引入CQRS解决读模型与写模型的差异

    2024年02月05日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包