Hej!
Próbuję ogarnąć CompletableFuture
, ale nie mogę zrozumieć jednego aspektu, coś czuję, że nie rozumiem wykonania asynchronicznego.
Mam pewną bazę (in-memory), którą zapełniam przy startupie pewnymi danymi, przykładowo:
CREATE TABLE USERS (
ID INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(255) NOT NULL,
PASSWORD VARCHAR(255) NOT NULL,
AGE INT,
ADMIN BOOLEAN
);
INSERT INTO USERS (ID, NAME, PASSWORD, AGE, ADMIN) values (1, 'Armin', 'zwdTJIb', 70, false);
i pomyślałem, że zrobię to asynchronicznie, ponieważ web server też potrzebuje sekundy. Chciałem, aby te dwa elementy wykonywały się niezależnie od siebie, przyspieszyło by mi to procedurę uruchomienia wszystkiego (nie, żeby trwała długo czy coś, ale pobawić się też można).
Mam klasę initialize:
package com.burdzi0.rest;
import com.burdzi0.rest.model.User;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
public class Initialize {
private EntityManagerFactory factory;
public Initialize(EntityManagerFactory factory) {
this.factory = factory;
}
protected void start() {
EntityManager manager = factory.createEntityManager();
manager.getTransaction().begin();
Query q = manager.createNativeQuery(getSQLFileContent());
q.executeUpdate();
manager.persist(new User("XYZ", "PASSWORD", true, 999));
manager.persist(new User("ABC", "PASSWORD1", true, 998));
manager.getTransaction().commit();
manager.close();
}
private String getSQLFileContent() {
ClassLoader classLoader = getClass().getClassLoader();
String sqlFileName = "sql/start.sql";
Optional<Path> filePath = Optional.ofNullable(Paths.get(classLoader.getResource(sqlFileName).getPath()));
StringBuilder stringBuilder = new StringBuilder();
Path path = filePath.orElseThrow(IllegalStateException::new);
try {
Files.lines(path).forEach(stringBuilder::append);
} catch (IOException e) {
throw new IllegalStateException("Couldn't find sql startup file");
}
if (stringBuilder.toString().equals(""))
throw new IllegalStateException("Couldn't load data from sql startup file");
return stringBuilder.toString();
}
}
Jak widać wywołuję kod sql z pliku i dodaję ręcznie dwa rekordy. Wywołuję kod następująco:
CompletableFuture.runAsync(() -> new Initialize(entityManagerFactory).start()).get();
ale kod ewidentnie nie zmienił swojego wykonania. Ciągle jest to zwykły kod synchroniczny - czas wystartowania servera i bazy oraz output (kolejność logów) są takie same.
Czytałem trochę, próbowałem się bawić tym CompletableFuture
, ale czego bym nie zrobił ciągle jest to kod synchroniczny. Przykład:
CompletableFuture.runAsync(() -> {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).get();
IntStream.range(0,1000).forEach(System.out::println);
najpierw zaczeka 10 sekund, a następnie dopiero wypisze pętlę. Po co w takim razie stworzono ten CompletableFuture
, skoro nic kompletnie nie zmienia? Gdzie popełniam błąd w rozumieniu tego tworu?