Heim  >  Artikel  >  Java  >  So verwenden Sie Java, um zuerst den Cache und dann die Datenbank abzufragen

So verwenden Sie Java, um zuerst den Cache und dann die Datenbank abzufragen

WBOY
WBOYnach vorne
2023-04-29 09:55:061241Durchsuche

Chestnut

Es besteht die Anforderung, das Produkt anhand des Produktnamens abzufragen. Dazu muss zuerst der Cache abgefragt werden. Wenn es nicht gefunden werden kann, gehen Sie zur Abfrage aus der Datenbank und fügen Sie es dem Cache hinzu , und fragen Sie bei einer erneuten Abfrage zuerst den Cache ab.

Denken Sie an die Analyse

Sie können ein bedingtes Urteil schreiben:

//先从缓存中查询
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);
}

Die obige Codefolge sieht auch nicht sehr kompliziert aus, aber diese Codefolge ist es und kann nicht wiederverwendet werden. kann nur in diesem Szenario verwendet werden. Unter der Annahme, dass es in unserem System viele ähnliche Anforderungen wie die obige Produktabfrage gibt, müssen wir überall einen solchen if(...)else{...} schreiben. Als Programmierer ist es sehr unangenehm, ähnliche oder wiederholte Codes nicht vereinheitlichen zu können. Daher muss der Code für dieses Szenario optimiert werden. 不可复用的,只能用在这个场景。假设在我们的系统中还有很多类似上面商品查询的需求,那么我们需要到处写这样的if(...)else{...}。作为一个程序员,不能把类似的或者重复的代码统一起来是一件很难受的事情,所以需要对这种场景的代码进行优化。

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

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

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

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

原理介绍

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

Das Problem mit dem obigen Code ist: Die Eingabeparameter sind nicht festgelegt, und der Rückgabewert ist auch nicht festgelegt. Wenn nur die Parameter nicht festgelegt sind, verwenden Sie Generics. Das Wichtigste ist jedoch, dass die Abfragemethode nicht festgelegt ist. Beispielsweise sind die Abfrage von Produkten und die Abfrage von Benutzern definitiv nicht dieselbe Abfragemethode.

Es wäre also großartig, wenn wir eine Methode (d. h. die verschiedenen oben genannten Abfragemethoden) als Parameter an eine einheitliche Beurteilungsmethode übergeben könnten, ähnlich wie:
    <?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>
  • Wenn Sie den oben genannten Effekt erzielen möchten, muss ich nur erwähnen Die neuen Funktionen von Java8: Funktionale Programmierung

    Einführung in das Prinzip

  • Es gibt ein Paket in Java:
  • java.util.function , das alle Schnittstellen ist und ist alle durch die Annotation @FunctionalInterface geändert.

    Funktionsklassifizierung

  • Verbraucher (Verbrauch):

    Akzeptiert Parameter, kein Rückgabewert
  • Funktion (Funktion):

    Akzeptiert Parameter, hat Rückgabewert
  • Operator (Operator): Akzeptiert Parameter und gibt Werte desselben Typs wie die Parameter zurück

Prädikat (Behauptung):

Akzeptiert Parameter und gibt booleschen Typ zurück

Supplier (Versorgung):

Keine Parameter, Rückgabewert

Ich werde nicht auf Einzelheiten eingehen, Sie können sich auf Folgendes beziehen: Java Functional Programming Overview

Code-Implementierung

Dann verwenden wir die elegante Implementierung von Java, um zuerst den Cache und dann die Datenbank abzufragen! So verwenden Sie Java, um zuerst den Cache und dann die Datenbank abzufragen

Projektcode

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

}

Projektstruktur

Wo CacheService Daten aus dem Cache abfragt, fragt GoodsService Daten aus der Datenbank ab
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;;
    }
}
Ware. java
package com.example.springbootquery.function;

@FunctionalInterface
public interface CacheSelector<T> {
    T select() throws Exception;
}
CacheSelector.java

Benutzerdefinierte funktionale Schnittstelle:
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

Ich werde es nicht tun, nachdem ich eine Verbindung zur Datenbank hergestellt habe , simulieren Sie eine Rückgabe So verwenden Sie Java, um zuerst den Cache und dann die Datenbank abzufragen

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 (Kernklasse)

So verwenden Sie Java, um zuerst den Cache und dann die Datenbank abzufragenDa mir die Parameter egal sind, benötige ich nur einen Rückgabewert, deshalb verwende ich hier Supplier.

🎜
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);
    }
}
🎜Verwendung🎜rrreee🎜Das erste Mal für die Abfrage aus den Daten🎜🎜🎜🎜🎜Das zweite Mal für die Abfrage aus dem Cache🎜🎜🎜🎜

Das obige ist der detaillierte Inhalt vonSo verwenden Sie Java, um zuerst den Cache und dann die Datenbank abzufragen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen