W JDBC powinieneś napisać sobie DDL i wykonać go w bazie, do której się łączysz.
Ostatnio bawiłem się Hiberante i code-first. Uważam, że wygenerowany kod schematu to jest niezły syf. Mam na myśli typy danych. Na przykład jest problem, aby Hibernate wygenerował prawidłowy typ danych dla daty i czasu z uwzględnieniem strefy czasowej dla JDK 1.8 (typ po stronie bazy oczywiście). Dlatego wolę manualnie ustawić typ danych na bazie wtedy wszystko śmiga. Albo jako klucz użyje mi INT8, a ja chcę BIGINTEGER o większym zakresie.
Sumarycznie więc robie tak, gdy pracuje z Hibernate:
- robię code-first, aby zobaczyć jak kod ORM został zinterpretowany (czy np. prawidłowo mapuje relacje jeden do wiele i wiele do wiele bez pośrednictwa dodatkowych tabel: prawidłowe użycie @JoinColumn i @JoinTable)
- jeżeli jest z grubsza ok to poprawiam typy danych i wprobwadzam to do pliku SQL, który jest wersjonowany (można rozważyć użycie narzędzia do migracji np. flyway)
- wersjonowany skrypt to jest też paliwo dla testów integracyjnych w Hibernate: przed każdym wykonanym testem jest tworzona baza o spodziewanym schemacie
- jeśli chcę zadeployować bazę na środowisko to mam gotowy skrypt, które mogę odtworzyć (spoko to się będzie automatyzować)
- poza tym dzięki wspólnemu skryptowi prosto mieć kontrole nad indeksami (i mieć wszędzie tak samo, co jest szczególnie ważne przy testowaniu integracyjnym z użyciem prawdziwej bazy)
Wiele osób uważa, że to ORM powinien o wszystkim decydować. W praktyce ORM jest głupi. Jakbym chciał bezpośrednio trzymać obiekty użyłbym NoSQL np. Mongo.