Redis(三)

2023-11-17

一、SpringBoot与Redis集成

1、引入依赖


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-parent</artifactId>
        <version>2.1.5.RELEASE</version>
    </parent>

    <dependencies>

        <!--引入spring mvc 依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--
            spirng boot 单元测试
        -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>


        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.1.0</version>
        </dependency>



        <!-- redis 配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.1.1.RELEASE</version>
        </dependency>

    </dependencies>

2、创建配置文件

server.port=8080

# redis 单机配置
spring.redis.host=192.168.12.130
spring.redis.port=6379


#redis 集群配置
#spring.redis.cluster.nodes=192.168.12.130:7001,192.168.12.130:7002,192.168.12.130:7003,192.168.12.130:7004,192.168.12.130:7005,192.168.12.130:7006
#spring.activemq.close-timeout=5000

3、创建启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {

    public static void main(String[] args) {

        SpringApplication.run(MyApplication.class,args);
    }

}

4、单元测试类

重点:必须和启动类同一包

package com.qfedu;

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.*;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

/**
 * 当前单元测试类 必须和启动类 在同一包下
 */

@RunWith(SpringRunner.class)
@SpringBootTest // 表明当前类是  springboot  单元测试类 必须和启动类 在同一包下
public class RedisTest {

    /**
     * StringRedisTemplate  所有存储数据都是string 字符串
     *    Template  模板  模板设计模式
     *              作用为使用方式 提供统一的 方法调用
     *
     */
    @Autowired // 从容器中获取stringRedisTemplate   key String  value 也是string (hash 除外)
    private StringRedisTemplate stringRedisTemplate;

    @Test
    public void  stringTest(){

        // ValueOperations 就是 springboot 对应 redis 提供的 key String (key value) 类型的的操作类
        ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();


        valueOperations.set("name", "xiaoing ");
        String name = valueOperations.get("name");

        System.out.println("name = " + name);


    }

    @Test
    public void hastTest(){

        // 操作 值为 hash 接口
        HashOperations<String, Object, Object> hashOperations = stringRedisTemplate.opsForHash();

        // 设置数据
        hashOperations.put("user1", "name", "xiaoxue");


        String name = (String) hashOperations.get("user1", "name");

        System.out.println("name = " + name);

    }

    /**
     * 测试 list
     */
    @Test
    public void listTest(){

        ListOperations<String, String> listOperations = stringRedisTemplate.opsForList();


        listOperations.leftPush("list1", "a");
        listOperations.leftPush("list1", "b");
        listOperations.leftPush("list1", "c");


        List<String> list1 = listOperations.range("list1", 0, -1);
        System.out.println("list1 = " + list1);

    }

    @Test
    public void boundValueTest(){


        // 在获取时 直接绑定了key   省去了每次操作制定 key 的流程
        BoundValueOperations<String, String> valueOps = stringRedisTemplate.boundValueOps("name");

        valueOps.set("xiaowang");

        String name = valueOps.get();

        System.out.println("name = " + name);

    }

    /**
     * 绑定 key  value Hash
     */
    @Test
    public void  boundHashTest(){

        BoundHashOperations<String, Object, Object> hashOps = stringRedisTemplate.boundHashOps("user1");

        hashOps.put("name", "xiaocui");

        Object name = hashOps.get("name");

        System.out.println("name = " + name);
    }

}

在这里插入图片描述

五、在springboot reids启动器中提供了两个模板类

StringRedisTemplate

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

RedisTemplate

 public void afterPropertiesSet() {
        super.afterPropertiesSet();
        boolean defaultUsed = false;
        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;
                defaultUsed = true;
            }

            if (this.valueSerializer == null) {
                this.valueSerializer = this.defaultSerializer;
                defaultUsed = true;
            }

            if (this.hashKeySerializer == null) {
                this.hashKeySerializer = this.defaultSerializer;
                defaultUsed = true;
            }

            if (this.hashValueSerializer == null) {
                this.hashValueSerializer = this.defaultSerializer;
                defaultUsed = true;
            }
        }

        if (this.enableDefaultSerializer && defaultUsed) {
            Assert.notNull(this.defaultSerializer, "default serializer null and not all serializers initialized");
        }

        if (this.scriptExecutor == null) {
            this.scriptExecutor = new DefaultScriptExecutor(this);
        }

        this.initialized = true;
    }

RedisTemplate 与 StringRedisTemplate区别

  • RedisTemplate:
    RedisTemplate是最基本的操作类,它默认的序列化方式是JdkSerializationRedisSerializer,在存值时,键值会被序列化为字节数组,可读性差,取值时也是一样,如果redis中存的值正常的字符串形式,取值时将返回null
  • StringRedisTemplate:
    StringRedisTemplate继承于 RedisTemplate<String, String>,默认的序列化方式是StringRedisSerializer,存值取值都是按照字符串的形式
 @Autowired// 序列化 jdk  序列化
    private RedisTemplate redisTemplate;

    @Test
    public void  redisTemplateTest1(){


        ValueOperations valueOperations = redisTemplate.opsForValue();

        valueOperations.set("str1", "hallo world");
        System.out.println("str1:"+valueOperations.get("str1"));
    }

在这里插入图片描述
解决RedistTemplate乱码

@Configuration
public class RedisConfig {

    
    @Bean("redisTemplate")
    public RedisTemplate redisTemplate(RedisConnectionFactory factory, Jackson2JsonRedisSerializer redisJsonSerializer) {
        RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
        //redis连接工厂
        template.setConnectionFactory(factory);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        //redis.key序列化器
        template.setKeySerializer(stringRedisSerializer);
        //redis.value序列化器
        template.setValueSerializer(redisJsonSerializer);
        //redis.hash.key序列化器
        template.setHashKeySerializer(stringRedisSerializer);
        //redis.hash.value序列化器
        template.setHashValueSerializer(redisJsonSerializer);
        //调用其他初始化逻辑
        template.afterPropertiesSet();
        //这里设置redis事务一致
        template.setEnableTransactionSupport(true);
        return template;
    }

    /**
     * 配置redis Json序列化器
     *
     * @return
     */
    @Bean
    public Jackson2JsonRedisSerializer redisJsonSerializer() {
        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
        Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(mapper);
        return serializer;
    }
}

二、Mybatis 使用Redis 作为二级缓存

单机 mybatis 开启二级缓存
1、在配置文件开启全局开关
2、在xml 注解 @CacheNamespace// 开启器二级缓存

mybatis 一级二级 缓存共同点
​在查询时 commit 产生缓存,只要发生增删改 清空缓存
mybatis 查询先去二级缓存,二级再去一级 ,一级没有去数据库差
mybatis-spring 应用中,每调用一次dao接口对应的方法,都会产生一个新的sqlSession,不存在一级缓存

1、mybatis 使用redis 作为二级缓存的优点

优点
1.提交查询效率
2.节约每个应用的jvm 内存空间 便于垃圾回收

在这里插入图片描述

2、在配置文件开启mybatis二级缓存

# 开启mybatis 二级缓存
mybatis.configuration.cache-enabled=true

3、创建 自定缓存类

package com.qfedu.cache;

import org.apache.ibatis.cache.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 自定义 mybatis 二级缓存  底层使用 redis 存储
 *
 * 当前 cache 没有加入到容器
 *
 */

public class RedisCache implements Cache {

    private  String id;

    // 读写锁  可以多个人同时读,只要有一个人写 其他人都不能读
    private  ReadWriteLock readWriteLock = new ReentrantReadWriteLock();



    public RedisCache() {
    }

    public RedisCache(String id) {
        System.out.println("命名空间-----id:"+id);
        this.id = id;
    }

    // 获取的id 就是 当前mapper 的命名空间
    public String getId() {
        return id;
    }


    /**
     * 向缓存中存放数据   key(类似sql) value (查询结果)
     * @param o
     * @param o1
     */
    public void putObject(Object key, Object value) {
        System.out.println("存储  key = " + key);
            getRedisTemplate().opsForValue().set(key.toString(), value, 10, TimeUnit.MINUTES);
    }

    /**
     * 获取缓存是 通过 key
     * @param key
     * @return
     */
    public Object getObject(Object key) {
        System.out.println("获取key 对应的值  key = " + key);

        return getRedisTemplate().opsForValue().get(key.toString());
    }

    /**
     * 清除key 对应的缓存
     * @param key
     * @return
     */
    public Object removeObject(Object key) {
        System.out.println("删除  key = " + key);
        return getRedisTemplate().delete(key.toString());
    }

    /**
     * 清空当前命名空间二级缓存
     *          就是删除所有 对应namespace(id) 的 key
     */
    public void clear() {
        // 获取到所有包含 namespace(id) 的 key
        Set<String> keys = getRedisTemplate().keys("*" + id + "*");

        for (String key : keys) {
            System.out.println("遍历清空所有的namespace 下 的key = " + key);
            getRedisTemplate().delete(key);
        }

    }

    /**
     * 获取当前命名空间对应的条数
     * @return
     */
    public int getSize() {

        System.out.println("获取当前命名空间下 的条数");
        // 获取到所有包含 namespace(id) 的 key
        Set<String> keys = getRedisTemplate().keys("*" + id + "*");
        return keys.size();
    }

    public ReadWriteLock getReadWriteLock() {
        return readWriteLock;
    }


    /**
     * 获取容器中的 redisTemplate
     * @return
     */
    public  RedisTemplate getRedisTemplate(){

        // 获取到容器
        ApplicationContext applicationContext = ApplicationHolder.getApplicationContext();

        return (RedisTemplate) applicationContext.getBean("redisTemplate");
    }
}

package com.qfedu.cache;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 *
 * ApplicationContextAware  作用 就是 在生成 对应的实例是调用,将容器ApplicationContext 传进来
 */
@Component// 将当前类加入到容器中  ,如果当前类实现ApplicationContextAware 还会在创建bean调用改接口对应的setApplicationContext
public class ApplicationHolder implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // 持有上下文对象
        this.applicationContext  = applicationContext;
    }


    /**
     * 获取核心容器
     * @return
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
}

4、在xml 中使用自定义缓存

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qfedu.dao.StudentDao">

    <!--  开启二级缓存

        type="" mybatis  会使用 用户自定的二级缓存 存储 如果没有配置就是用 jvm

        mybatis 创建 RedisCache ,没有加入到容器中
    -->
    <cache type="com.qfedu.cache.RedisCache" eviction="LRU" size="1024" flushInterval="60"></cache>

    <!--
            在springboot中使用别名有 警告 误报没有影响
            可以使用全限定名解决  com.qfedu.entity.Student

    -->
    <select id="findAllStudent" resultType="com.qfedu.entity.Student">
        select * from student_tb
    </select>


    <update id="updateStudent">
        update student_tb  set name = #{name},age =  #{age},sex = #{sex},height=#{height} where id =#{id}
    </update>

</mapper>

5、测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyBatisTest {

    @Autowired
    private StudentService studentService;

    @Test
    public void findAllStudentTest(){
        // 第一次查询
        List<Student> allStudent = studentService.findAllStudent();

        System.out.println("allStudent = " + allStudent);

        System.out.println(" xiaocui!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*********************");
        // 第二次查询
        List<Student> allStudent2 = studentService.findAllStudent();

        System.out.println("allStudent2 = " + allStudent2);

    }


    @Test
    public void updateStudentTest(){

        Student student = new Student();
        student.setId(2);
        student.setName("崔老师");
        student.setAge(20);
        student.setSex("M");
        student.setHeight(190);

        // 只要发生增删改 清空二级缓存
        int num =  studentService.updateStudent(student);

        System.out.println("num = " + num);
    }


}

三、Spring使用Redis作为缓存

Spring 本身也支持缓存,也可以使用使用redis 作为缓存

缓存方法调用的结果

Spring Cache 默认使用SimpleCacheConfiguration 来进行缓存的,如果配置了Springboot-redis启动器则使用Redis缓存

Spring Boot缓存注解有 @EnableCaching @Cacheable、@CacheEvict、@CachePut @Caching

前提条件 关闭二级缓存

# 开启mybatis 二级缓存
mybatis.configuration.cache-enabled=false

1、开启spring缓存

@MapperScan("com.qfedu.dao")
@SpringBootApplication
@EnableCaching// 开启 spring 缓存
public class MyApplication {

    public static void main(String[] args) {

        SpringApplication.run(MyApplication.class,args);
    }

}

使用缓存

  • @Cacheable
    作用在方法上 ,将该方法对应的结果进行缓存
  • @CachePut(value = “student”,key = “#student.id”)// 在更新时 会更新 spring 缓存 ,并且写入mysql
    // 先更新缓存 (缓存结果为 返回的数据) 在 修改数据库
  • @CacheEvict(value = “student”,key = “#id”,allEntries = true,beforeInvocation=true)// 在删除的时候清空所有的缓存(否则会出现数据不一致问题)
    // 会删除所有以 student 开头的 key ,allEntries = true
    // 调用在这个 方法之前 先清空缓存 在去数据库删除(防止脏数据出现)
package com.qfedu.controller;

import com.qfedu.entity.Student;
import com.qfedu.service.StudentService;
import org.junit.After;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * Student 相关
 */
@RestController
public class StudentController {

    @Autowired
    private StudentService studentService;


    @RequestMapping("/findAllStudent")
    @Cacheable(value = "student") // 将结果进行缓存   student 对应缓存key 的前缀
    public List<Student> findAllStudent(){
        System.out.println("查询所有学生");

        return studentService.findAllStudent();
    }


    @RequestMapping("/findStudentById")
    @Cacheable(value = "student",key = "#id",condition = "#id>2")// key 制定缓存key  condition 制定缓存条件,不满足条件不会缓存
    public Student findStudentById(int id) {

        System.out.println("查询所有学生id"+ id);

        return studentService.findStudentById(id);
    }



    @RequestMapping("/updateStudent")
    @CachePut(value = "student",key = "#student.id")// 在更新时 会更新 spring 缓存 ,并且写入mysql
    //  先更新缓存 (缓存结果为 返回的数据) 在 修改数据库
    //  更新也尽量用 @CacheEvict 有可能发生脏数据
    public Student  updateStudent(Student student){


        int num =   studentService.updateStudent(student);


        return student;
    }

    @RequestMapping("/deleteStudentById")
    @CacheEvict(value = "student",key = "#id",allEntries = true,beforeInvocation=true)// 在删除的时候清空所有的缓存(否则会出现数据不一致问题)
    // 会删除所有以 student 开头的 key  ,allEntries = true
    // 调用在这个 方法之前 先清空缓存 在去数据库删除(防止脏数据出现)   beforeInvocation=true

    public String deleteStudentById(int id){

        int i = studentService.deleteStudentById(id);

        return i +"";
    }
}

四、redis缓存的常见问题

1、缓存穿透问题

穿透:穿过去(redis)去mysql 查询 ,查询数据库中不存在的数据,每次都要穿过reddis 去数据库查询一下

当前我们查询的结果id=1000 student 在数据库中没有时,不会在redis中缓存,下一次再去查询id=1000 student (经过redis ,redis 没有 去数据库拿,没有,)

在这里插入图片描述

2、缓存击穿问题

缓存击穿,就是缓存中的数据失效,用户访问时,不得已去数据库查询

雪崩:就是因为 mysql 响应时间过长,造成 tomcat 请求响应堆积,可能造成tomcat 连接数 内存不够用 tomcat挂掉 整个系统崩塌

在这里插入图片描述

3、缓存倾斜

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Redis(三) 的相关文章

  • Android:如何暂停和恢复可运行线程?

    我正在使用 postDelayed 可运行线程 当我按下按钮时 我需要暂停并恢复该线程 请任何人帮助我 这是我的主题 protected void animation music6 music4 postDelayed new Runnab
  • java程序有多少种结束方式?

    我知道使用 System exit 0 可以结束一个java程序 例如 如果我有一个JFrame窗口 它会关闭并结束程序 但我想知道还有多少其他方法 可以关闭它并结束程序 包括发生错误时 程序会被关闭 JFrame也会被关闭吗 添加到其他答
  • 在不支持 CAS 操作的处理器上进行 CompareAndSet

    今天 我在一次采访中被问到下一个问题 如果您在具有不支持 CAS 操作的处理器的机器上调用 AtomicLong 的compareAndSet 方法 会发生什么情况 您能否帮我解决这个问题 并在可能的情况下提供一些全面描述的链接 From
  • 以相反的顺序打印任何集合中的项目?

    我在 使用 Java 进行数据结构和问题解决 一书中遇到以下问题 编写一个例程 使用 Collections API 以相反的顺序打印任何 Collection 中的项目 不要使用 ListIterator 我不会把它放在这里 因为我想让有
  • Java LostFocus 和 InputVerifier,按反向制表符顺序移动

    我有一个 GUI 应用程序 它使用 InputVerifier 在产生焦点之前检查文本字段的内容 这都是很正常的 然而 昨天发现了一个问题 这似乎是一个错误 但我在任何地方都找不到任何提及它的地方 在我将其报告为错误之前 我想我应该问 我在
  • 无法使用 datastax java 驱动程序通过 UDT 密钥从 cassandra 检索

    我正在尝试使用用户定义的类型作为分区键将对象存储在 cassandra 中 我正在使用 datastax java 驱动程序进行对象映射 虽然我能够插入到数据库中 但无法检索该对象 如果我更改分区键以使用非 udt 例如文本 我就能够保存和
  • Java中Gson、JsonElement、String比较

    好吧 我想知道这可能非常简单和愚蠢 但在与这种情况作斗争一段时间后 我不知道发生了什么 我正在使用 Gson 来处理一些 JSON 元素 在我的代码中的某个位置 我将 JsonObject 的 JsonElements 之一作为字符串获取
  • 将类转换为 JSONObject

    我有好几堂这样的课 我想将类转换为 JSONObject 格式 import java io Serializable import com google gson annotations SerializedName public cla
  • JAXB - 忽略元素

    有什么方法可以忽略 Jaxb 解析中的元素吗 我有一个很大的 XML 文件 如果我可以忽略其中一个大而复杂的元素 那么它的解析速度可能会快很多 如果它根本无法验证元素内容并解析文档的其余部分 即使该元素不正确 那就更好了 例如 这应该只生成
  • 如何更改 Swagger-ui URL 前缀?

    我正在使用 Springfox Swagger2 和 Spring boot 1 5 9 我可以通过此链接访问 swagger UI http localhost 8090 swagger ui html http localhost 80
  • 如何使用双重调度来分析图形基元的交集?

    我正在分析图形基元 矩形 直线 圆形等 的交互并计算重叠 相对方向 合并等 这被引用为双重调度的一个主要示例 例如维基百科 http en wikipedia org wiki Double dispatch 自适应碰撞算法通常要求 不同的
  • IntelliJ Idea:将简单的 Java servlet(无 JSP)部署到 Tomcat 7

    我尝试按照教程进行操作here http wiki jetbrains net intellij Creating a simple Web application and deploying it to Tomcat部署 servlet
  • 类更改(例如字段添加或删除)是否保持 Serialized 的向后兼容性?

    我有一个关于 Java 序列化的问题 在这种情况下 您可能需要修改可序列化类并保持向后兼容性 我有丰富的 C 经验 所以请允许我将 Java 与 NET 进行比较 在我的Java场景中 我需要使用Java的运行时序列化机制序列化一个对象 并
  • 文本视图不显示全文

    我正在使用 TableLayout 和 TableRow 创建一个简单的布局 其中包含两个 TextView 这是代码的一部分
  • Lombok 不适用于 Eclipse Neon

    我下载了lombok jar lombok 1 16 14 jar 并将其放入我的下载中 然后我点击这个 jar 执行正确地识别了我的 MacOS 上的 Eclipse 实例 然后我选择了我想要的实例 Lombok也在pom xml中指定
  • Azure Java SDK:ServiceException:ForbiddenError:

    尝试了基本位置检索器代码 如下所示 String uri https management core windows net String subscriptionId XXXXXXXX 5fad XXXXXX 9dfa XXXXXX St
  • 我所有的 java 应用程序现在都会抛出 java.awt.headlessException

    所以几天前我有几个工作Java应用程序使用Swing图书馆 JFrame尤其 他们都工作得很好 现在他们都抛出了这个异常 java awt headlessexception 我不知道是什么改变了也许我的Java版本不小心更新了 谢谢你尽你
  • 用于请求带有临时缓存的远程 Observable 的 RxJava 模式

    用例是这样的 我想暂时缓存最新发出的昂贵的Observable响应 但在它过期后 返回到昂贵的源Observable并再次缓存它 等等 一个非常基本的网络缓存场景 但我真的很难让它工作 private Observable
  • 什么是 Java2D 处理程序线程?

    我创建了一个使用 Hibernate 的示例 java 应用程序 当我进行线程转储时 我观察到一个名为 Java2D Disposer 的奇怪线程 有人能告诉我该线程的功能吗 AWT 系统中的某些实体需要最终确定以释放资源 最突出的例子是j
  • 在会话即将到期之前调用方法

    我的网络应用程序有登录的用户 有一个超时 在会话过期之前 我想执行一个方法来清理一些锁 我已经实现了sessionListener但一旦我到达public void sessionDestroyed HttpSessionEvent eve

随机推荐

  • np.where()函数的详细使用介绍

    看了很多博客 见到的没有一个给说清楚了 这里做个记录 这是python提供的函数说明 Help on function where in module numpy where where condition x y Return eleme
  • linux man php,linux man命令的使用

    linux man命令的使用 main 是最常见的帮助命令 也是 Linux 最主要的帮助命令 其基本信息如下 命令名称 man 英文原意 format and display the on line manual pages 所在路径 u
  • 第二个电商项目Bug点统计和解决方法

    第二个完成的项目 在完成项目后 我总结了那些自己感觉重要的BUG 1 BUG系列一 设置延时 导致Activity销毁后 延时中的PullToRefreshListView 为null Bug现象 Bug 85536 在网络不好情况下 快速
  • Nuitka 和 PyInstaller 对比

    一 什么是 Nuitka 和 PyInstaller 1 1 Nuitka Nuitka 是一个 Python 编译器 可以将 Python 代码转换成可执行的 C 代码 然后将其编译成本机可执行文件 与常规的 Python 解释器相比 使
  • 8.3 PowerBI系列之DAX函数专题-矩阵Matrix中高亮显示最大最小值

    需求 用颜色标量年度最大最小值 用颜色标示折线的最大值最小值 实现 在条件格式 规则 基于字段进行计算 度量值 is max min var displayed data calculatetable addcolumns summariz
  • 坚持天天写技术笔记

    恍恍惚惚
  • 用C语言编写一段堆排序算法

    include
  • 同步、异步和阻塞、非阻塞的区别与联系

    同步 异步和阻塞 非阻塞的概念 同步 在执行一个操作的时候需要等待当前操作执行完毕才能执行下一操作 相当于操作串行化 即执行当前函数的时候需要拿到当前函数的返回结果才可以继续执行 异步 在执行一个操作的时候不需要拿到返回结果 只需要拿到注册
  • 程序员必备的免费AI生产力(摸鱼)工具,最后一个,人手必备

    最近ChatGPT等AI技术风靡全球 对于普通大众来说 越来越多的人开始关注智能时代对我们生活的影响 它颠覆了写作 办公 绘画 音视频 图像处理 UI 设计等领域 并涌现出了一批具有颠覆性的应用 在程序员领域 许多 AI 工具已经涌现 如
  • Android fragment间的通讯

    1 使用FragmentPagerAdapter情况下 param viewpagerId viewpager id eg R id vp param position fragment 的位置 return private Fragmen
  • linux线程内存开销

    1 首先是线程自己栈 程序没设置过 就是默认的 ulimit s 中的值 现在一般都是10240 单位KB 2 跟版本有关 是否有 glibc 的 malloc per thread arenas 特性 有了这个特性 设置不好 一个新线程要
  • 2003 - Cant't connect to MySQL server on 'ip'(10060 "Unknown error")

    问题描述 今天在搭建服务器之后 安装好MySQL 启动成功 并且创建远程连接用户 用户名和密码都正确 使用Navicat远程连接抛出如下错误 2003 Cant t connect to MySQL server on 192 168 13
  • Go module的介绍及使用

    Go1 1 1版本发布 2018 08 24发布 已经过去几天 从官方的博客中看到 有两个比较突出的特色 一个就是今天讲的module 模块概念 目前该功能还在试验阶段 有些地方还需要不断的进行完善 在官方正式宣布之前 打算不断修正这种支持
  • 牛客网:美团2021校招笔试-编程题(通用编程试题,第10场)

    某比赛已经进入了淘汰赛阶段 已知共有n名选手参与了此阶段比赛 他们的得分分别是a 1 a 2 a n 小美作为比赛的裁判希望设定一个分数线m 使得所有分数大于m的选手晋级 其他人淘汰 但是为了保护粉丝脆弱的心脏 小美希望晋级和淘汰的人数均在
  • Vivido添加pynq-Z2开发板

    一 下载pynq z2开发板文件 下载地址 https www tulembedded com FPGA ProductsPYNQ Z2 html 二 将下载的文件解压到vivado安装的位置 如果boards目录下面没有boards fi
  • 软件测试自动化UI框架之生成测试报告

    设置报告 自动化测试最后的运行结果要以报告的形式呈现 报告的格式是web端网页 需要引入第三方库 不是唯一的 有很多 一般一个公司统一用一个 1 引入自动生成测试框架报告 2 创建测试报告生成文件夹 reports 3 写代码 框架的入口文
  • UE4开发七:UE4打包

    一 使用UFE打包 UFE Unreal Frontend 虚幻前端 简化加快游戏开发及测试任务的工具 它可以用来准备游戏构建 将游戏部署到设备上并进行启动 测试版本 4 18为例 注意 UE4官方文档原话是在UE4编辑器中启动UFE或者P
  • java并发编程笔记(四)--JMM内存模型

    1 计算机结构 输入设备 就是我们的鼠标 键盘 存储器 对应的就是我们的内存 缓存 运算器和控制器共同组成了cpu 而输出设备就比如显示屏 打印机 我们重点来聊一下缓存 2 缓存 其实 当我们说计算机运行效率低下 速度慢 往往不是cpu的锅
  • Qt: QStringList去除重复元素

    项目中有个需求 有一个Qt字符串列表 里面有一些元素是重复的 要求去除 只留下不重复的元素 方法如下 QStringList distin QStringList list A B C D B B E B E C for int i 0 i
  • Redis(三)

    一 SpringBoot与Redis集成 1 引入依赖