redisTemplate 使用 setIfAbsent 返回 null 问题原理及解决办法

这篇具有很好参考价值的文章主要介绍了redisTemplate 使用 setIfAbsent 返回 null 问题原理及解决办法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

redisTemplate 使用 setIfAbsent 返回 null 问题原理及解决办法

1.简介

有的时候我们使用 redisTemplate给锁设置超时时间的方法,设置锁并返回的 lock 有可能不是 true 或 false,而是null。

Boolean lock = redisTemplate.opsForValue().setIfAbsent("redisTemplateTest锁住了", "value", 10, TimeUnit.SECONDS);

setifabsent,redis,java,spring boot,redis,redistemplate

setifabsent,redis,java,spring boot,redis,redistemplate
从上图我们可以看出虽然生成了锁,但是返回的 lock 却是 null ,这就会影响我们下面的代码运行。
下面我先说一下可能的产生原因和解决办法,之后再详细说一下原理。

2.产生原因及解决办法

最直接的产生原因就是项目启动后缺少了 RedisConnectionFactory 这个bean,导致这一情况的发生有可能是引用了以下的jar包:

 		<dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.10.6</version>
        </dependency>

解决办法很简单:

1)换个jar包使用,如使用:

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

或者该jar包配合 redisson 包共同使用:

 		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.10.6</version>
        </dependency>

2)手动加入 RedisConnectionFactory 这个bean:

	@Bean
    public RedisConnectionFactory redisConnectionFactory(){
        return new LettuceConnectionFactory();
    }

3.产生的原理

首先我们要对 springboot 自动装配有一定了解,SpringBoot 启动时会加载所有 META-INF 文件夹下的 spring.factories 文件,在其中找到要装配的类。

setifabsent,redis,java,spring boot,redis,redistemplate

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

这只是众多 spring.factories 的文件中的一个 , 从上面我们可以看到 spring 自动配置了 RedisAutoConfiguration 这个bean。下面我们展示一下 RedisAutoConfiguration 的源码:

public class RedisAutoConfiguration {
    public RedisAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean(
        name = {"redisTemplate"}
    )
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

从上面的源码中我们可以得知,装配 RedisAutoConfiguration 这个bean 的时候,同时也会装载 redisTemplate 和 StringRedisTemplate 这两个 bean ,并且这两个bean 都是基于 RedisConnectionFactory 去构建的。

下面我们来看一下 RedisConnectionFactory 的结构 :

setifabsent,redis,java,spring boot,redis,redistemplate

从上图我们可以看出 RedisConnectionFactory 作为一个接口,有 JedisConnectionFactory 和 LettuceConnectionFactory 这两个实现类。

从上面的所有信息中我们可以得知,我们所使用的 redisTemplate 和 StringRedisTemplate 是通过 JedisConnectionFactory 和 LettuceConnectionFactory 这两个实现类来构建的。

下面我们验证一下该结论:

首先我们只引用 spring-boot-starter-data-redis jar包:

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

setifabsent,redis,java,spring boot,redis,redistemplate

setifabsent,redis,java,spring boot,redis,redistemplate

从上图可以看出确实是我们推论的 redisTemplate 和 StringRedisTemplate 是通过 LettuceConnectionFactory 来构建的。

我们可以尝试在启动项目的时候打印 spring 容器中的所有 bean 来看一下,以上 redis 的 bean 是否存在。

@SpringBootApplication
public class ApplicationStarter {

    public static void main(String[] args) {
        //1.返回我们IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(ApplicationStarter.class, args);

        //2.查看容器里面的组件
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }

}

setifabsent,redis,java,spring boot,redis,redistemplate
从上图可以看出理应存在的 bean 全部都已经生成完毕,致此,redisTemplate 正常的使用已经说明完毕了。

那么接下来让我们来演示一下为什么获取到了锁还会产生 lock = null 这种情况:
setifabsent,redis,java,spring boot,redis,redistemplate

下面我们使用一下 redisson-spring-boot-starter 这个jar包:

 		<dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.10.6</version>
        </dependency>

setifabsent,redis,java,spring boot,redis,redistemplate
从上图我们可以看到该jar包配置了 RedissonAutoConfiguration 这个新的 bean 。那么让我们看一下 RedissonAutoConfiguration 的源码:

public class RedissonAutoConfiguration {
    @Autowired
    private RedissonProperties redissonProperties;
    @Autowired
    private RedisProperties redisProperties;
    @Autowired
    private ApplicationContext ctx;

    public RedissonAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean(
        name = {"redisTemplate"}
    )
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean({StringRedisTemplate.class})
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean({RedisConnectionFactory.class})
    public RedissonConnectionFactory redissonConnectionFactory(RedissonClient redisson) {
        return new RedissonConnectionFactory(redisson);
    }

    @Bean(
        destroyMethod = "shutdown"
    )
    @ConditionalOnMissingBean({RedissonClient.class})
    public RedissonClient redisson() throws IOException {
        Config config = null;
        Method clusterMethod = ReflectionUtils.findMethod(RedisProperties.class, "getCluster");
        Method timeoutMethod = ReflectionUtils.findMethod(RedisProperties.class, "getTimeout");
        Object timeoutValue = ReflectionUtils.invokeMethod(timeoutMethod, this.redisProperties);
        int timeout;
        Method nodesMethod;
        if (null == timeoutValue) {
            timeout = 0;
        } else if (!(timeoutValue instanceof Integer)) {
            nodesMethod = ReflectionUtils.findMethod(timeoutValue.getClass(), "toMillis");
            timeout = ((Long)ReflectionUtils.invokeMethod(nodesMethod, timeoutValue)).intValue();
        } else {
            timeout = (Integer)timeoutValue;
        }

        if (this.redissonProperties.getConfig() != null) {
            try {
                InputStream is = this.getConfigStream();
                config = Config.fromJSON(is);
            } catch (IOException var11) {
                try {
                    InputStream is = this.getConfigStream();
                    config = Config.fromYAML(is);
                } catch (IOException var10) {
                    throw new IllegalArgumentException("Can't parse config", var10);
                }
            }
        } else if (this.redisProperties.getSentinel() != null) {
            nodesMethod = ReflectionUtils.findMethod(Sentinel.class, "getNodes");
            Object nodesValue = ReflectionUtils.invokeMethod(nodesMethod, this.redisProperties.getSentinel());
            String[] nodes;
            if (nodesValue instanceof String) {
                nodes = this.convert(Arrays.asList(((String)nodesValue).split(",")));
            } else {
                nodes = this.convert((List)nodesValue);
            }

            config = new Config();
            ((SentinelServersConfig)config.useSentinelServers().setMasterName(this.redisProperties.getSentinel().getMaster()).addSentinelAddress(nodes).setDatabase(this.redisProperties.getDatabase()).setConnectTimeout(timeout)).setPassword(this.redisProperties.getPassword());
        } else {
            Method method;
            if (clusterMethod != null && ReflectionUtils.invokeMethod(clusterMethod, this.redisProperties) != null) {
                Object clusterObject = ReflectionUtils.invokeMethod(clusterMethod, this.redisProperties);
                method = ReflectionUtils.findMethod(clusterObject.getClass(), "getNodes");
                List<String> nodesObject = (List)ReflectionUtils.invokeMethod(method, clusterObject);
                String[] nodes = this.convert(nodesObject);
                config = new Config();
                ((ClusterServersConfig)config.useClusterServers().addNodeAddress(nodes).setConnectTimeout(timeout)).setPassword(this.redisProperties.getPassword());
            } else {
                config = new Config();
                String prefix = "redis://";
                method = ReflectionUtils.findMethod(RedisProperties.class, "isSsl");
                if (method != null && (Boolean)ReflectionUtils.invokeMethod(method, this.redisProperties)) {
                    prefix = "rediss://";
                }

                ((SingleServerConfig)config.useSingleServer().setAddress(prefix + this.redisProperties.getHost() + ":" + this.redisProperties.getPort()).setConnectTimeout(timeout)).setDatabase(this.redisProperties.getDatabase()).setPassword(this.redisProperties.getPassword());
            }
        }

        return Redisson.create(config);
    }

    private String[] convert(List<String> nodesObject) {
        List<String> nodes = new ArrayList(nodesObject.size());
        Iterator var3 = nodesObject.iterator();

        while(true) {
            while(var3.hasNext()) {
                String node = (String)var3.next();
                if (!node.startsWith("redis://") && !node.startsWith("rediss://")) {
                    nodes.add("redis://" + node);
                } else {
                    nodes.add(node);
                }
            }

            return (String[])nodes.toArray(new String[nodes.size()]);
        }
    }

    private InputStream getConfigStream() throws IOException {
        Resource resource = this.ctx.getResource(this.redissonProperties.getConfig());
        InputStream is = resource.getInputStream();
        return is;
    }
}

从以上代码可以看出 RedissonAutoConfiguration 是先构建 RedissonClient ,之后通过 RedissonClient 构建 RedissonConnectionFactory ,然后通过 RedissonConnectionFactory 构建 redisTemplate 和 StringRedisTemplate 。和之前构建 redisTemplate 的不同主要在于使用了不同的 RedisConnectionFactory 实现类:

setifabsent,redis,java,spring boot,redis,redistemplate
我们同样打印一下 spring 容器中的 bean 看一下:

setifabsent,redis,java,spring boot,redis,redistemplate
从上文两种jar包的对比,我们可以得知两种方式获取 redisTemplate 的区别正是在于 RedisConnectionFactory 的实现类不同,而这也是导致 lock = null 的原因所在。 redisson 底层调用了大量的 netty 包,该jar包自带的 RedissonConnectionFactory 影响了之前的返回逻辑,下面我们简单验证一下推论:

setifabsent,redis,java,spring boot,redis,redistemplate
setifabsent,redis,java,spring boot,redis,redistemplate
从上图可以看出该jar包确实是通过 RedissonConnectionFactory 构建 redisTemplate ,并且返回的 lock 为 null 。

下面我们手动加入 RedisConnectionFactory 这个bean进行对照看下:

	@Bean
    public RedisConnectionFactory redisConnectionFactory(){
        return new LettuceConnectionFactory();
    }

setifabsent,redis,java,spring boot,redis,redistemplate

setifabsent,redis,java,spring boot,redis,redistemplate
从上面的对比可以看出我们的推论完全是正确的, redisson-spring-boot-starter 这个jar包的 RedissonConnectionFactory 影响了原本的判断,导致返回 lock=null 这种现象。

由于 Redisson 里面运用了大量的回调方法、匿名表达式、异步操作等难以debug的方法,所以我这里只在表层进行了问题的排查与解决,如果有哪位大佬具体排查出在代码运行中具体是什么原因导致了使用 RedissonConnectionFactory 返回 lock=null 这种现象。使用它与使用 LettuceConnectionFactory 的返回差异具体体现在哪里的话麻烦告知一声。文章来源地址https://www.toymoban.com/news/detail-754689.html

到了这里,关于redisTemplate 使用 setIfAbsent 返回 null 问题原理及解决办法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • SurfaceControl.screenshot()用法 | SurfaceControl.screenshot()使用后返回null的解决方案

    SurfaceControl.screenshot() 是系统的截屏方法,属于系统API,对用户不开放,因此要使用的话需要系统的签名( platform.keystore 文件)才能调用到。 在高版本的android上(例如 android 11 ),如果没有系统签名,即使用反射也会报找不到方法的异常,但是有系统签名的话,直接调用就行。 网

    2024年02月10日
    浏览(76)
  • 解决SUM函数返回为NULL

    SUM函数的作用:计算某一字段中所有行的数值和, 使用SUM函数进行对符合条件的结果行数进行求和。 sum 求和时会对 null 进行过滤,不计算,但如果没有返回结果,则sum 函数的返回值为 null,不是 0: 1. IFNULL 使用IFNULL函数进行查询,判断第一个参数是否为null,如果是 则返回

