Heim > Java > javaLernprogramm > Analyse von Java Redis-Nutzungsszenarien

Analyse von Java Redis-Nutzungsszenarien

王林
Freigeben: 2023-05-09 13:07:17
nach vorne
968 Leute haben es durchsucht

1. Als Cache

1.1 Warum

Daten werden im Speicher gespeichert und die Datenabfragegeschwindigkeit ist hoch. Der Datenbankdruck kann geteilt werden.

Analyse von Java Redis-Nutzungsszenarien

1.2 Welche Art von Daten eignen sich zum Zwischenspeichern?

Die Abfragehäufigkeit ist relativ hoch, die Änderungshäufigkeit jedoch relativ niedrig.

Daten mit niedrigem Sicherheitsfaktor

1.3 Redis als Cache verwenden

1.3.1 Nicht verwendete Konfigurationsklasse

Hinweis an Serialisieren Sie die Entitätsklasse:

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "tb_dept")
public class Dept implements Serializable {
    @TableId(value = "id",type = IdType.AUTO)
    private Integer id;
    private String name;
    private String realname;
}
Nach dem Login kopieren

Entsprechende Abhängigkeit:

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--连接数据源-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--mp的依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
Nach dem Login kopieren

Entsprechender Code der Controller-Schicht:

@RestController
@RequestMapping("order")
public class DeptController {
    @Resource
    private DeptService deptService;
    @GetMapping("getById/{id}")
    //order/getById/1
    //{}可以放多个,由下面的传参函数对应
    //@PathVariable:获取请求映射中{}的值
    public Dept getById(@PathVariable Integer id){
        return deptService.findById(id);
    }
    @GetMapping("deleteById/{id}")
    public String deleteById(@PathVariable Integer id){
        int i = deptService.deleteById(id);
        return i>0?"删除成功":"删除失败";
    }
    @GetMapping("insert")
    public Dept insert(Dept dept){
        Dept insert = deptService.insert(dept);
        return insert;
    }
    @GetMapping("update")
    public Dept update(Dept dept){
        Dept update = deptService.update(dept);
        return update;
    }
}
Nach dem Login kopieren

Entsprechender Code der Service-Schicht: #🎜 🎜#

@Service
public class DeptService {
    @Resource
    private DeptMapper deptMapper;
    //当存储的value类型为对象类型使用redisTemplate
    //存储的value类型为字符串。StringRedisTemplate
    @Autowired
    private RedisTemplate redisTemplate;
    //业务代码
    public Dept findById(Integer id){
        ValueOperations forValue = redisTemplate.opsForValue();
        //查询缓存
        Object o = forValue.get("dept::" + id);
        //缓存命中
        if(o!=null){
            return (Dept) o;
        }
        Dept dept = deptMapper.selectById(id);
        if(dept!=null){
            //存入缓存中
            forValue.set("dept::"+id,dept,24, TimeUnit.HOURS);
        }
        return dept;
    }
    public int deleteById(Integer id){
        redisTemplate.delete("dept::"+id);
        int i = deptMapper.deleteById(id);
        return i;
    }
    public Dept insert(Dept dept){
        int insert = deptMapper.insert(dept);
        return dept;
    }
    public Dept update(Dept dept){
        redisTemplate.delete("dept::"+dept.getId());
        int i = deptMapper.updateById(dept);
        return dept;
    }
}
Nach dem Login kopieren

Konfigurationsquelle:

# Konfigurationsdatenquelle

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver# 🎜🎜# spring.datasource.url=jdbc:mysql://localhost:3306/mydb?serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root#🎜 🎜## sqllog
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#Connect redis
spring.redis.host=192.168.22 *.1* *
spring.redis.port=6379


Angesehener Cache: Der erste Teil des Codes ist die gleiche @before-Benachrichtigung, und der zweite Teil des Codes ist ebenfalls der Gleiche Beitragsbenachrichtigung. Wir können AOP verwenden, um Caching-Code und Geschäftscode zu trennen.

Frühlingsrahmen sollte auch daran denken können. --Dies kann mithilfe von Anmerkungen erfolgen. Analysieren Sie die Anmerkung.

1.3.2 Verwenden Sie die Konfigurationsklasse

(1) Fügen Sie die Cache-Konfigurationsklasse hinzu
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置序列化(解决乱码的问题),过期时间600秒
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600)) //缓存过期10分钟 ---- 业务需求。
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))//设置key的序列化方式
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) //设置value的序列化
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
Nach dem Login kopieren
(2) Verwenden Sie die Anmerkung zum Aktivieren des Caches #🎜 🎜 #

(3) Verwendungsanmerkungen

//业务代码
    //使用查询注解:cacheNames表示缓存的名称 key:唯一标志---dept::key
    //先从缓存中查看key为(cacheNames::key)是否存在,如果存在则不会执行方法体,如果不存在则执行方法体并把方法的返回值存入缓存中
    @Cacheable(cacheNames = {"dept"},key="#id")
    public Dept findById(Integer id){
        Dept dept = deptMapper.selectById(id);
        return dept;
    }
//先删除缓存在执行方法体。
    @CacheEvict(cacheNames = {"dept"},key = "#id")
    public int deleteById(Integer id){
        int row = deptMapper.deleteById(id);
        return row;
    }
    //这个注释可以确保方法被执行,同时方法的返回值也被记录到缓存中,实现缓存与数据库的同步更新。
    @CachePut(cacheNames = "dept",key="#dept.id")
    public Dept update(Dept dept){
        int insert = deptMapper.updateById(dept);
        return dept;
    }
Nach dem Login kopieren
Analyse von Java Redis-Nutzungsszenarien2. Verteilte Sperre

Verwenden Sie zum Testen Stresstest-Tools Hohe Parallelität bringt Thread-Sicherheitsprobleme mit sich

2.1 Verwendung von Stresstest-Tools

Analyse von Java Redis-Nutzungsszenarien# 🎜 🎜#

Analyse von Java Redis-Nutzungsszenarien

Analyse von Java Redis-NutzungsszenarienInterne Konfiguration:

Analyse von Java Redis-Nutzungsszenarien

# 2.2 Inventarelemente . 2 Dao-Schicht

@RestController
@RequestMapping("bucket")
public class BucketController {
    @Autowired
    private BucketService bucketService;
    @GetMapping("update/{productId}")
    public String  testUpdate(@PathVariable Integer productId){
        String s = bucketService.updateById(productId);
        return s;
    }
}
Nach dem Login kopieren

2.2.3 EntitätsschichtAnalyse von Java Redis-Nutzungsszenarien

//此处写就不需要在启动类使用注解
@Mapper
public interface BucketMapper extends BaseMapper<Bucket> {
    public Integer updateBucketById(Integer productId);
}
Nach dem Login kopieren

2.2.4 Serviceschicht

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Bucket {
    @TableId(value = "productId",type = IdType.AUTO)
    private Integer productId;
    private Integer num;
}
Nach dem Login kopieren
Analyse von Java Redis-Nutzungsszenarien2.2.5 Mapper

@Service
public class BucketService {
    @Resource
    private BucketMapper bucketMapper;
    public String updateById(Integer productId){
        //查看该商品的库存数量
        Bucket bucket = bucketMapper.selectById(productId);
        if(bucket.getNum()>0){
            //修改库存每次减1
            Integer integer = bucketMapper.updateBucketById(productId);
            System.out.println("扣减成功!剩余库存数:"+(bucket.getNum()-1));
            return "success";
        }else {
            System.out.println("扣减失败!库存数不足");
            return "fail";
        }
    }
}
Nach dem Login kopieren
# 🎜🎜#2.2.6 Abhängigkeit

<?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.qy151wd.dao.BucketMapper">
    <update id="updateBucketById" parameterType="int">
        update bucket set num=num-1 where productId=#{productId}
    </update>
</mapper>
Nach dem Login kopieren
Analyse von Java Redis-Nutzungsszenarien2.2.7 Testergebnis

Wir sehen, dass das gleiche Inventar n-mal verwendet wird . Und der Bestand in der Datenbank ist negativ. Verursacht durch Thread-Sicherheitsprobleme.
2.3 Lösung
2.3.1 Synchronisiert verwenden oder Sperre sperren
Die entsprechende Serviceschicht wird in
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--连接数据源-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--mp的依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
Nach dem Login kopieren
geändert Wenn ein Projektcluster erstellt wird, ist diese Sperre ungültig.

2.3.2 Verwendung von redisTemplateAnalyse von Java Redis-Nutzungsszenarien

(1) Verwenden Sie die Idee, um ein Clusterprojekt zu öffnen

#🎜🎜 ## 🎜🎜#

(2) Verwendung von nginx

(3) Testergebnisse

#🎜🎜 ## 🎜🎜#

Es wurde festgestellt, dass es wiederholte Zahlen und negative Bestände gibt. Analyse von Java Redis-Nutzungsszenarien

(4) Lösung

Service entsprechende Codeänderung Analyse von Java Redis-Nutzungsszenarien

@Service
public class BucketService {
    @Resource
    private BucketMapper bucketMapper;
    public String updateById(Integer productId){
        //加自动锁
        synchronized (this){
            //查看该商品的库存数量
            Bucket bucket = bucketMapper.selectById(productId);
            if(bucket.getNum()>0){
                //修改库存每次减1
                Integer integer = bucketMapper.updateBucketById(productId);
                System.out.println("扣减成功!剩余库存数:"+(bucket.getNum()-1));
                return "success";
            }else {
                System.out.println("扣减失败!库存数不足");
                return "fail";
            }
        }
    }
}
Nach dem Login kopieren
Achten Sie hier auf den Druck Die Messgeschwindigkeit ist nicht einfach zu schnell (es wird empfohlen, 5 Sekunden und 100 Threads zu verwenden)

Nach dem Druckmesstest ist das Ergebnis:

Analyse von Java Redis-Nutzungsszenarien#🎜🎜 #

Das obige ist der detaillierte Inhalt vonAnalyse von Java Redis-Nutzungsszenarien. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:yisu.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage