Alternativa k Hibernate

anonym

Re:Alternativa k Hibernate
« Odpověď #15 kdy: 20. 07. 2018, 17:52:06 »
Hoši já nevím, je to složité a proto mi přijde naprd to ještě zesložiťovat Hibernatem. Vezměte si třeba tu Cache, ten Hibernate si to nějak cachuje, ale jak? A když nevíte jak, tak jak můžete vědět, že zachováte 100% serializovatelnost transakcí? A když to na 100% nevíte, protože do toho Hibernate nevidíte, tak jak to můžete používat? Já bych se na to nejraději úplně vysral a použil něco jako je MyBatis. A nemusím nic řešit. Nakonec, když mám pořádnou DB, tak si tam stejně dám Liquibase.

Hibernate Caching je 1) transakcni 2) zdokumentovany 3) na serializovatelnost transakci nema vliv (a pokud jo, tak jsi to mel stejne blbe i predtim - klasicky priklad s nekorektne pouzitym READ COMMITTED).

Nic proti MyBatis, je fajn, klidne ho pouzivej, ale tohle mi prijde jako zbytecne (a neopravnene) plivani spiny na Hibernate

Caching u Hibernate klidne muze byt transakcni, ale ne vuci jine nezavisle connection do Databaze. Ta Service muze byt ledasco, muze to byt nejaka periodicky poustena ulozena procedura, muze to byt trigger, muze to byt nejaky programator ktery zrovna opravuje databazi manualne. Kdyz pouzivas Cache, automaticky porusujes Serializable na urovni databaze.


BoneFlute

  • *****
  • 1 983
    • Zobrazit profil
Re:Alternativa k Hibernate
« Odpověď #16 kdy: 20. 07. 2018, 19:08:07 »
Nakonec, když mám pořádnou DB, tak si tam stejně dám Liquibase.
Ale Liquibase nijak nesouvisí ani s ORM, ani s kešováním, ne? Liquibase je na verzování změn db.

kraxna

Re:Alternativa k Hibernate
« Odpověď #17 kdy: 20. 07. 2018, 19:16:53 »
Caching u Hibernate klidne muze byt transakcni, ale ne vuci jine nezavisle connection do Databaze. Ta Service muze byt ledasco, muze to byt nejaka periodicky poustena ulozena procedura, muze to byt trigger, muze to byt nejaky programator ktery zrovna opravuje databazi manualne. Kdyz pouzivas Cache, automaticky porusujes Serializable na urovni databaze.

Logicky pokud je neco NEZAVISLA connection do databaze, tak ma logicky NEZAVISLE transakce. Hibernate samozrejme tyhle veci resi pomoci XA transaction, pokud mas sdilenou transakci pres vice connection (do ruznych db), tak se synchronizuje pres XA.

Ale pokud tvuj argument znel,ze kdyz pouzijes cache, tak ze se ti rozbije v pripade, ze nekdo neco zmeni a neinvaliduje cache, tak vznika rozpor, tak to je samozrejme pravda, ale v takovem pripade nemuzes pouzivat vubec zadnou cache :-D

anonym

Re:Alternativa k Hibernate
« Odpověď #18 kdy: 20. 07. 2018, 19:21:08 »
Nakonec, když mám pořádnou DB, tak si tam stejně dám Liquibase.
Ale Liquibase nijak nesouvisí ani s ORM, ani s kešováním, ne? Liquibase je na verzování změn db.

Ale souvisí s tím, jakým způsobem se bude definovat databáze, ne modelovýma třídama jako u hibernate, ale sqlkem.

Franta <xkucf03/>

Re:Alternativa k Hibernate
« Odpověď #19 kdy: 20. 07. 2018, 22:26:28 »
Pro inserty osobne pouzivam stored procedury,  mam pak navic jistotu, ze nikdo  neudela nic, co nechcu, sam si ridim transakce.

Jak zajišťují uložené procedury, že "nikdo  neudela nic, co nechcu"? Jaký mají uložené procedury vliv na transakce?

Samy o sobě nijak, ale obvykle se používají v souvislosti s tím, že máš v DB víc uživatelů, a ten, pod kterým tam chodí aplikace má jen omezená práva, není vlastníkem objektů a nemůže dělat INSERT, UPDATE atd. a může jen volat ty procedury + SELECTy na určitých tabulkách.

Co se týče transakcí, ty bych do procedur většinou nedával a řešil je vně – tak, aby si transakci mohl řídit ten, kdo to volá a nebylo to zadrátované v proceduře. Výjimkou je logování, které se dělá v autonomní transakci (zalogováno chci mít vše, i když se na konci udělá ROLLBACK a/nebo vyletí nějaká výjimka) a některé speciální případy.


anonym

Re:Alternativa k Hibernate
« Odpověď #20 kdy: 20. 07. 2018, 22:55:34 »
Pro inserty osobne pouzivam stored procedury,  mam pak navic jistotu, ze nikdo  neudela nic, co nechcu, sam si ridim transakce.

Jak zajišťují uložené procedury, že "nikdo  neudela nic, co nechcu"? Jaký mají uložené procedury vliv na transakce?

Samy o sobě nijak, ale obvykle se používají v souvislosti s tím, že máš v DB víc uživatelů, a ten, pod kterým tam chodí aplikace má jen omezená práva, není vlastníkem objektů a nemůže dělat INSERT, UPDATE atd. a může jen volat ty procedury + SELECTy na určitých tabulkách.

Co se týče transakcí, ty bych do procedur většinou nedával a řešil je vně – tak, aby si transakci mohl řídit ten, kdo to volá a nebylo to zadrátované v proceduře. Výjimkou je logování, které se dělá v autonomní transakci (zalogováno chci mít vše, i když se na konci udělá ROLLBACK a/nebo vyletí nějaká výjimka) a některé speciální případy.

Čili v podstatě uděláš to, co musí být uděláno, a to na úrovni databáze - tzn. k databazi se pristupuje jen a pouze pres nějáký centrální program. V SOA když je databáze, do které pčistupují různé Service, tak to rovněž nemůžou dělat napřímo - prostě to nelze kvůli zamykání a bordelu - ale přistupují tam přes centrální service.

Procedury v DB budou OK pro něco malého, ale složitější business logiku nějaké banky bych si v tom neuměl představit psát, to je nanic, a lepší je to dát do centrální Java service. A ještě lepší je, nechat každou Service aby měla vlastní DB a žádnou centrální "DB která vládne všem" nedělat. Je to proto, že v té centrální Service je zákonitě bordel jako prase, protože do ní všechny týmy zapisují. Takhle má každý tým svůj vlastní chlíveček za který si odpovídá sám.

Franta <xkucf03/>

Re:Alternativa k Hibernate
« Odpověď #21 kdy: 21. 07. 2018, 00:32:50 »
Procedury v DB budou OK pro něco malého, ale složitější business logiku nějaké banky bych si v tom neuměl představit psát, to je nanic, a lepší je to dát do centrální Java service.

Celkem vtipné, protože tohle je běžná praxe řady systémů. Neříkám, že je to optimální (nový systém bych taky psal primárně v té Javě), ale rozhodně to není nic nepředstavitelného a v praxi to (byť s nějakými problémy) funguje. Je třeba brát v úvahu, v jaké době ty systémy vznikaly – dnes se běžně používají systémy, jejichž návrh je deset a víc let starý. Někdy je to myšlenkově nebo i reálně staré dvacet let. Nakonec můžeš být rád, že to není psané v COBOLu :-)

L.

Re:Alternativa k Hibernate
« Odpověď #22 kdy: 21. 07. 2018, 17:01:27 »
Procedury v DB budou OK pro něco malého, ale složitější business logiku nějaké banky bych si v tom neuměl představit psát, to je nanic, a lepší je to dát do centrální Java service.

Celkem vtipné, protože tohle je běžná praxe řady systémů. Neříkám, že je to optimální (nový systém bych taky psal primárně v té Javě), ale rozhodně to není nic nepředstavitelného a v praxi to (byť s nějakými problémy) funguje. Je třeba brát v úvahu, v jaké době ty systémy vznikaly – dnes se běžně používají systémy, jejichž návrh je deset a víc let starý. Někdy je to myšlenkově nebo i reálně staré dvacet let. Nakonec můžeš být rád, že to není psané v COBOLu :-)

Jojo, taky jeden takový systém znám.

anonym

Re:Alternativa k Hibernate
« Odpověď #23 kdy: 28. 07. 2018, 12:16:37 »
Zkoušel jsem si jak by to vypadalo s JDBC a nepřijde mi to vůbec špatné:



Kód: [Vybrat]
public class DbUtil {

    public static <T extends ResultSetModel> List<T> resultSet(T model, ResultSet rs) throws SQLException, IllegalAccessException, InstantiationException {
        List<T> ret = new ArrayList<>();
        while(rs.next()) {
            Object[] rowArr = getRowAsArray(rs);
            model.setFromRow(rowArr);
            ret.add(model);
        }
        return ret;
    }

    public static Object[] getRowAsArray(ResultSet rs) throws SQLException {
        int colCnt = rs.getMetaData().getColumnCount();
        Object[] ret = new Object[colCnt];
        for(int i = 0; i < colCnt; i++) {
            ret[i] = rs.getObject(i+1);
        }
        return ret;
    }


    public static ResultSet executeQuery(String sql, ConnStm conn) throws InterruptedException, SQLException {
        PreparedStatement st = null;
        ResultSet rs = null;
        try {
            st = conn.getPrepStat(sql);
            rs = st.executeQuery();
        } catch (SQLException e) {
            throw e;
        }

        return rs;
    }

    public static <T extends ResultSetModel> List<T> executeQuery(String sql, T model, ConnStm conn) throws SQLException, InterruptedException, InstantiationException, IllegalAccessException {
        return resultSet(model, executeQuery(sql, conn) );
    }
}


Kód: [Vybrat]
public interface ResultSetModel {
    public void setFromRow(Object[] row);
}

@Data
@ToString
public class Timeline implements ResultSetModel {
    private Timestamp measured_timestamp;
    private String keyword_name_fid;
    private Integer amount;
    private String special;

    @Override
    public void setFromRow(Object[] row) {
        int i = 0;
        measured_timestamp = (Timestamp) row[i++];
        keyword_name_fid = (String) row[i++];
        amount = (Integer) row[i++];
        special = (String) row[i++];

    }
}



A staci mi pak udelat:

Kód: [Vybrat]

@AllArgsConstructor
public class TimelineDao {
    final static String findAll = "SELECT * FROM TIMELINE";

    public List<Timeline> findAll(ConnStm conn) throws Exception {
        return DbUtil.executeQuery(findAll, new Timeline(), conn);
    }
}



Akorat jeste nevim, jak dopravit do DAOcka Connection jinak, nez pres parametr metody. Takhle totiz muzu snadno zaridit, aby mi kazdy jeden request probehl v jedne transakci.

Takhle vypadá moje DI:

Kód: [Vybrat]

@Data
public class App {

    DatasourcePool datasourcePool;
    DataService dataService;
    LoginService loginService;
    RestApi restApi;
    TimelineDao timelineDao;


    public App() throws Exception {
        initProperties();

        datasourcePool = new DatasourcePool(
                "org.postgresql.Driver",
                System.getProperty("jdbc.connection"),
                System.getProperty("jdbc.user"),
                System.getProperty("jdbc.password")
        );
        timelineDao = new TimelineDao();
        dataService = new DataService(timelineDao);
        loginService = new LoginService();
        restApi = new RestApi(dataService, loginService, datasourcePool);
    }


Start na Tomcatovi je za 700ms.

Re:Alternativa k Hibernate
« Odpověď #24 kdy: 28. 07. 2018, 13:33:24 »
Zkoušel jsem si jak by to vypadalo s JDBC a nepřijde mi to vůbec špatné:



Kód: [Vybrat]
public class DbUtil {

    public static <T extends ResultSetModel> List<T> resultSet(T model, ResultSet rs) throws SQLException, IllegalAccessException, InstantiationException {
        List<T> ret = new ArrayList<>();
        while(rs.next()) {
            Object[] rowArr = getRowAsArray(rs);
            model.setFromRow(rowArr);
            ret.add(model);
        }
        return ret;
    }

    public static Object[] getRowAsArray(ResultSet rs) throws SQLException {
        int colCnt = rs.getMetaData().getColumnCount();
        Object[] ret = new Object[colCnt];
        for(int i = 0; i < colCnt; i++) {
            ret[i] = rs.getObject(i+1);
        }
        return ret;
    }


    public static ResultSet executeQuery(String sql, ConnStm conn) throws InterruptedException, SQLException {
        PreparedStatement st = null;
        ResultSet rs = null;
        try {
            st = conn.getPrepStat(sql);
            rs = st.executeQuery();
        } catch (SQLException e) {
            throw e;
        }

        return rs;
    }

    public static <T extends ResultSetModel> List<T> executeQuery(String sql, T model, ConnStm conn) throws SQLException, InterruptedException, InstantiationException, IllegalAccessException {
        return resultSet(model, executeQuery(sql, conn) );
    }
}


Kód: [Vybrat]
public interface ResultSetModel {
    public void setFromRow(Object[] row);
}

@Data
@ToString
public class Timeline implements ResultSetModel {
    private Timestamp measured_timestamp;
    private String keyword_name_fid;
    private Integer amount;
    private String special;

    @Override
    public void setFromRow(Object[] row) {
        int i = 0;
        measured_timestamp = (Timestamp) row[i++];
        keyword_name_fid = (String) row[i++];
        amount = (Integer) row[i++];
        special = (String) row[i++];

    }
}



A staci mi pak udelat:

Kód: [Vybrat]

@AllArgsConstructor
public class TimelineDao {
    final static String findAll = "SELECT * FROM TIMELINE";

    public List<Timeline> findAll(ConnStm conn) throws Exception {
        return DbUtil.executeQuery(findAll, new Timeline(), conn);
    }
}



Akorat jeste nevim, jak dopravit do DAOcka Connection jinak, nez pres parametr metody. Takhle totiz muzu snadno zaridit, aby mi kazdy jeden request probehl v jedne transakci.

Takhle vypadá moje DI:

Kód: [Vybrat]

@Data
public class App {

    DatasourcePool datasourcePool;
    DataService dataService;
    LoginService loginService;
    RestApi restApi;
    TimelineDao timelineDao;


    public App() throws Exception {
        initProperties();

        datasourcePool = new DatasourcePool(
                "org.postgresql.Driver",
                System.getProperty("jdbc.connection"),
                System.getProperty("jdbc.user"),
                System.getProperty("jdbc.password")
        );
        timelineDao = new TimelineDao();
        dataService = new DataService(timelineDao);
        loginService = new LoginService();
        restApi = new RestApi(dataService, loginService, datasourcePool);
    }


Start na Tomcatovi je za 700ms.

Vypadá to hezky a na triviální úkoly typu select z jedné tabulky to taky tak používám.

Akorát, že se to celé neúměrně zesložití, jakmile začneme entity skládat (kde entita obsahuje kolekci jiných entit) a začneme ty entity ukládat do databáze, opětovně načítat, zjišťovat, zda se entita změnila, ověřovat kardinalitu... Skončíte na vlastním malém, ale nedokonalém ORM. To už je lepší použít něco hotového.

anonym

Re:Alternativa k Hibernate
« Odpověď #25 kdy: 28. 07. 2018, 14:11:16 »
To si nemyslím, že je problém, mám pro to úplně jasné řešení.

Kolikrát potřebujete mít 1:1 vztah Objekt-Tabulka? V naprosto zanedbatelném počtu přípádů. Vždy používáte složené dotazy, které jsou v podstatě kočkopes. Výstupem těch dotazů je ResultSet a k němu odpovídající ResultSetModel. Ten model nepředstavuje žádnou tabulku, představuje výstup z SQL dotazu, k němu je vztažen, a obsahuje mix informací z různých tabulek.

Ještě jednou, když máte trochu složitější databázi, tak vaše Objekty jsou SQL-orientované a né Tabulkově-orientované. Samostatné tabulky vás až tak nezajímají.

Tady mě právě sere ten Hibernate, já nikdy nejsem zvědavý na načítání celých tabulek, chci mít raději SQL-orientovaný ResultSetModel. Navíc tím dostanou krásnou svobodu čistého SQL.

Takže u Selectů je to jansé, tam mi přijde že jasně vede přístup přes JDBC.


Co se týče insertování nových záznamů, taaak....... tam opět moc nevidím problém, proč si myslíš, že se to zesložití? Vždyť ty nepotřebuješ komponovat Model třídy jako u Hibernate, to přece vůbec není nutné. Vždy sám v kódu víš, jestli k nově vkládanému řádku v tabulce A chceš přidat FID z již existujícího řádku v B, nebo chceš přidat i nový řádek do B a jeho id použít v A.

Taky co se týče updatu, tak tam taky snad nikdy nepořebuješ super-univerzální možnost updatovat kdykoliv cokoliv tak jak to umí Hibernate, v praxi vždycky potřebuješ z hlediska business logiky updatovat jen pár sloupečků v tabulce, na to si case-to-case uděláš nevou metodu do Daočka.

Problém je, že ty chceš, asi ze zvyku, nutně dělat ORM mapování, vč. reálných vazeb mezi Modely, tak jak to má hibernate. A TO JE PRÁVĚ to, co způsobuje ty problémy, u kterých skončíš tak, že hibernate použiješ rovnou. Ale proč to kompletní ORM chceš dělat, co ti to přinese? To přece vůbec není nutné, neumím si představit nějakou podstatnou výhodu.

Mě přijde SQL svět mnohem přehlednější a jasnější, a když dlám aplikaci, tak přece nad ním nechci dělat tlustou nadstavbu. Vždyť SQL to je asi ta nejsolidnější technologie co tu je, spolu třeba s REGEXem. Proč bych nad tím chtěl dělat nějakou tlustou nadstavbu je jedno v čem.

Mě přijde výhoda Hibernata-like frameworku, když děláš v nějaké totální žumpě s pomalým intranetem, kde přístup do soukromé databáze tvé komponenty je na s vysokou latencí a ty si tu svou databázi nemůžeš dát na stejný stroj kde ti ta tvá komponenta běží, ikdyž ji vlastně ta komponenta vlastní. To jsou ty typické Oracle sračky, kde je jedna obří databáze a ty v ní máš svého Usera. V ten moment ti nezbývá než si tu databázi kvůli latencím cachovat, protože by to jinak bylo pomalé jako prase. A tady může třeba ten Hibernate pomoct.

anonym

Re:Alternativa k Hibernate
« Odpověď #26 kdy: 28. 07. 2018, 17:35:41 »
Jo a ještě taková jedna věc, když jsem nepoužil Spring, integrační test se mi spustí ve vteřině:

Kód: [Vybrat]

@RunWith(JUnit4.class)
public class AppIT {

    App app;

    @Before
    public void init() throws Exception {
        app = new App();
    }

