Diese Seite ist eine kleine Einführung zum objektrelationale Mapping von Datenbanken mit dem Open Source Tool Hibernate. Als Beispiel dient eine Zitate Datenbank auf Basis von MySQL. Andere Datenbanken sind auch durch leichtes anpassen der Konfiguration möglich.
Als Grundlage des Beispiels soll diese Zitate Datenbank mit folgender Struktur dienen.
Es gibt eine 1:n Beziehung. Ein Autor kann mehrere Zitate haben.
Möglichkeiten des Mappings:
| Nr. | Mapping von | nach | mit Klasse oder Tool | Beispiel | Bemerkung |
| 1 | XML | DDL | net.sf.hibernate.tool. hbm2ddl.SchemaExport |
tw-zitat-schema-export.bat | Erzeugt aus der XML Mapping Datei das Schema für die Datenbank. |
| 2 | DDL | XML | Middlegen | - | Aus vorhandener Datenbank wird mit Middlegen die Hibernate Mapping XML Datei erzeugt. |
| 3 | XML | Java | net.sf.hibernate.tool. hbm2java.CodeGenerator |
tw-zitat-generate-java.bat | Generiert Java Code (Beans) aus XML Hibernate Mapping Dateien. |
| 4 | Java | XML | net.sf.hibernate.tool. class2hbm.MapGenerator |
tw-zitat-mapping.bat | Aus Java Klassen werden die Hibernate XML Dateien generiert. |
| 5 | Java | XML | XDoclet | - | Aus Java Klassen die mit XDoclet Tags versehen sind,werden die Hibernate XML Dateien generiert. |
DDL = Datenbank Schema
XML = Hibernate Mapping
Java = Java Beans
Es gibt verschiedenen Ansätze für die Vorgehensweise.
Der Middle-out-Ansatz beginnt mit dem erstellen der Hibernate XML Datei. Dann wird mit dem hbm2ddl Tool das Datenbank Schema erzeugt. Anschließend werden die Java Beans mit hbm2java generiert.
Der Bottom-up-Ansatz geht von einer bestehenden Datenbank aus. Bei dem Top-down-Ansatz wird mit dem schreiben der Java Beans begonnen.
Kommen wir zum ersten Beispiel. Wir erstellen die Hibernate Mapping XML Datei per Hand. Und generieren dann über hbm2ddl das Datenbank Schema. Für jede Tabelle wird je eine XML Datei erstellt. Für unser Beispiel könnten sie so aussehen:
Die XML Datei für die Autoren:
<?xml version="1.0"?
Die XML Datei für die Zitate:
<?xml version="1.0"?
Aus beiden obigen mapping Dateien wird eine tw-zitat-mapping.xml erzeugt. Aus dieser Mapping Datei wird dann das Datenbankschema erzeugt. Es kann ein solches Script verwendet werden. Die Pfade müssen entsprechen angepasst werden.
rem tw-zitat-schema-export.bat set BASIS=E:\Java\lokal\TWZitat set LIB=%BASIS%\lib set BIN=%BASIS%\bin set INPUT_DATEI=tw-zitat-mapping.xml set OUTPUT_SCHEMA_DATEI=tw-zitat-schema.ddl set DB_TREIBER=C:\mysql\mm.mysql.jdbc-1.2c\mysql_comp.jar set CP=%LIB%; %BIN%; %DB_TREIBER%; %CLASSPATH%; %LIB%\hibernate2.jar; %LIB%\commons-logging-1.0.4.jar; %LIB%\commons-lang-1.0.1.jar; %LIB%\cglib-2.0-rc2.jar; %LIB%\dom4j-1.4.jar; %LIB%\odmg-3.0.jar; %LIB%\xml-apis.jar; %LIB%\xerces-2.4.0.jar; %LIB%\xalan-2.4.0.jar; %LIB%\jdom.jar; %LIB%\commons-collections-2.1.1.jar; %LIB%\hibernate-tools.jar rem --text Option schreibt keine Datenbank java -cp %CP% net.sf.hibernate.tool.hbm2ddl.SchemaExport --text --format --delimiter=; --properties=%BASIS%/hibernate.properties --output=%OUTPUT_SCHEMA_DATEI% %INPUT_DATEI%
Für die Ausführung werden die obigen jar Dateien benötigt. Sie sind alle bei Hibernate dabei. Die hibernate-tools.jar ist im hibernate-extensions-2.1.3 Package enthalten das gesondert geladen werden muss.
Nach dem fehlerfreien Ausführen erhält man das Datenbank Schema, welches in die DB geschrieben werden kann. Wird die --text Option nicht angegeben, wird versucht gleich in die Datenbank zu schreiben. Für unser Beispiel sieht das erzeugte Schema (tw-zitat-schema.ddl) so aus:
alter table ZITATE drop foreign key FK9DC0094D84751B00; drop table if exists ZITATE; drop table if exists AUTOREN; create table ZITATE ( ZITATE_ID integer not null auto_increment, AUTOR_NR integer not null, ZITAT varchar(255) not null, KATEGORIE integer, primary key (ZITATE_ID) ); create table AUTOREN ( AUTOREN_ID integer not null auto_increment, NAME varchar(255) not null, GEBDATUM date, BERUF varchar(255), BEMERKUNG varchar(255), VORNAME varchar(255), TODESDATUM date, primary key (AUTOREN_ID) ); alter table ZITATE add index FK9DC0094D84751B00 (AUTOR_NR), add constraint FK9DC0094D84751B00 foreign key (AUTOR_NR) references AUTOREN (AUTOREN_ID);
Nach dem Import dieses Schemas in die Datenbank ist die gewünschte Zitat Datenbank vorhanden.
//todo
Aus den oben erstellten Hibernate Mapping Datei tw-zitat-mapping.xml die für die Autoren und die Zitate die beschreibungen enthält wird nun Java Code generiert. Die tw-zitat-generate-java.bat ruft den hbm2java CodeGenerator auf.
rem tw-zitat-generate-java.bat set BASIS=E:\Java\lokal\TWZitat set LIB=%BASIS%\lib set BIN=%BASIS%\bin set INPUT_DATEI=tw-zitat-mapping.xml set OUTPUT_SCHEMA_DATEI=tw-zitat-schema.ddl set CP=%LIB%; %BIN%; %DB_TREIBER%; %CLASSPATH%; %LIB%\hibernate2.jar; %LIB%\commons-logging-1.0.4.jar; %LIB%\commons-lang-1.0.1.jar; %LIB%\cglib-2.0-rc2.jar; %LIB%\dom4j-1.4.jar; %LIB%\odmg-3.0.jar; %LIB%\xml-apis.jar; %LIB%\xerces-2.4.0.jar; %LIB%\xalan-2.4.0.jar; %LIB%\jdom.jar; %LIB%\commons-collections-2.1.1.jar; %LIB%\hibernate-tools.jar java -cp %CP% net.sf.hibernate.tool.hbm2java.CodeGenerator %INPUT_DATEI%
Das Ergebnis sind zwei Java Beans. Eine für den Autor:
1:package de.wenzlaff.twzitat.mapping; 2: 3:import java.io.Serializable; 4:import java.util.Date; 5:import java.util.Set; 6:import org.apache.commons.lang.builder.ToStringBuilder; 7: 8: 9:/** @author Hibernate CodeGenerator */ 10:public class Autor implements Serializable { 11: 12: /** identifier field */ 13: private Integer id; 14: 15: /** persistent field */ 16: private String name; 17: 18: /** nullable persistent field */ 19: private Date gebDatum; 20: 21: /** nullable persistent field */ 22: private String beruf; 23: 24: /** nullable persistent field */ 25: private String bemerkung; 26: 27: /** nullable persistent field */ 28: private String vorname; 29: 30: /** nullable persistent field */ 31: private Date todesDatum; 32: 33: /** persistent field */ 34: private Set zitate; 35: 36: /** full constructor */ 37: public Autor(String name, Date gebDatum, String beruf, String bemerkung, String vorname, Date todesDatum, Set zitate) { 38: this.name = name; 39: this.gebDatum = gebDatum; 40: this.beruf = beruf; 41: this.bemerkung = bemerkung; 42: this.vorname = vorname; 43: this.todesDatum = todesDatum; 44: this.zitate = zitate; 45: } 46: 47: /** default constructor */ 48: public Autor() { 49: } 50: 51: /** minimal constructor */ 52: public Autor(String name, Set zitate) { 53: this.name = name; 54: this.zitate = zitate; 55: } 56: 57: public Integer getId() { 58: return this.id; 59: } 60: 61: public void setId(Integer id) { 62: this.id = id; 63: } 64: 65: public String getName() { 66: return this.name; 67: } 68: 69: public void setName(String name) { 70: this.name = name; 71: } 72: 73: public Date getGebDatum() { 74: return this.gebDatum; 75: } 76: 77: public void setGebDatum(Date gebDatum) { 78: this.gebDatum = gebDatum; 79: } 80: 81: public String getBeruf() { 82: return this.beruf; 83: } 84: 85: public void setBeruf(String beruf) { 86: this.beruf = beruf; 87: } 88: 89: public String getBemerkung() { 90: return this.bemerkung; 91: } 92: 93: public void setBemerkung(String bemerkung) { 94: this.bemerkung = bemerkung; 95: } 96: 97: public String getVorname() { 98: return this.vorname; 99: } 100: 101: public void setVorname(String vorname) { 102: this.vorname = vorname; 103: } 104: 105: public Date getTodesDatum() { 106: return this.todesDatum; 107: } 108: 109: public void setTodesDatum(Date todesDatum) { 110: this.todesDatum = todesDatum; 111: } 112: 113: public Set getZitate() { 114: return this.zitate; 115: } 116: 117: public void setZitate(Set zitate) { 118: this.zitate = zitate; 119: } 120: 121: public String toString() { 122: return new ToStringBuilder(this) 123: .append("id", getId()) 124: .toString(); 125: } 126: 127:}
Und eine für die Zitate:
1:package de.wenzlaff.twzitat.mapping; 2: 3:import java.io.Serializable; 4:import org.apache.commons.lang.builder.ToStringBuilder; 5: 6: 7:/** @author Hibernate CodeGenerator */ 8:public class Zitat implements Serializable { 9: 10: /** identifier field */ 11: private Integer id; 12: 13: /** persistent field */ 14: private int autorNr; 15: 16: /** persistent field */ 17: private String zitat; 18: 19: /** nullable persistent field */ 20: private Integer kategorie; 21: 22: /** full constructor */ 23: public Zitat(int autorNr, String zitat, Integer kategorie) { 24: this.autorNr = autorNr; 25: this.zitat = zitat; 26: this.kategorie = kategorie; 27: } 28: 29: /** default constructor */ 30: public Zitat() { 31: } 32: 33: /** minimal constructor */ 34: public Zitat(int autorNr, String zitat) { 35: this.autorNr = autorNr; 36: this.zitat = zitat; 37: } 38: 39: public Integer getId() { 40: return this.id; 41: } 42: 43: public void setId(Integer id) { 44: this.id = id; 45: } 46: 47: public int getAutorNr() { 48: return this.autorNr; 49: } 50: 51: public void setAutorNr(int autorNr) { 52: this.autorNr = autorNr; 53: } 54: 55: public String getZitat() { 56: return this.zitat; 57: } 58: 59: public void setZitat(String zitat) { 60: this.zitat = zitat; 61: } 62: 63: public Integer getKategorie() { 64: return this.kategorie; 65: } 66: 67: public void setKategorie(Integer kategorie) { 68: this.kategorie = kategorie; 69: } 70: 71: public String toString() { 72: return new ToStringBuilder(this) 73: .append("id", getId()) 74: .toString(); 75: } 76: 77:}
rem tw-zitat-mapping.bat set BASIS=E:\Java\lokal\TWZitat set LIB=%BASIS%\lib set BIN=%BASIS%\bin set OUTPUT_DATEI=tw-zitat-mapping.xml set MAPPING_CLASS=de.wenzlaff.twzitat.mapping.Autor de.wenzlaff.twzitat.mapping.Zitat set CP=%LIB%; %BIN%; %CLASSPATH%; %LIB%\hibernate2.jar; %LIB%\commons-logging-1.0.4.jar; %LIB%\commons-lang-1.0.1.jar; %LIB%\cglib-2.0-rc2.jar; %LIB%\dom4j-1.4.jar; %LIB%\odmg-3.0.jar; %LIB%\xml-apis.jar; %LIB%\xerces-2.4.0.jar; %LIB%\xalan-2.4.0.jar; %LIB%\jdom.jar; %LIB%\commons-collections-2.1.1.jar; %LIB%\hibernate-tools.jar java -classpath %CP% net.sf.hibernate.tool.class2hbm.MapGenerator --output=%OUTPUT_DATEI% %MAPPING_CLASS%
Das Ergebnis sind die automatisch erzeugten XML Dateien. Die für den Autor:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="de.wenzlaff.twzitat.mapping.Autor" table="AUTOREN"> <id name="id" column="AUTOREN_ID" type="integer"> <generator class="identity"/> </id
Und die für die Zitate:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="de.wenzlaff.twzitat.mapping.Zitat" table="ZITATE">
<id name="id" column="ZITATE_ID" type="integer">
<generator class="identity"/>
</id
//todo
Das folgende Java Beispiel zeigt den Zugriff mit Hibernate.
1:/* 2: * Thomas Wenzlaff 05.05.2006 3: */ 4:package test.de.wenzlaff.twzitat; 5: 6:import java.util.Date; 7:import java.util.List; 8: 9:import net.sf.hibernate.HibernateException; 10:import net.sf.hibernate.Session; 11:import net.sf.hibernate.SessionFactory; 12:import net.sf.hibernate.Transaction; 13:import net.sf.hibernate.cfg.Configuration; 14:import de.wenzlaff.twzitat.mapping.Autor; 15:import de.wenzlaff.twzitat.mapping.Zitat; 16: 17:/** 18: * @author Thomas Wenzlaff 19: * 20: */ 21:public class ZitatGenerator { 22: 23: private SessionFactory sessionFactory; 24: 25: public static void main(String[] args) { 26: 27: ZitatGenerator ivZitatInstanz = new ZitatGenerator(); 28: // ivZitatInstanz.showAlleZitat(); 29: // ivZitatInstanz.showAlleAutoren(); 30: ivZitatInstanz.showAlleZitatMitAutoren(); 31: } 32: 33: public ZitatGenerator() { 34: try { 35: System.out.println("Initializing Hibernate"); 36: sessionFactory = new Configuration().configure() 37: .buildSessionFactory(); 38: System.out.println("Finished Initializing Hibernate"); 39: } catch (HibernateException ex) { 40: ex.printStackTrace(); 41: System.exit(5); 42: } 43: } 44: 45: private void showAlleZitat() { 46: Session sess = null; 47: Transaction trx = null; 48: try { 49: sess = sessionFactory.openSession(); 50: trx = sess.beginTransaction(); 51: 52: List lvZitate = sess.find("from Zitat"); 53: for (int i = 0; i < lvZitate.size(); i++) { 54: Zitat lvZitat = (Zitat) lvZitate.get(i); 55: System.out.println("Autor Nr.: " + lvZitat.getAutorNr() 56: + " : " + lvZitat.getZitat()); 57: 58: } 59: trx.commit(); 60: } catch (HibernateException ex) { 61: if (trx != null) try { 62: trx.rollback(); 63: } catch (HibernateException exRb) { 64: } 65: throw new RuntimeException(ex.getMessage()); 66: } finally { 67: try { 68: sess.close(); 69: } catch (Exception exCl) { 70: } 71: } 72: } 73: 74: private void showAlleAutoren() { 75: Session sess = null; 76: Transaction trx = null; 77: try { 78: sess = sessionFactory.openSession(); 79: trx = sess.beginTransaction(); 80: 81: List lvZitate = sess.find("from Autor"); 82: for (int i = 0; i < lvZitate.size(); i++) { 83: Autor lvAutor = (Autor) lvZitate.get(i); 84: System.out.println("Autor Nr.: " + lvAutor.getId() + " = " 85: + lvAutor.getVorname() + " " + lvAutor.getName() + "( " 86: + lvAutor.getBeruf() + " )"); 87: } 88: trx.commit(); 89: } catch (HibernateException ex) { 90: if (trx != null) try { 91: trx.rollback(); 92: } catch (HibernateException exRb) { 93: } 94: throw new RuntimeException(ex.getMessage()); 95: } finally { 96: try { 97: sess.close(); 98: } catch (Exception exCl) { 99: } 100: } 101: } 102: 103: private void showAlleZitatMitAutoren() { 104: Session sess = null; 105: Transaction trx = null; 106: try { 107: sess = sessionFactory.openSession(); 108: trx = sess.beginTransaction(); 109: 110: List lvZitate = sess.find("from Zitat where AUTOR_NR=2"); 111: List lvAutor = sess.find("from Autor where AUTOREN_ID=2"); 112: 113: for (int i = 0; i < lvZitate.size(); i++) { 114: Zitat lvZitat = (Zitat) lvZitate.get(i); 115: System.out.println("Autor Nr.: " + lvZitat.getAutorNr() + " " 116: + lvZitat.getZitat()); 117: 118: } 119: System.out 120: .println("Autor : " + ((Autor) lvAutor.get(0)).getName()); 121: 122: // Einen neuen Autor speichern 123: Autor lvNeuerAutor = new Autor(); 124: lvNeuerAutor.setName("Wenzlaff"); 125: lvNeuerAutor.setVorname("Thomas"); 126: lvNeuerAutor.setBeruf("IT-Berater"); 127: lvNeuerAutor.setGebDatum(new Date()); 128: lvNeuerAutor.setTodesDatum(new Date()); 129: lvNeuerAutor.setBemerkung(""); 130: sess.save(lvNeuerAutor); 131: 132: // Ein neues Zitat speichern unter dem neuen Autor. 133: Zitat lvZitat = new Zitat(); 134: lvZitat.setZitat("Mein neues Zitat was immer hinten ran kommt."); 135: lvZitat.setAutorNr(((Integer)lvNeuerAutor.getId()).intValue()); 136: sess.save(lvZitat); 137: 138: 139: 140: sess.flush(); 141: 142: trx.commit(); 143: 144: } catch (HibernateException ex) { 145: if (trx != null) try { 146: trx.rollback(); 147: } catch (HibernateException exRb) { 148: } 149: throw new RuntimeException(ex.getMessage()); 150: } finally { 151: try { 152: sess.close(); 153: } catch (Exception exCl) { 154: } 155: } 156: } 157: 158:}
Damit das Beispiel läuft, ist die Anwendung noch zu konfigurieren. Dazu diese hibernate.cfg.xml Datei erstellen.
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">
org.gjt.mm.mysql.Driver
</property>
<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/twzitat
</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"></property>
<property name="dialect"<net.sf.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<property name="transaction.factory_class">
net.sf.hibernate.transaction.JDBCTransactionFactory
</property>
<property name="hibernate.cache.provider_class">
net.sf.hibernate.cache.HashtableCacheProvider
</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping resource="de/wenzlaff/twzitat/mapping/Autor.hbm.xml"/>
<mapping resource="de/wenzlaff/twzitat/mapping/Zitat.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Die Hibernate Properties kann für MySQL so aussehen:
# # TWZitat Properties # ###################### ### Query Language ### ###################### ## define query language constants / function names hibernate.query.substitutions true 1, false 0, yes 'Y', no 'N' ################# ### Platforms ### ################# ## MySQL hibernate.dialect net.sf.hibernate.dialect.MySQLDialect hibernate.connection.driver_class org.gjt.mm.mysql.Driver #hibernate.connection.driver_class com.mysql.jdbc.Driver hibernate.connection.url jdbc:mysql://localhost/twzitat hibernate.connection.username public hibernate.connection.password public ################################# ### Hibernate Connection Pool ### ################################# hibernate.connection.pool_size 1 ############################## ### Proxool Connection Pool### ############################## ## Properties for external configuration of Proxool hibernate.proxool.pool_alias pool1 ################################# ### Plugin ConnectionProvider ### ################################# ## use a custom ConnectionProvider (if not set, Hibernate will choose a built-in ConnectionProvider using hueristics) #hibernate.connection.provider_class net.sf.hibernate.connection.DriverManagerConnectionProvider net.sf.hibernate.connection.DatasourceConnectionProvider ############################## ### Miscellaneous Settings ### ############################## ## print all generated SQL to the console hibernate.show_sql true ## set the maximum JDBC 2 batch size (a nonzero value enables batching) hibernate.jdbc.batch_size 0 ## use JDBC batching for versioned data hibernate.jdbc.batch_versioned_data true ## use streams when writing binary types to / from JDBC hibernate.jdbc.use_streams_for_binary true ## set the maximum depth of the outer join fetch tree hibernate.max_fetch_depth 1 ########################## ### Second-level Cache ### ########################## ## set a prefix for cache region names hibernate.cache.region_prefix hibernate.test ## enable the query cache hibernate.cache.use_query_cache true ## choose a cache implementation hibernate.cache.provider_class net.sf.hibernate.cache.EhCacheProvider