Winterschlaf für die Kleinsten und nicht nur

    Guten Tag an alle! Wenn sie ein Programm schreiben, das irgendwie mit der Datenbank interagiert, verwenden sie unterschiedliche Mittel. Dies ist das gute alte jdbc , das auch verwendet wird: EclipseLink , TopLink , iBatis (bereits MyBatis ), Spring Framework und natürlich der Held unseres Artikels - Hibernate . Natürlich habe ich hier nicht alle Tools für die Arbeit mit der Datenbank aufgelistet, aber ich habe versucht, die am häufigsten verwendeten anzugeben. Dieser Artikel zeigt, wie Sie mit Hibernate gespeicherte Prozeduren aufrufen, Tabellen und Klassenabfragen zuordnen können. Nehmen Sie als experimentelle Datenbank Oracle.
    Wir werden alles Notwendige für die Experimente vorbereiten. Beginnen wir mit der Datenbank. Zunächst erstellen wir 3 Tabletten, über die wir üben werden.
    CREATE TABLE book
    (
        id             NUMBER NOT NULL,
        name           VARCHAR2 (100 BYTE) NOT NULL,
        description    VARCHAR2 (1000 BYTE) NOT NULL,
        CONSTRAINT pk$book_id PRIMARY KEY (id)
    )
    CREATE TABLE student
    (
        id         NUMBER NOT NULL,
        name       VARCHAR2 (100 BYTE) NOT NULL,
        CONSTRAINT pk$student_id PRIMARY KEY (id)
    )
    CREATE TABLE catalog
    (
        id_student   NUMBER NOT NULL,
        id_book      NUMBER NOT NULL
    )
    

    Erstellen Sie nun eine Funktion. Ein Beispiel ist dumm, aber es zeigt das Prinzip des Aufrufs einer Funktion mit einem numerischen Eingabeparameter und der Ausgabezeichenfolge.
    CREATE OR REPLACE
    FUNCTION get_book_name_by_id (p_id IN NUMBER)
        RETURN VARCHAR2
    IS
        v_name   VARCHAR2 (100);
    BEGIN
        SELECT name
          INTO v_name
          FROM book
         WHERE id = p_id;
        RETURN v_name;
    EXCEPTION
        WHEN NO_DATA_FOUND
        THEN
            RETURN 'ну нет такой книги!!';
    END;
    

    Als Experiment erstellen wir außerdem eine einfache Prozedur zum Speichern in der Datenbank, die sowohl Eingabe- als auch Ausgabeparameter enthält.
    CREATE OR REPLACE 
    PROCEDURE save_book (p_id      IN OUT NUMBER,
                             p_name    IN     VARCHAR2,
                             p_descr   IN     VARCHAR2)
    IS
    BEGIN
        IF p_id > 0
        THEN
            UPDATE book
               SET name = p_name, description = p_descr
             WHERE id = p_id;
        ELSE
            SELECT catalog_seq.NEXTVAL INTO p_id FROM DUAL;
            INSERT INTO book
            VALUES (p_id, p_name, p_descr);
        END IF;
    END;
    

    Kommen wir nun zu Klassen in Java.
    Wir zeigen unsere 3 Datenbanktabellen in den Klassen wie folgt an:
    @Entity
    @Table
    public class Student implements Serializable {
    	private static final long serialVersionUID = -5170875020617735653L;
    	@Id  
    	@GeneratedValue(strategy = GenerationType.AUTO, generator = "my_entity_seq_gen")
    	@SequenceGenerator(name = "my_entity_seq_gen", sequenceName = "catalog_seq")
    	private long id;
    	@Column
    	private String name;
    	@OneToMany(mappedBy = "student", fetch = FetchType.LAZY)
    	private Set bookList;
    		// здесь идет реализация методов  getter, setter, hashCode(), equals(), toString()
    }
    

    Eine kleine Erklärung zum Code:
    • Wenn Ihr Klassenname beispielsweise nicht mit dem Tabellennamen übereinstimmt, schreiben wir wie folgt: Table (name = "STUDENT");
    • Eine der Anforderungen des Frameworks ist, dass jede Tabelle eine ID haben muss. Stimmen auch der Name des ID-Felds der Tabelle und der Name unserer Variablen nicht überein, sieht die Annotation folgendermaßen aus: Id @Column (name = "Tabellen-ID in der Datenbank");
    • Mit den Annotationen @GeneratedValue und @SequenceGenerator legen wir die Strategie für die Generierung eines eindeutigen Bezeichners fest. In diesem Fall wird beim Speichern von Informationen in der Datenbank eine Nummer aus der Sequenz mit dem Namen "catalog_seq" verwendet.
    • Da ein Schüler mehrere Bücher haben kann, zeigen wir dies mit der folgenden Annotation an: @OneToMany (mappedBy = "Schüler", fetch = FetchType.LAZY), wobei mappedBy = "Schüler" der Name des Feldes in der Buchklasse ist (siehe unten) und FetchType.LAZY - sagt uns, dass die Auflistung
      Set bookList
      Wir werden Daten nur auf Anfrage laden.

    Das Mapping der folgenden 2 Datenbanktabellen sieht folgendermaßen aus:
    @Entity
    @Table
    public class Book implements Serializable {
    	private static final long serialVersionUID = 1L;
    	@Id
    	@Column(name="ID")
    	@GeneratedValue(strategy = GenerationType.AUTO, generator = "my_entity_seq_gen")
    	@SequenceGenerator(name = "my_entity_seq_gen", sequenceName = "catalog_seq")
    	private long id;
    	@Column(name="NAME",unique = true, nullable = false, length = 100)
    	private String name;
    	@Column(name="DESCRIPTION",unique = true, nullable = false, length = 100)
    	private String description;
    	@ManyToOne(fetch = FetchType.LAZY,optional=true)
    	@JoinTable(name = "CATALOG", joinColumns = @JoinColumn(name = "ID_BOOK"), inverseJoinColumns = @JoinColumn(name = "ID_STUDENT"))
    	private Student student;
    	// здесь идет реализация методов  getter, setter, hashCode(), equals(), toString() 
    }
    

    Einschränkungen für Felder können direkt in der Annotation festgelegt werden. Dies erfolgt über die folgende Zeile @Column (name = "NAME", unique = true, nullable = false, length = 100). Mit den Annotationen @ManyToOne und @JoinTable (name = “CATALOG”) sagen wir, dass die Book-Tabelle und die Student-Tabelle eine Viele-zu-Viele-Beziehung über die Catalog-Tabelle haben. Daher werden alle Änderungen an Book und Student automatisch angewendet Katalogtabelle.
    Nun, wir sind mit der Zuordnung von Tabellen fertig und arbeiten jetzt direkt mit der Datenbank.
    Die Datenextraktion beim Befüllen der Sammlung kann auf verschiedene Arten erfolgen:
    1. Verwenden von HQL-Abfragen (Hibernate Query Language)
      	List book = (List)session.createQuery("from Book order by name").list();
      	
    2. Verwenden von SQL-Abfragen
      	List book = (List)session.createSQLQuery("select ID, DESCRIPTION, NAME from book order by NAME")
      	.addScalar("id",Hibernate.LONG).addScalar("name").addScalar("description")
      	.setResultTransformer(Transformers.aliasToBean(Book.class)).list();
      	
    3. mit Kriterien
      	List book=(List)session.createCriteria(Book.class).createAlias("student", "st").add(Restrictions.eq("st.name", "Maxim")).list();
      	

    Fahren wir mit der Arbeit mit gespeicherten Prozeduren fort. Um eine Funktion aufzurufen, die den Titel des Buches anhand der ID zurückgibt, führen Sie die folgenden Schritte aus:
    String bookName = (String)session.createSQLQuery("{? = call get_book_name_by_id (:id)}").setLong("id",1).uniqueResult();
    
    Angenommen, wir haben keine Tabelle auf dem Server mit dem Namen Student, aber es gibt nur eine Funktion, die einen Cursor zurückgibt:
    FUNCTION get_all_students
        RETURN SYS_REFCURSOR
    IS
        l_cur   SYS_REFCURSOR;
    BEGIN
        OPEN l_cur FOR
            SELECT *
              FROM student
           ORDER BY 1;
        RETURN l_cur;
    END;
    
    Das Mapping wird dann wie folgt durchgeführt, anstelle der von @Table(name="STUDENT")uns geschriebenen Annotation
    @NamedNativeQuery(name="getAllStudent",query="{? = call get_all_students}", callable=true, resultClass=Student.class)
    Und der Aufruf dieser Funktion lautet wie folgt:
     List student = (List) session.getNamedQuery("entity").list();

    Nun, um unsere save_book-Prozedur aufzurufen, werden wir die folgenden Manipulationen durchführen:
    CallableStatement st = session.connection().prepareCall("{call save_book(?,?,?)}");
    			st.setLong(1,0);
    			st.setString(2, "Золотой ключик, или Приключения Буратино");
    			st.setString(3,"повесть-сказка Алексея Николаевича Толстого");
    			st.registerOutParameter(1, java.sql.Types.NUMERIC);
    			st.execute();
    System.out.println(st.getLong(1));
    
    Wie Sie wahrscheinlich bemerkt haben, wurde beim Schreiben von Befehlen für den Zugriff auf die Datenbank und zum Auffüllen der Auflistung die Wortsitzung verwendet. In unserem Fall gibt dieses Wort die Hauptschnittstelle zwischen unserer Java-Anwendung und dem Hibernate-Framework an, d. H. Org.hibernate.Session-Sitzung. Aber zuerst müssen wir eine andere grundlegende und wichtige Schnittstelle verwenden - SessionFactory. SessionFactory ist die globale Factory, die für eine bestimmte Datenbank verantwortlich ist. Um diese Factory zu erhalten, benötigen wir eine Instanz der org.hibernate.cfg.Configuration-Klasse. Dies geschieht wie folgt:
     SessionFactory sessions = new Configuration().configure().buildSessionFactory();
    
    Dabei analysiert Configuration (). Configure (). BuildSessionFactory () eine Datei mit dem Namen hibernate.cfg.xml, die sich neben dem aufgerufenen Programm befindet, wenn der Pfad nicht angegeben ist. Hier ist die Konfigurationsdatei, die die Konfiguration der Verbindung zur Datenbank und die Anzeige unserer Tabellen zeigt:
     
    
    
        
             oracle.jdbc.driver.OracleDriver
            jdbc:oracle:thin:@localhost:port:baseName
            username
            password
            org.hibernate.dialect.Oracle10gDialect
            true
            
                    
        
    
    Und jetzt, wenn wir eine Fabrik haben, in der es alle erforderlichen Konfigurationen gibt (Verbindung zur Datenbank über den Pool, Zuordnung / Anzeige von Tabellen usw.), können wir mit Session arbeiten
    Session session = sessions.openSession();
    Sie können auf diese Weise mit Transaktionen arbeiten: session.beginTransaction();und dementsprechend session.getTransaction().commit();
    scheint es alles zu sein. Natürlich konnte ich nicht alles abdecken, aber ich denke, das reicht für einen schnellen Start.

    Jetzt auch beliebt: