Spring-data-redis

news2024/9/21 16:18:05

一、spring-data-redis 介绍

spring-data-jpa spring-data-jdbc spring-data-redis

说明: 在 SpringBoot2.x 之后,原来使用的jedis 被替换为了 lettuce

jedis : 采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全的,使用 jedis pool 连接池

lettuce : 采用netty,实例可以再多个线程中进行共享,不存在线程不安全的情况!可以减少线程数据了

1.加入Redis相关依赖
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.application.properties中加入redis相关配置
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=192.168.0.24
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=200
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
3.具体代码了解
序列化策略
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=10
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=1000
3.具体代码了解

spring data redis中封装了两个模板类,帮助我们实现redis的crud
RedisTemplate key value泛型都是object
StringRedisTemplate key value泛型都是string
注意:
1.两者数据各自存,各自取,数据不互通。
RedisTemplate不能取StringRedisTemplate存入的数据
StringRedisTemplate不能取RedisTemplate存入的数据
2.序列化策略不同:
RedisTemplate采用JDK的序列化策略(JdkSerializationRedisSerializer)保存的key和value 都是采用此策略序列化保存的存储时,先将数据序列化为字节数组,再存入Redis数据库。查看Redis会发现,是字节数组的形式类似乱 码读取时,会将数据当做字节数组转化为我们需要的数据,以用来存储对象,但是要实现Serializable接 口
StringRedisTemplate采用String的序列化策略(StringRedisSerializer)保存的key和value都 是采用此策略序列化保存的当存入对象时,会报错:can not cast into String存储和读取,都为可读的数据
3.两者的关系是StringRedisTemplate继承RedisTemplate
4.使用场景:
当你的redis数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型数据的时候,那
么你就使 用StringRedisTemplate即可。
但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取
出一个对 象,那么使用RedisTemplate是更好的选择。
五大数据类型

  • redisTemplate.opsForValue();//操作字符串
  • redisTemplate.opsForList();//操作List
  • redisTemplate.opsForSet();//操作Set
  • redisTemplate.opsForZSet();//操作ZSet
  • redisTemplate.opsForHash();//操作Hash
3.1 redisTemplate
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootRedis01ApplicationTests {


    //演示1(专用对象)
    @Autowired
    public RedisTemplate redisTemplate;
    /**
     * 测试RedisTemplate
     * 法意:
     * 1.测试RedisTemplate与stringRedisTemplate存的数据相互独立
     * 2.redisTemplate默认使用key序列化方式和value的序列化方式都使用的是jdk serializer序列化
     * 	 所以存对象会乱码
     *
     * */
    @Test
    public void show2(){

        ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations.set("name","薛老师");
        String name = (String) valueOperations.get("name");
        System.out.println(name);


        redisTemplate.opsForValue();//String
        redisTemplate.opsForList();//List
        redisTemplate.opsForHash();//hash
        redisTemplate.opsForSet();//set
        redisTemplate.opsForZSet();//zset


        Student stu1 = new Student(1,"薛老师","洗脚");
        redisTemplate.opsForValue().set("stu1",stu1);
        Student ss1 = (Student)redisTemplate.opsForValue().get("stu1");
        System.out.println(ss1);

        redisTemplate.opsForList().leftPushAll("mylist","睡觉","游戏");
        List<String> list = redisTemplate.opsForList().range("mylist",0,-1);
        for (int i = 0; i < list.size(); i++) {
            String s =  list.get(i);
            System.out.println(s);
        }

        System.out.println("打印默认序列策略"+redisTemplate.getDefaultSerializer());


    }

3.2 StringRedisTemplate
//演示2(专用字符串key value均是String)
    @Autowired
    public StringRedisTemplate stringRedisTemplate;

    /**
     * 测试stringRedisTemplate+
     * */
    @Test
    public void stringRedisTemplate(){
        //1.key相关
        Set<String> keys = stringRedisTemplate.keys("*");
        for (String key : keys) {
            System.out.println(key);
        }
        //2.各种类型支持
        stringRedisTemplate.opsForValue();
        stringRedisTemplate.opsForList();//List
        stringRedisTemplate.opsForHash();//hash
        stringRedisTemplate.opsForSet();//set
        stringRedisTemplate.opsForZSet();//zset
        //3.举例字符串
        stringRedisTemplate.opsForValue().set("name","许老师");
        String name = stringRedisTemplate.opsForValue().get("name");
        System.out.println(name);
        //4.操作list列表
        stringRedisTemplate.opsForList().leftPush("myList1","曹丕");
        stringRedisTemplate.opsForList().leftPush("myList1","曹植");
        stringRedisTemplate.opsForList().leftPushAll("mylistAll","曹操","曹丕","曹植");
        List<String> list =  stringRedisTemplate.opsForList().range("mylistAll",0,2);
        System.out.println(list);
    }

3.3 自定义测试
3.3.1 编写Redis配置类
@Configuration
public class RedisConfig {


    @Bean
    public RedisTemplate<Object, Object> jsonRedisTemplate(
        RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        //1.创建自定义模板类
        RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
        //配置json类型的序列化工具
        template.setKeySerializer(new StringRedisSerializer());//这样key会用字符串方式保存
        template.setDefaultSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));

        template.setConnectionFactory(redisConnectionFactory);

        return template;
    }



}
3.3.2 自定义测试代码
/**
     * 测试自定义
     * 法意:定义配置类JavaConfig,自定义序列化策略
     *
     * */
    @Test
    public void show3(){
        //保存对象
        Student stu = new Student(1,"彭老师","拉面");
        jsonRedisTemplate.opsForValue().set("stu",stu);
        //获取对象
        Object s1 = jsonRedisTemplate.opsForValue().get("stu");
        String jsonS1 = JSONObject.toJSONString(s1);
        Student s11 = JSONObject.parseObject(jsonS1,Student.class);
        System.out.println(s11);

        Student stu2 = new Student(2,"彭老师","拉面");
        Student stu1 = new Student(2,"彭老师","拉面");
        Student stu3 = new Student(2,"彭老师","拉面");
        List<Student> students = Arrays.asList(stu1, stu2, stu3);
        jsonRedisTemplate.opsForValue().set("stus",students);
        //必须Object接受,利用ObjectMapper对象转换,如果强制转换会报错
        Object data = jsonRedisTemplate.opsForValue().get("stus");
        String dataJson = JSONObject.toJSONString(data);
        //将JSON类型转为List
        List<Student> stus = JSONObject.parseArray(dataJson, Student.class);
        System.out.println(stus);

    }

}

3.4序列化策略

改变序列化策略

默认序列化方式存储到redis的数据人工不可读不同策略序列化的过程有性能高低的

spring-data-redis提供如下几种序列化策略

GenericTostringserializer:可以将任何对象泛化为字符串并序列化

jackson23sonRedisserializer: 跟JacksonJsonRedisserializer实际上是一样的

jacksonJsonRedisserializer:序列化object对象为json字符串

jdkserializationRedisserializer:序列化java对象

stringRedisserializer:简单的字符串序列化

二、使用Redis结合三层框架做学生的查看与删除,第一次查看的时候Redis缓存中没有数据,所以会在数据库中查看结果,返回数据,第二次查看的时候就可以直接在缓存中查看

代码展示:
@Configuration
public class RedisConfig{


    @Bean
    public RedisTemplate<Object, Object> jsonRedisTemplate(
            RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setStringSerializer(new StringRedisSerializer());
        //配置json类型的序列化工具
        template.setDefaultSerializer(new Jackson2JsonRedisSerializer(Object.class));
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }


}
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("student")
public class Student {
    @TableId(value = "stu_id" ,type = IdType.AUTO)
    private Integer stuId;
    @TableField("stu_name")
    private String stuName;
    @TableField("stu_hobby")
    private String stuHobby;


}
public interface StudentMapper extends BaseMapper<Student>{

}
package com.ztt.springboot_redis02.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

// 在我们真实的开发中,一般都可以看到一个公司自己封装RedisUtil
@Component
public  class RedisUtil {

    @Autowired(required = false)
    private RedisTemplate jsonRedisTemplate;
    
    // =========================================================
    /**
     * 指定缓存失效时间
     * @param key  键
     * @param time 时间(秒)
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                jsonRedisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据key 获取过期时间
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key) {
        return jsonRedisTemplate.getExpire(key, TimeUnit.SECONDS);
    }


    /**
     * 判断key是否存在
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return jsonRedisTemplate.hasKey(key);
        } catch (Exception e) {
            return false;
        }
    }


    /**
     * 删除缓存
     * @param key 可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                jsonRedisTemplate.delete(key[0]);
            } else {
                jsonRedisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }


    // ============================String=============================

    /**
     * 普通缓存获取
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : jsonRedisTemplate.opsForValue().get(key);
    }
    
    /**
     * 普通缓存放入
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */

    public boolean set(String key, Object value) {
        try {
            jsonRedisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            return false;
        }
    }


    /**
     * 普通缓存放入并设置时间
     * @param key   键
     * @param value 值
     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */

    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                jsonRedisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 递增
     * @param key   键
     * @param delta 要增加几(大于0)
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return jsonRedisTemplate.opsForValue().increment(key, delta);
    }


    /**
     * 递减
     * @param key   键
     * @param delta 要减少几(小于0)
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        return jsonRedisTemplate.opsForValue().increment(key, -delta);
    }


    // ================================Map=================================

    /**
     * HashGet
     * @param key  键 不能为null
     * @param item 项 不能为null
     */
    public Object hget(String key, String item) {
        return jsonRedisTemplate.opsForHash().get(key, item);
    }
    
    /**
     * 获取hashKey对应的所有键值
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object, Object> hmget(String key) {
        return jsonRedisTemplate.opsForHash().entries(key);
    }
    
    /**
     * HashSet
     * @param key 键
     * @param map 对应多个键值
     */
    public boolean hmset(String key, Map<String, Object> map) {
        try {
            jsonRedisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * HashSet 并设置时间
     * @param key  键
     * @param map  对应多个键值
     * @param time 时间(秒)
     * @return true成功 false失败
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
        try {
            jsonRedisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value) {
        try {
            jsonRedisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {
            jsonRedisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 删除hash表中的值
     *
     * @param key  键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item) {
        jsonRedisTemplate.opsForHash().delete(key, item);
    }


    /**
     * 判断hash表中是否有该项的值
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        return jsonRedisTemplate.opsForHash().hasKey(key, item);
    }


    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     *
     * @param key  键
     * @param item 项
     * @param by   要增加几(大于0)
     */
    public double hincr(String key, String item, double by) {
        return jsonRedisTemplate.opsForHash().increment(key, item, by);
    }


    /**
     * hash递减
     *
     * @param key  键
     * @param item 项
     * @param by   要减少记(小于0)
     */
    public double hdecr(String key, String item, double by) {
        return jsonRedisTemplate.opsForHash().increment(key, item, -by);
    }


    // ============================set=============================

    /**
     * 根据key获取Set中的所有值
     * @param key 键
     */
    public Set<Object> sGet(String key) {
        try {
            return jsonRedisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 根据value从一个set中查询,是否存在
     *
     * @param key   键
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return jsonRedisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 将数据放入set缓存
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSet(String key, Object... values) {
        try {
            return jsonRedisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * 将set数据放入缓存
     *
     * @param key    键
     * @param time   时间(秒)
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = jsonRedisTemplate.opsForSet().add(key, values);
            if (time > 0)
                expire(key, time);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * 获取set缓存的长度
     *
     * @param key 键
     */
    public long sGetSetSize(String key) {
        try {
            return jsonRedisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * 移除值为value的
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 移除的个数
     */

    public long setRemove(String key, Object... values) {
        try {
            Long count = jsonRedisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    // ===============================list=================================
    
    /**
     * 获取list缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束 0 到 -1代表所有值
     */
    public List<Object> lGet(String key, long start, long end) {
        try {
            return jsonRedisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 获取list缓存的长度
     *
     * @param key 键
     */
    public long lGetListSize(String key) {
        try {
            return jsonRedisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * 通过索引 获取list中的值
     *
     * @param key   键
     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     */
    public Object lGetIndex(String key, long index) {
        try {
            return jsonRedisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     */
    public boolean lSet(String key, Object value) {
        try {
            jsonRedisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 将list放入缓存
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            jsonRedisTemplate.opsForList().rightPush(key, value);
            if (time > 0)
                expire(key, time);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }


    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            jsonRedisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }


    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            jsonRedisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0)
                expire(key, time);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据索引修改list中的某条数据
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return
     */

    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            jsonRedisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 移除N个值为value
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */

    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = jsonRedisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }

    }

}
package com.ztt.springboot_redis02.service;



import com.ztt.springboot_redis02.pojo.Student;
import com.ztt.springboot_redis02.mapper.StudentMapper;

import com.ztt.springboot_redis02.utils.RedisUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;


@Service
public class StudentService {


    @Autowired(required = false)
    StudentMapper mapper;

    @Autowired
    public RedisUtil redisUtil;


    /**
     * 获取用户策略:先从缓存中获取用户,没有则取数据表中数据,再将数据写入缓存
     */
    public Student findById(Integer id){
        String key = "student:id:" + id;

        //1.1判断key在redis中是否存在
        boolean hasKey = redisUtil.hasKey(key);
        if (hasKey) {
            //1.2存在缓存则直接获取
            Object stu = redisUtil.get(key);
            ObjectMapper change = new ObjectMapper();
            Student student =   change.convertValue(stu,Student.class);
            System.out.println("==========从缓存中获得数据=========");
            System.out.println(student.getStuName());
            System.out.println("==============================");
            return student;
        } else {
            //1.3不存在缓存,先从数据库中获取,在保存至redis,最后返回用户
            Student student = mapper.selectById(id);
            System.out.println("==========从数据表中获得数据=========");
            System.out.println(student.getStuName());
            System.out.println("==============================");
            if (student != null){
                redisUtil.set(key, student);//写入缓存
            }
            return student;
        }
    }


    /**
     * 删除用户策略:删除数据表中数据,然后删除缓存
     *
     */
    public void deleteStudentById(Integer id){
        //1.删除数据库
        int result = mapper.deleteById(id);
        //2.判断数据库中是否删除成功
        String key = "student:id:" + id;
        if (result != 0) {
            //3.判断redis中是否存在
            boolean hasKey = redisUtil.hasKey(key);
            //4.存在删除,不存在直接跳转
            if (hasKey) {
                redisUtil.del(key);
                System.out.println("删除了缓存中的key:" + key);
            }
        }
    }

}
@RestController
public class StudentController {

    @Autowired
    StudentService stuService;

    @GetMapping("/findById/{id}")
    public Student findById(@PathVariable("id") Integer id) {
        Student stu = stuService.findById(id);
        return stu;
    }
@SpringBootApplication
@MapperScan("com.ztt.springboot_redis02.mapper")
public class SpringbootRedis02Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootRedis02Application.class, args);
    }

}
输出结果:

 

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

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

相关文章

vue前后端交互学习问题记录2

1.在使用定时任务时报如下错误&#xff1a;No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton. This is an invalid application configuration. 看报错是ThreadContext未绑定Secur…

Java调用Python的简单运用

这里提供两种调用方法&#xff1a; 1、通过Jython来实现Java调用Python (目前只支持Python2) 2、通过ProcessBuilder来实现Java执行Python脚本&#xff08;既支持Python2也支持Python3&#xff09; 通过Jython来实现Java调用Python Jython目前只支持Python2 一、准备好Pytho…

如何高效记录并整理编程学习笔记

目录 1.概述 1.1. 选择合适的工具 1.2. 分类整理 1.3. 制定标准格式 1.4. 定期复习和更新 1.5. 利用图形和视觉辅助 1.6. 记录问题和解决过程 1.7. 使用版本控制 1.8. 与他人分享和讨论 2.笔记工具选择 2.1. 印象笔记 2.2. 语雀 2.3. 有道云笔记 2.4. 腾讯文档 …

基于Spring Boot的企业员工薪酬关系系统的设计

TOC springboot229基于Spring Boot的企业员工薪酬关系系统的设计 第一章 课题背景及研究内容 1.1 课题背景 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#…

Spring好坑!为什么代理对象的属性没有值?

先看代码&#xff1a; Service Transactional public class ZhouyuService {private String name "zhouyu";public final void test() {System.out.println(name);} }关键点&#xff1a; 加了Transactional&#xff0c;所以ZhouyuService会生成代理对象作为Bean对…

HAProxy理论+实验

目录 一、基于cookie的会话保持 1、配置选项 2、配置示例 3、验证cookie信息 二、IP透传 1、layer4 与 layer7 &#xff08;1&#xff09;四层:IPPORT转发 &#xff08;2&#xff09;七层:协议内容交换 三、haproxy的ACL应用 1、ACL配置选项 &#xff08;1&#xf…

应用案例:劳易测传感器助力宝马集团莱比锡工厂锂电池生产

位于德国萨克森州的宝马集团莱比锡工厂&#xff0c;是全球领先的汽车制造基地之一&#xff0c;不仅生产燃油车&#xff0c;也致力于电动汽车的生产。随着电动汽车及混合动力车辆的普及&#xff0c;锂电池的需求日益增长&#xff0c;宝马集团在莱比锡工厂内部设立了锂电池生产线…

Python之简单了解pylab绘图工具和汇编语言

《Python入门经典以解决计算问题为导向的Python编程实践》89-93页的笔记。 用pylab对数据绘图最小的通用计算 用pylab对数据绘图 PyLab是Matplotlib面向对象绘图库的过程界面。Matplotlib是整个软件包&#xff1b; matplotlib.pyplot是Matplotlib中的一个模块&#xff1b;而P…

能够清理浮毛的宠物空气净化器哪家好用?希喂、安德迈测评分享

虽然已经立秋了&#xff0c;但是现在这个天气还是很热&#xff0c;尤其是还处在南方城市就更加了&#xff0c;天气热空气中的水含量还高&#xff0c;这就代表着即使下雨天能降温但身体还是会有黏黏的感觉。家里养有猫和狗&#xff0c;大汗淋漓的到家&#xff0c;一进门就被我家…

17位著名妈妈和女儿在电影中合作 包括斯特里普、黛米摩尔、安吉丽娜朱莉等

好莱坞母女二人组正在占领大银幕。如今&#xff0c;你不会只在头条新闻中看到她们的名字。这些强大的女性正在联手&#xff0c;创造电影奇迹&#xff0c;并为她们家喻户晓的名字增添更多的明星影响力。 虽然像戈尔迪霍恩和凯特哈德森这样的母女组合更喜欢分开工作&#xff0c;…

Python进阶之3D图形

Python进阶之3D图形 在数据可视化中&#xff0c;2D图形通常可以满足大多数需求。然而&#xff0c;对于一些复杂的数据或分析&#xff0c;3D图形可以提供更多的视角和洞察。在Python中&#xff0c;使用 Matplotlib 和 Plotly 等库可以轻松创建各种3D图形。本文将介绍如何使用这…

C++第一讲:开篇

C第一讲&#xff1a;开篇 1.C历史背景1.1C创世主--本贾尼1.2C版本更新1.3C的重要性1.4C书籍推荐 2.C的第一个程序3.命名空间3.1namespace是什么3.2namespace的使用3.3namespace使用注意事项3.4命名空间的使用 4.C输入和输出5.缺省参数6.函数重载7.引用7.1什么是引用7.2引用的定…

点餐系统软件源码入门教程:从零开始构建你的餐饮系统

随着餐饮行业的数字化转型&#xff0c;点餐系统已经成为餐厅运营不可或缺的一部分。无论是新手开发者还是有经验的程序员&#xff0c;学习如何从零开始构建一个点餐系统&#xff0c;都是一项具有挑战性但又非常有意义的任务。本文将带你逐步了解如何使用基本的技术和代码&#…

E. Lucky Queries

https://codeforces.com/contest/145/problem/E 元素值只有4,7转换成01序列&#xff0c;操作一区间反转,操作二询问类LIS 我们先考虑操作二 应该维护什么量呢 线段树维护量&#xff0c;是通过左子树和右子树的信息合并来维护的 大致有两种情况 可以发现可以通过Leftcnt0Righ…

45.跳跃游戏

&#xff1a;双层for。复杂度n*n n class Solution {public int jump(int[] nums) {// 找到所有的条约方法&#xff0c;返回其中的最小次数// 从后向前&#xff0c;依次记录到最后的次数int n nums.length;if(n 1) return 0;// int[] temp new int[n];// temp[n-1] 0;fo…

Redis远程字典服务器(5) —— hash类型详解

目录 一&#xff0c;hash基本情况 二&#xff0c;hash常用命令详解 2.1 hset&#xff0c;hget&#xff0c;hexists&#xff0c;hdel 2.2 hexists&#xff0c;hdel 2.3 hkeys&#xff0c;hvals 2.4 hgetall&#xff0c;hmget 2.5 hlen&#xff0c;hsetnx 2.6 hincrby&am…

Android逆向题解 攻防世界难度4- Android2.0

Jeb打开apk 关键代码在Native函数getResult IDA 打开 so 发现代码比较简单&#xff0c;可以直接静态分析。 输出字符串也就是flag 长度是15&#xff0c;然后分成三段&#xff0c;第一段是可以整除3&#xff0c;第二段是除3取余1&#xff0c;第三段是除3取余等于2&#xff1…

【Redis进阶】缓存设计模式

目录 Cache Aside&#xff08;旁路缓存&#xff09;模式 概念 读操作流程如上图所示 写操作流程如上图所示 代码示例 总结 Read-Through 模式 概念 操作流程&#xff1a; 优点&#xff1a; Write-Through 模式 概念 操作流程&#xff1a; 优点&#xff1a; Writ…

【摄影后期技巧】连拍多张图像中快速找到最清晰的图像——Python代码实现

手持相机高速连拍过程&#xff0c;当快门速度不够高时不可避免出现模糊帧&#xff0c;通过肉眼去从多张连拍图像中找到最清晰的帧是比较费事的&#xff0c;可通过代码自动去计算最清晰的图像&#xff0c;省去挑选图像的麻烦事&#xff0c;同时也可以将模糊图像剔除掉&#xff0…

【Python学习-UI界面】PyQt5 小部件11-Dialog Button Box 确认与取消框

样式如下: 一个预配置的对话框&#xff0c;带有一个文本字段和两个按钮&#xff0c;OK和取消。在用户单击OK按钮或按下Enter键后&#xff0c;父窗口会在文本框中收集输入。 用户输入可以是数字、字符串或列表中的项。还会显示一个提示用户应该做什么的标签。 常用方法如下&…