Maison  >  Article  >  Java  >  Comment utiliser Java pour interroger d'abord le cache, puis interroger la base de données

Comment utiliser Java pour interroger d'abord le cache, puis interroger la base de données

WBOY
WBOYavant
2023-04-29 09:55:061273parcourir

李子

Il est nécessaire d'interroger le produit en utilisant le nom du produit. Cela nécessite d'abord d'interroger le cache, et s'il est introuvable, accédez à la base de données pour l'interroger. ; après avoir interrogé la base de données, ajoutez-le au cache, puis lors de l'interrogation, continuez d'abord à interroger le cache.

Analyse d'idées

Vous pouvez rédiger un jugement conditionnel, le pseudo code est le suivant :

//先从缓存中查询
String goodsInfoStr = redis.get(goodsName);
if(StringUtils.isBlank(goodsInfoStr)){
	//如果缓存中查询为空,则去数据库中查询
	Goods goods = goodsMapper.queryByName(goodsName);
	//将查询到的数据存入缓存
	goodsName.set(goodsName,JSONObject.toJSONString(goods));
	//返回商品数据
	return goods;
}else{
	//将查询到的str转换为对象并返回
	return JSON.parseObject(goodsInfoStr, Goods.class);
}
# 🎜🎜#Above Cette chaîne de code peut également obtenir des effets de requête, et cela n'a pas l'air très compliqué. Cependant, cette chaîne de code n'est pas réutilisable et ne peut être utilisée que dans ce scénario. En supposant qu'il existe de nombreux besoins similaires à la requête de produit ci-dessus dans notre système, nous devons alors écrire un tel if(...)else{...} partout. En tant que programmeur, il est très inconfortable de ne pas pouvoir unifier des codes similaires ou répétés. Le code de ce scénario doit donc être optimisé.

不可复用的,只能用在这个场景。假设在我们的系统中还有很多类似上面商品查询的需求,那么我们需要到处写这样的if(...)else{...}。作为一个程序员,不能把类似的或者重复的代码统一起来是一件很难受的事情,所以需要对这种场景的代码进行优化。

上面这串代码的问题在于:入参不固定、返回值也不固定,如果仅仅是参数不固定,使用泛型即可。但最关键的是查询方法也是不固定的,比如查询商品和查询用户肯定不是一个查询方法吧。

所以如果我们可以把一个方法(即上面的各种查询方法)也能当做一个参数传入一个统一的判断方法就好了,类似于:

/**
 * 这个方法的作用是:先执行method1方法,如果method1查询或执行不成功,再执行method2方法
 */
public static<T> T selectCacheByTemplate(method1,method2)

想要实现上面的这种效果,就不得不提到Java8的新特性:函数式编程

原理介绍

在Java中有一个package:java.util.function ,里面全部是接口,并且都被@FunctionalInterface

Le problème avec le code ci-dessus est :

Les paramètres d'entrée ne sont pas corrigés, et la valeur de retour n'est pas corrigée non plus. Si seuls les paramètres ne sont pas corrigés, utilisez des génériques. . Mais le plus important est que la méthode de requête n'est pas fixe. Par exemple, interroger des produits et interroger des utilisateurs n'est certainement pas la même méthode de requête. Ce serait donc génial si nous pouvions passer une méthode (c'est-à-dire les différentes méthodes de requête ci-dessus) en tant que paramètre dans une méthode de jugement unifiée, similaire à :

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>SpringBoot-query</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>SpringBoot-query</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
#🎜 🎜#Si vous souhaitez obtenir l'effet ci-dessus, vous devez mentionner les nouvelles fonctionnalités de Java8 : Programmation fonctionnelle
  • Introduction au principe

    # 🎜🎜#Il y a un package en Java : java.util.function , qui contient toutes les interfaces, et elles sont toutes modifiées par l'annotation @FunctionalInterface.

  • Catégorie de fonction

  • Consommateur (Consommation) :

    Accepter les paramètres, Aucune valeur de retour Opérateur : accepte les paramètres et renvoie des valeurs du même type que les paramètres

  • #🎜🎜 #Predicate ): Accepte les paramètres et renvoie le type booléen

  • Fournisseur (supply): Aucun paramètre, valeur de retour #🎜 🎜 #

Je n'entrerai pas dans les détails Vous pouvez vous référer à : Résumé de la programmation fonctionnelle Java

Implémentation du code

#. 🎜🎜# Alors utilisons Java pour interroger élégamment d'abord le cache, puis la base de données !

Code du projet

Fichier de configuration

pom.xml

package com.example.springbootquery;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootQueryApplication {

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

}
#🎜 🎜#Structure du projet

Parmi eux, CacheService interroge les données du cache et GoodsService interroge les données de la base de données Comment utiliser Java pour interroger dabord le cache, puis interroger la base de données

SpringBootQueryApplication . java

package com.example.springbootquery.entity;
public class Goods {
    private String goodsName;
    private Integer goodsTotal;
    private Double price;
    public String getGoodsName() {
        return goodsName;
    }
    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }
    public Integer getGoodsTotal() {
        return goodsTotal;
    }
    public void setGoodsTotal(Integer goodsTotal) {
        this.goodsTotal = goodsTotal;
    }
    public Double getPrice() {
        return price;
    }
    public void setPrice(Double price) {
        this.price = price;
    }
    @Override
    public String toString() {
        return "Goods{" +
                "goodsName=&#39;" + goodsName + &#39;\&#39;&#39; +
                ", goodsTotal=&#39;" + goodsTotal + &#39;\&#39;&#39; +
                ", price=" + price +
                &#39;}&#39;;
    }
}

Goods.java
package com.example.springbootquery.function;

@FunctionalInterface
public interface CacheSelector<T> {
    T select() throws Exception;
}
CacheSelector.java
Interface fonctionnelle personnalisée :
#🎜🎜 #
package com.example.springbootquery.service;

import com.example.springbootquery.entity.Goods;
public interface CacheService {
    /**
     * 从缓存中获取商品
     *
     * @param goodsName 商品名称
     * @return goods
     */
    Goods getGoodsByName(String goodsName) throws Exception;
}

CacheService.java

package com.example.springbootquery.service.impl;

import com.alibaba.fastjson.JSON;
import com.example.springbootquery.entity.Goods;
import com.example.springbootquery.service.CacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

@Service("cacheService")
public class CacheServiceImpl implements CacheService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public Goods getGoodsByName(String goodsName) throws Exception {
        String s = redisTemplate.opsForValue().get(goodsName);
        return null == s ? null : JSON.parseObject(s, Goods.class);
    }
}
CacheServiceImpl.java

package com.example.springbootquery.service;
import com.example.springbootquery.entity.Goods;
public interface GoodsService {
    Goods getGoodsByName(String goodsName);
}
GoodsService.java
package com.example.springbootquery.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.example.springbootquery.entity.Goods;
import com.example.springbootquery.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class GoodsServiceImpl implements GoodsService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public Goods getGoodsByName(String goodsName) {
        Goods goods = new Goods();
        goods.setGoodsName("商品名1");
        goods.setGoodsTotal(20);
        goods.setPrice(30.0D);
        stringRedisTemplate.opsForValue().set(goodsName, JSONObject.toJSONString(goods));
        return goods;
    }
}
GoodsServiceImpl.java#🎜🎜 ## 🎜 🎜#
Je ne vais pas me connecter à la base de données ici, mais simuler un retour
package com.example.springbootquery.util;
import com.example.springbootquery.function.CacheSelector;
import java.util.function.Supplier;
public class BaseUtil {
    /**
     * 缓存查询模板
     *
     * @param cacheSelector    查询缓存的方法
     * @param databaseSelector 数据库查询方法
     * @return T
     */
    public static <T> T selectCacheByTemplate(CacheSelector<T> cacheSelector, Supplier<T> databaseSelector) {
        try {
            System.out.println("query data from redis ······");
            // 先查 Redis缓存
            T t = cacheSelector.select();
            if (t == null) {
                // 没有记录再查询数据库
                System.err.println("redis 中没有查询到");
                System.out.println("query data from database ······");
                return databaseSelector.get();
            } else {
                return t;
            }
        } catch (Exception e) {
            // 缓存查询出错,则去数据库查询
            e.printStackTrace();
            System.err.println("redis 查询出错");
            System.out.println("query data from database ······");
            return databaseSelector.get();
        }
    }
}
BaseUtil.java (core class)
#🎜🎜 # Parce que je ne me soucie pas des paramètres et que j'ai seulement besoin d'une valeur de retour, Supplier est utilisé ici.

package com.example.springbootquery;

import com.example.springbootquery.entity.Goods;
import com.example.springbootquery.service.CacheService;
import com.example.springbootquery.service.GoodsService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static com.example.springbootquery.util.BaseUtil.selectCacheByTemplate;
@SpringBootTest
class SpringBootQueryApplicationTests {
    @Autowired
    private CacheService cacheService;
    @Autowired
    private GoodsService userService;
    @Test
    void contextLoads() throws Exception {
        Goods user = selectCacheByTemplate(
                () -> cacheService.getGoodsByName("商品名1"),
                () -> userService.getGoodsByName("商品名1")
        );
        System.out.println(user);
    }
}
Usage
rrreee
Première requête à partir des données

Requête à partir du cache pour la deuxième fois

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer