【问题标题】:Example of state data persisting across runs of Spring Boot Server跨 Spring Boot Server 运行持久化的状态数据示例
【发布时间】:2021-02-21 21:26:10
【问题描述】:

我想在我的 Spring Boot 服务器启动和停止中保持一个可变状态。例如,一个整数表示服务器在每天递增一次的服务对象队列中的位置(参见下面的“nowServing”):

@RestController
public class ArticleController {

    @Autowired
    ArticleRepository articleRepo;

    // TODO - these two variables need to persist between runnings of the server.  Refactor to be set and get from the database.
    //the article with id '0' and '1' better be approved!
    private Integer nowServing = 0;          //where in the queue we are serving an article from at the moment
    LocalDate serveDate = LocalDate.now().minusDays(1);   //a date associated with the current article being served
    
    /**
     * When the date changes, find the next approved article in the queue, and set that as our serving point.
     * @return which primary key in our sorted table we're serving
     */
    private Integer nowServing() {
        if (!LocalDate.now().equals(serveDate)) {
            //time to start serving the next article
            serveDate = LocalDate.now();
            Boolean foundAnApprovedOne = false;
            for (nowServing++; ( (nowServing<articleRepo.count()) && (foundAnApprovedOne == false) ); nowServing++) {
                Optional<Article> article = articleRepo.findById(nowServing);
                if ( (article.isPresent()) && (article.get().getApprovalStatus()) ) {
                    foundAnApprovedOne = true;
                }
            }
            if (foundAnApprovedOne == false) {
                //There are no more approved articles left in the queue.  Restart from the beginning
                nowServing = 1;
            }
        }
        return nowServing;
    }

我搜索了如何保存状态信息,遇到了以下可能的帖子: JPA: Singleton Entity Hibernate/persistence and singleton pattern

我认为每个示例都只是展示整体的一部分,希望观看者知道如何将提供的内容与其他补充组件集成。我现在的 Spring 能力非常有限,我希望研究一个更全面(存储库、实体、控制器等)的简单示例,我可以适应和学习。最好,这个示例将远离 bean 并包含一个实体,以依靠我目前的优势。

【问题讨论】:

  • 您可以使用像 Redis 这样的简单内存键值数据库,我认为这会更有效。有一个 Spring Data Redis Spring Boot 启动器,使用起来非常简单。

标签: spring spring-boot


【解决方案1】:

我很欣赏 Yann39 指向 Redis 的指针,这可能是完成这项工作的一种更好的方式。然而,我有限的 Spring 经验再次妨碍了解读 Redis 文档。我已经从我知道的实体存储库控制器模型中构建了一些东西:

实体:

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class StateData {

    //This class helps keep track of server data across instances of the the server running
    //There's a trade-off in this implementation:  consolidated gateway in the code, for
    //a database table that is going to have multiple unused(null) fields per instance.
        
    public static final int NOW_SERVING = 0;    //used to track where we are in the article queue
    public static final int SERVE_DATE  = 1;    //used to track what date the currently served article is associated with
    
    @Id
    private Integer variableName;

    //While multiple types are listed, each instance of StateData only uses one.
    //Think of this as a list of possibilities
    private Integer intValue;
    private LocalDate dateValue;

    public StateData() {}

    //To differentiate the StateData instance by type of variable (String, Integer, etc.), different constructors are used.
    public StateData(Integer id, Integer value) {
        setVariableName(id);
        setIntValue(value);
    }

    public StateData(Integer id, LocalDate value) {
        setVariableName(id);
        setDateValue(value);
    }

    public String getVariableName() {
        switch (variableName.intValue()) {
            case NOW_SERVING:
                return "nowServing";
            case SERVE_DATE:
                return "serveDate";
        }
        return "unknown";
    }
    
    /*
     * Pass in one of the static variable values defined above, such as NOW_SERVING
     */
    public void setVariableName(Integer variableName) {
        this.variableName = variableName;
    }
    
    //It's up to the programmer to know which get is appropriate for a particular StateData.
    //Calling getIntValue() on a StateData representing LocalDate, for example, is a useless op that returns null 
    
    public void setIntValue(Integer value) {
        this.intValue = value;
    }

    public Integer getIntValue() {
        return intValue;
    }

    public void setDateValue(LocalDate value) {
        this.dateValue = value;
    }

    public LocalDate getDateValue() {
        return dateValue;
    }

}

存储库:

import org.springframework.data.repository.CrudRepository;

import com.lotterysim.server.model.StateData;

public interface StateDataRepository extends CrudRepository<StateData, Integer> {

}

控制器:

公共类 ArticleController {

@Autowired
ArticleRepository articleRepo;

@Autowired
StateDataRepository stateDataRepo;      //used to persist server values across runnings of the server

private Integer nowServing = null;       //where in the queue we are serving an article from at the moment

LocalDate serveDate = null;   //a date associated with the current article being served

/**
 * Write state data for nowServing to database for persistent storage across server runnings
 * @param value  where in the queue we are in article servings
 */
private void setNowServing(int value) {
    nowServing = value;
    StateData sd = new StateData(StateData.NOW_SERVING, value);
    stateDataRepo.save(sd);
}

/**
 * Write state data for serveDate to database for persistent storage across server runnings
 * @param value  what day our serving is associated with
 */
private void setServeDate(LocalDate value) {
    serveDate= value;
    StateData sd = new StateData(StateData.SERVE_DATE, value);
    stateDataRepo.save(sd);
}

/**
 * When the date changes, find the next approved article in the queue, and set that as our serving point.
 * @param override force the queue to advance, even if the day hasn't 
 * @return which primary key in our sorted table we're serving
 */
private Integer nowServing(boolean override) {
    if (nowServing == null) {       //load state from database
        Optional<StateData> sdPhantom = stateDataRepo.findById(StateData.NOW_SERVING);
        if (sdPhantom.isPresent()) {
            nowServing = sdPhantom.get().getIntValue();
        } else {
            setNowServing(0);       //default
        }
    }

    if(serveDate == null) {         //load state from database
        Optional<StateData> sdPhantom = stateDataRepo.findById(StateData.SERVE_DATE);
        if (sdPhantom.isPresent()) {
            serveDate = sdPhantom.get().getDateValue();
        } else {
            setServeDate(LocalDate.now().minusDays(1));     //default.  Will trip a re-assessment
        }
    }

将此视为伪代码,因为我尚未确认它按原样工作

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-29
    • 1970-01-01
    • 2016-02-17
    • 1970-01-01
    • 2017-08-10
    • 2016-06-12
    相关资源
    最近更新 更多