Stała w serwisie ale brana z bazy

0

Hej

Chciałbym aby w moim OrderService była zmienna określająca czas w jakim można wycofać zamówienie, ale musiałby być on brany z bazy. Na razie wystarczy, że zostanie pobrany raz przy starcie aplikacji - jak to zrobić? Dodać repo do parametrów i ustawić zmienną w konstruktorze?


@Service
class OrderService {

    private final OrderRepository repository;
    private long timeToWithdrawMillis = //jak ustawić?;

    OrderService(final OrderRepository repository) {
        this.repository = repository;
    }

    // jakaś metoda
    boolean cancelOrder(final long orderId) {
      Order order = repository.getById(id);

      if (LocalDateTime.now().isBefore(order.getDate().plus(timeToWithdrawMillis, ChronoUnit.MILLIS))) {
        // wycofaj zamówienie
      }

      // dalej kod
    }
}

1

A nie możesz przy składaniu zamówienia dodać ten czas do bazy czyli
LocalDateTime.now().plusHours()
a przy anulowaniu sprawdzić czy jest jest jeszcze przed .

0

Kiedyś się do takich rzeczy używało Guava Cache

2

Założmy, że zamówienie można anulować np. 15 minut po jego złożeniu. Tę wartość możesz sobie trzymać w jakimś configu albo nawet w tym serwisie albo w encji a w bazie trzymasz tylko datę złożenia zamówienia i potem przy anulowaniu sprawdzasz czy obecny czas jest mniejszy niż data złożenia zamówienia + te 15 minut i tyle. Wydaje mi się to dość proste albo czegoś nie widzę.

2

Pytanie, co masz i jak to chcesz zrobić. Na potrzeby bycia fajnym wymyśliłem, że mamy ConfigRepository z metodą getTimeToWithdrawMillis. Oczywiście repozytorium nie musi pobierać danych z bazy danych, może je pobierać z jakiegoś YAMLa - sam preferuję właśnie tego typu configi trzymać w plikach konfiguracyjnych.

0

Nie lepiej z propertisów aplikacyjnych?
Zmieniasz wartość w konfiguracji i restartujesz aplikację (są narzędzia pozwalające przeładowanie propertisów bez restartu).

0

Tworzysz repozytorium, wywołujesz metodę pobierającą, którą przepychasz kontruktorem do OrderService. Zgaduje, że pytanie wynika z tego, że używasz Springa i zrobienie czegoś nietrywialnego w czasie budowania drzewa zależności aplikacji wywołuje szok kulturowy

1

Na pytanie "Jak pobrać longa z bazy w serwisie Springowym" już ci odpowiedzieli, więc:

dlaczego ten czas "musiałby być on brany z bazy"?

Przydałoby się więcej kontekstu:

  • jak często ten czas w jakim można wycofać zamówienie będzie się zmieniać, jeśli w ogóle?
  • dlaczego on będzie się zmieniać?
  • czy będzie on wyliczany dynamicznie na podstawie innych wartości, np. inny dla innych rodzajów zamówień, dla klientów VIP, itp. itd.?

Ludzie często przychodzą na forum z Problemem XY, dlatego mam wątpliwości, że faktycznie potrzebujesz to brać z bazy

1
KamilAdam napisał(a):

Kiedyś się do takich rzeczy używało Guava Cache

RequiredNickname napisał(a):

Nie lepiej z propertisów aplikacyjnych?
Zmieniasz wartość w konfiguracji i restartujesz aplikację (są narzędzia pozwalające przeładowanie propertisów bez restartu).

(Chyba pisałem, ale może telefon mnie powstrztymał przed wysłaniem)
jest spora grupa bibliotek "do konfiguracji", zarówno niezależne od środowiska, jak i chyba moduł w Springu (ach springowcy!), i w Jakarcie EE na pewno

Wiele jest fajnymi, niewielkimi projektami. Np ma przewidziane powiadomienie o zmianach itd
Zwykle "multimedialne" (z 3ch - 7 źródeł), w tym łykające propertisy

0

Używasz springa, więc to nie jest aż tak dużo pracy. Jeżeli chcesz polecieć „na grubo”, to jest Spring Cloud Config, czyli stawiasz sobie serwer, który będzie ci serwował konfigurację jako endpoint. W docelowej aplikacji konfigurujesz sobie źródło na tym serwerze i wio. ALE to jest na prawdę na grubo.

Wersja prostsza, acz nie aż tak elegancka, to implementacja EnvironmentPostProcessor, w której dociągasz odpowiednie wartości:

public class ReadDbPropertiesPostProcessor implements EnvironmentPostProcessor {

    private static final String PROPERTY_SOURCE_NAME = "databaseProperties";
    
    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        Map<String, Object> propertySource = new HashMap<>();

        try {
            DataSource ds = DataSourceBuilder
                    .create()
                    .username(USERNAME) // 
                    .password(PASSWORD) // 
                    .url(DATASOURCE-URL)// 
                    .driverClassName(DRIVER) // to musisz wyciągnąć z environment
                    .build();

            PreparedStatement preparedStatement = ds.getConnection().prepareStatement("SELECT name, value FROM propertyConfig WHERE service = ?");
            preparedStatement.setString(1, APP_NAME);
            
            ResultSet rs = preparedStatement.executeQuery();

            while (rs.next()) {
                String propName = rs.getString("name");
                propertySource.put(propName, rs.getString("value"));
            }

            environment.getPropertySources().addFirst(new MapPropertySource(PROPERTY_SOURCE_NAME, propertySource));
        
        } catch (Exception e) {
            throw new RuntimeException("Error fetching properties from db");
        }
    }
}

I następnie w musisz stworzyć plik src/main/resources/META-INF/spring.factories i dodać w nim:

org.springframework.boot.env.EnvironmentPostProcessor=com.your.package.ReadDbPropertiesPostProcessor

To wszystko.

0
  1. Po pierwsze - nazywajmy rzeczy po imieniu. To co chcesz zrobić to nie jest "wczytanie stałej z bazy", tylko tak na prawdę chcesz cach'ować pierwsze wczytanie danej z bazy.
  2. Po drugie, pomysł że ta wartość ma być brana "tylko raz", to jest dosyć niski szczegół implementacyjny. Ja bym na Twoim miejscu wczytywał to za każdym razem jak ktoś próbuje wycofać zamówienie.
  3. Uruchom aplikację, i spróbuj wycofać zamówienie, zobacz czy performance aplikacji jest zadowalający, ewentualnie odpal profiler. Jeśli jest spoko, to wszelki sposoby cache'owania tego pierwszego wczytania są mikrooptymalizacją.

1 użytkowników online, w tym zalogowanych: 0, gości: 1