    @Test
    public void daoTest() throws SQLException, InterruptedException, InstantiationException, IllegalAccessException {
        KeywordDao kw = app.getKeywordDao();
        DatasourcePool dp = app.getDatasourcePool();

        List<FetchNewDataRS> fetchNewDataRS = kw.fetchNewDataRS(dp.getConnection());

        fetchNewDataRS.stream().forEach(System.out::println);

    }
}


Naprosto neskutečné, mám z toho radost :-) Když si vzpomenu, jaký to je porod pouštět integrační test se Springem, než se to načte atp.

Mám tady kopii té aplikace ve Springu a tam to startuje dobrých 8 vteřin, tragédie. Při spuščtěné aplikaci to jde alespoň díky Devtools, které však občas blbosu, jen za 2.5 vteřiny, ale to jaksi nejde v případě integračních testů.
A kdyby jenom to, ještě navíc mi to tam teď nahodile hází exception ohledně jakésik Hibernatí třídy a tu exception to jednou při startu vyhodí a jednou ne, takže je to nahodilé. Sranda docela.

Fuck off Spring.

anonym

Re:Alternativa k Hibernate
« Odpověď #27 kdy: 28. 07. 2018, 17:39:21 »
všimněte si v tom junit testu, že já v podstatě vytvořím instanci celé své aplikace App, která slouží zároveň jako DI kontext, a ta se prostě vytvoří okamžitě díky tomu, že nepoužívám reflexi a můj Datapool vytváří connections líně.

Re:Alternativa k Hibernate
« Odpověď #28 kdy: 28. 07. 2018, 18:21:51 »
To si nemyslím, že je problém, mám pro to úplně jasné řešení.

Kolikrát potřebujete mít 1:1 vztah Objekt-Tabulka? V naprosto zanedbatelném počtu přípádů. Vždy používáte složené dotazy, které jsou v podstatě kočkopes. Výstupem těch dotazů je ResultSet a k němu odpovídající ResultSetModel. Ten model nepředstavuje žádnou tabulku, představuje výstup z SQL dotazu, k němu je vztažen, a obsahuje mix informací z různých tabulek.

Ještě jednou, když máte trochu složitější databázi, tak vaše Objekty jsou SQL-orientované a né Tabulkově-orientované. Samostatné tabulky vás až tak nezajímají.

Tady mě právě sere ten Hibernate, já nikdy nejsem zvědavý na načítání celých tabulek, chci mít raději SQL-orientovaný ResultSetModel. Navíc tím dostanou krásnou svobodu čistého SQL.

Takže u Selectů je to jansé, tam mi přijde že jasně vede přístup přes JDBC.


Co se týče insertování nových záznamů, taaak....... tam opět moc nevidím problém, proč si myslíš, že se to zesložití? Vždyť ty nepotřebuješ komponovat Model třídy jako u Hibernate, to přece vůbec není nutné. Vždy sám v kódu víš, jestli k nově vkládanému řádku v tabulce A chceš přidat FID z již existujícího řádku v B, nebo chceš přidat i nový řádek do B a jeho id použít v A.

Taky co se týče updatu, tak tam taky snad nikdy nepořebuješ super-univerzální možnost updatovat kdykoliv cokoliv tak jak to umí Hibernate, v praxi vždycky potřebuješ z hlediska business logiky updatovat jen pár sloupečků v tabulce, na to si case-to-case uděláš nevou metodu do Daočka.

Problém je, že ty chceš, asi ze zvyku, nutně dělat ORM mapování, vč. reálných vazeb mezi Modely, tak jak to má hibernate. A TO JE PRÁVĚ to, co způsobuje ty problémy, u kterých skončíš tak, že hibernate použiješ rovnou. Ale proč to kompletní ORM chceš dělat, co ti to přinese? To přece vůbec není nutné, neumím si představit nějakou podstatnou výhodu.

Mě přijde SQL svět mnohem přehlednější a jasnější, a když dlám aplikaci, tak přece nad ním nechci dělat tlustou nadstavbu. Vždyť SQL to je asi ta nejsolidnější technologie co tu je, spolu třeba s REGEXem. Proč bych nad tím chtěl dělat nějakou tlustou nadstavbu je jedno v čem.

Mě přijde výhoda Hibernata-like frameworku, když děláš v nějaké totální žumpě s pomalým intranetem, kde přístup do soukromé databáze tvé komponenty je na s vysokou latencí a ty si tu svou databázi nemůžeš dát na stejný stroj kde ti ta tvá komponenta běží, ikdyž ji vlastně ta komponenta vlastní. To jsou ty typické Oracle sračky, kde je jedna obří databáze a ty v ní máš svého Usera. V ten moment ti nezbývá než si tu databázi kvůli latencím cachovat, protože by to jinak bylo pomalé jako prase. A tady může třeba ten Hibernate pomoct.

Pokud tomu dobře rozumím, složitosti skládání entit se vyhnete tím, že používáte anonymní ResultSetModel. A ostatním  problémům se vyhnete tím, že použijete jiný programátorský styl. Pro nějaké mikroprojekty to asi není problém, ale jinak se tím zbavujete jedné z možnosti jak dekomponovat aplikační doménu (problém, který má aplikace řešit). To je obecně spíš krok zpět. To už mi přijde lepší se objektově-relační impedanci (problému mapování objektů na sql) vyhnout použitím nějaké nativní objektové databáze.

peter

Re:Alternativa k Hibernate
« Odpověď #29 kdy: 28. 07. 2018, 18:32:42 »
Tiez sa priklanam vynechat ORM. Zdoraznil by som ale pristup k databaze cez Declarative interface (napr  v jdbi).
V principe si spravis cisty interface, a ten potom pomocou sql dotazov implementujes. napr:

public interface ZmluvyDao{
 List<Zmluva> zoznamZmluv(String customerId);
 Zmluva zmluvaPodlaId(String cisloZmluvy);
 long vytvorZmluvu(Zmluva);
}

potom uz len pises sql dotazy k jednotlivym metodam
ZmluvyDao.zoznamZmluv:
sleect * from zmluvy where customerId=:customerId order by cisloZmluvy;
atd.

Ak sa dobre pozries na interface, pripomina API k nejakemu inemu systemu, ako by si databazu volal cez pripravene REST rozhranie. Takto vies aplikaciu oddelit od problematiky databazy. Proste si napises API ake potrebujes a potom si ho implementujes (napises sql ktore ho zrealizuju v db).

taketo rozdelenie vies potom vyuzit vo viacerych smeroch:

1. sql je netypovy jazyk bez moznosti validacie pri kompilovani aplikacie. Preto je absolutne nutne robit unit testy aby nahradili kompilacnu typovu validaciu. Pri takomto rozdeleni je to jednoduche. Vytvoris databazu (napr h2 v pamati),
spustis int scripty (napr. Flyway) a zacnes volat jednotilive methody interface. Takto si schopny otestovat celu databazu bez toho aby si sa prekusaval business logikou aplikacie ktora ju pouziva. Vies jednoducho skontrolovat ze si otestoval 100% volani db.

2. ak mas nad db vrstvou zlozitejsiu business logiku, vies specificke unit testy robit bez nutnosti vytvarania db, lebo db interface sa da lahko namokovat.

3. cirou nahodou si prave naplnil principy "hexagonal architecture"

4. neboj sa robit ine data objekty na citanie a ine na zapisovanie, ak to potrebujes. Vyhoda je ze vies priamo z databazy vytahovat DTO z public rozhrani aplikacie a nemusis ich premapovavat ako sa to bezne robi s hibernate. Ako pristupit k rozdielom pri zapise a cistani pozri napr na CQRS ktore to detailnejsie rozobera https://martinfowler.com/bliki/CQRS.html