    2024年02月08日
    浏览(34)
  • reids自定义RedisTemplate以及乱码问题解决

            1,使用 ObjectMapper().writeValueAsString(*);                  2,所有pojo实现 Serializable接口         3,自定义序列化,企业开发中可以直接使用          我要保证使用到了我们自定义的RedisTemplate 使用添加注解 当可以点进去 即为成功! 使用RedisTemplate需要频繁调用

    2024年04月09日
    浏览(42)
  • Android11 相机拍照权限,以及解决resolveActivity返回null

    一、配置拍照和读写权限 二、手动申请权限         implementation \\\'com.permissionx.guolindev:permissionx:1.4.0\\\'         1、手动申请读写,拍照权限         2、手动申请文件管理权限 三、Manifest中配置queries(解决resolveActivity为null) 四、Manifest中配置provider 五、配置file_paths文件

    2024年02月15日
    浏览(52)
  • 【解决问题思路分析】记录hutool默认使用服务端上次返回cookie的问题解决思路

    本服务需要调用第三方接口获取数据,首先调用public-key接口获取公钥,然后用公钥加密密码,将用户名和密码传入/ticket接口,获取Cookie和response body中的token。 由于是调用第三方接口出现问题,第一步先拉通第三方对接人查看后台日志,对方使用apisix作为api网关,初步判断是

    2024年02月07日
    浏览(49)
  • uniapp微信小程序 页面返回使用navigateBack,返回后页面不刷新问题解决方案

    尝试了众多方法,比如vuex,本地缓存,都不行 1,如果是页面之间的跳转 可以使用onShow生命周期请求数据 2,组件之间的跳转,使用redirectTo,通过关闭当前页面,跳转到指定页面再加载,这种适合二级页面到三级页面数据不更新问题 3,当一级页面使用了某个组件,组件内跳转

    2024年02月15日
    浏览(59)
  • 微信小程序使用自定义tabbar 想要获取tabbar的高度,返回的结果是null,该如何获取?

    在使用自定义tabbar时,你可能会需要获取tabbar的高度,但是按照网上的方法却得不到正确的结果,这让你十分头疼。那么该怎么办呢?小编为大家整理了以下几个方法,希望能够帮到大家。 1️⃣ 使用wx.getSystemInfoSync()方法获取系统信息,然后通过计算得出tabbar的高度。 示例

    2024年02月11日
    浏览(64)
  • mybatis-plus 查询数据为null问题解决

    首先数据库能查询到数据, 不过查询到的字段都是 null 值, 因为业务上就用到这3个字段 代码中使用 mybatis-plus 精确字段查询, select方法可以精确查询字段 之后debug看到 orderMain 对象为 null, 因为 这 3 个字段在数据库表中都是 null 解决方式是把 select方法需要查询一个数据库中不为

    2024年02月11日
    浏览(55)
  • json_decode返回NULL

    最近在调用某公司的API时,将对方返回的数据,使用PHP的json_decode函数解析,但是返回NULL,最终排查为对方传送来的json格式有误 打印$_REQUEST,数据结构大致如下: 1 2 3 4 5 6 7 8 9 10 array   (    \\\'TeleRec\\\'   = \\\'{    Tel:\\\'17090114281\\\',    Type:2,    StartTime:\\\'2016/9/19 10:19:29\\\',    EnteTime

    2024年02月10日
    浏览(26)
  • Mybatis 批量新增 只返回第一主键ID 其他返回null

    出现 问题 是加 on duplicate key update 受了影响, 去掉 on duplicate key update代码 ON DUPLICATE key update是根据索引字段是否重复来判断是否执行,如果重复则执行update,否则则执行insert。 优先级主键唯一索引 当主键重复时则执行update 当主键不重复,唯一索引重复时也执行update 当主键

    2024年02月16日
    浏览(39)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包