PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Hibernate-Problem


michl
2007-11-25, 13:57:42
Hi!

Ich habe ein Problem mit Hibernate und zwar werden nicht alle Datensätze in einer HSQLDB gespeichert. Im konkreten Fall nur 96 statt 100.

Das Problem liegt anscheined, dass zwischen dem commit einer Transaction und dem close() der Session ein paar Sekunden vergehen müssen.
Erst dann werden die letzten Datensätze geschrieben.
Kann man so einen Timeout konfigurieren oder liegt das Problem wo anders?

Bin für jeden Tipp dankbar.

Michl

Mein Code:

import java.io.IOException;
import java.util.Calendar;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;


public class TestWorkingTime {

public static void main(String[] args) {
AnnotationConfiguration configuration = new AnnotationConfiguration();
configuration.configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
for (int i=0; i<100; i++) {
WorkingTime wt = new WorkingTime();
wt.setDate(Calendar.getInstance().getTime());
session.save(wt);
}
try {
transaction.commit();
System.in.read();
session.close();
sessionFactory.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}


Mein hibernate-Config:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>

<!-- Database connection settings -->
<property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="connection.url">jdbc:hsqldb:file:myhibdb</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>

<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>

<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.HSQLDialect</property>

<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>

<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>

<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>

<property name="hibernate.format_sql">true</property>

<!-- Auflistung der gemappten Klassen -->
<mapping class="WorkingTime"/>


</session-factory>

</hibernate-configuration>

Ectoplasma
2007-11-25, 17:56:35
Wie sieht denn das Objekt WorkingTime aus?

Und nur mal so zum Style deines Programms. Der Try/Catch Block ist nicht sauber plaziert. Ich würde das so schreiben:


import java.io.IOException;
import java.util.Calendar;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;


public class TestWorkingTime {

public static void main(String[] args) {
SessionFactory sessionFactory = null;
Session session = null;
Transaction transaction = null;

try {
configuration = new AnnotationConfiguration();
configuration.configure();
sessionFactory = configuration.buildSessionFactory();
session = sessionFactory.openSession();
transaction = session.beginTransaction();

for (int i = 0; i < 100; ++i) {
WorkingTime wt = new WorkingTime();

wt.setDate(Calendar.getInstance().getTime());
session.save(wt);
}

transaction.commit();
} catch (Exception e) {
e.printStackTrace();
if (transaction != null) {
transaction.rollback();
}
} finally {
if (session != null) {
session.clode();
}
if (sessionFactory != null) {
sessionFactory.close();
}
}
}

}


Welchen Primärschlüssel hast du?

registrierter Gast
2007-11-25, 19:30:37
omg, muss man sich bei Hibernate echt mit so einem Scheiß wie Sessions und Transactions rumschlagen? Das ist ja übel und hätte ich von einem so bekannten ORM nicht erwartet.
Neben der Empfehlung das ORM zu wechseln und ein ordentliches zu verwenden, kann ich jetzt nur das wiedergeben, was ich in der Anleitung von Hibernate entdeckt habe.
Bei langen/großen Transaktionen ist es anscheinend notwendig (lol @ hibernate ;D), die Session zu flushen und anschließend zu clearen.

Füge also
session.flush();
session.clear(); vor dem commit und nach der Schleife hinzu.
Und die for-Schleife würde ich persönlich so gestalten:
Date date = new Date();
for (int i = 101; --i > 0;) {
WorkingTime wt = new WorkingTime();

wt.setDate(date);
session.save(wt);
}

michl
2007-11-25, 21:24:09
Wie sieht denn das Objekt WorkingTime aus?

Und nur mal so zum Style deines Programms. Der Try/Catch Block ist nicht sauber plaziert.

Welchen Primärschlüssel hast du?

Danke für die Anmerkung mit dem try/catch-Block.
Der Code der WorkingTime-Klasse.


import java.util.Date;

import javax.persistence.*;

@Entity
public class WorkingTime {

private Integer id;
private Date date;
private Date kommt;
private Date geht;
private Date working;

public WorkingTime() {}

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getId() {
return id;
}

public Date getDate() {
return date;
}

public void setDate(Date date) {
this.date = date;
}

public Date getKommt() {
return kommt;
}

public void setKommt(Date kommt) {
this.kommt = kommt;
}

public Date getGeht() {
return geht;
}

public void setGeht(Date geht) {
this.geht = geht;
}

public Date getWorking() {
return working;
}

public void setWorking(Date working) {
this.working = working;
}

public void setId(Integer id) {
this.id = id;
}
}

michl
2007-11-25, 21:26:00
Die Sache mit flush() habe ich schon probiert. Leider kein Erfolg.

omg, muss man sich bei Hibernate echt mit so einem Scheiß wie Sessions und Transactions rumschlagen? Das ist ja übel und hätte ich von einem so bekannten ORM nicht erwartet.
Neben der Empfehlung das ORM zu wechseln und ein ordentliches zu verwenden, kann ich jetzt nur das wiedergeben, was ich in der Anleitung von Hibernate entdeckt habe.
Bei langen/großen Transaktionen ist es anscheinend notwendig (lol @ hibernate ;D), die Session zu flushen und anschließend zu clearen.

Füge also
session.flush();
session.clear(); vor dem commit und nach der Schleife hinzu.
Und die for-Schleife würde ich persönlich so gestalten:
Date date = new Date();
for (int i = 101; --i > 0;) {
WorkingTime wt = new WorkingTime();

wt.setDate(date);
session.save(wt);
}

Ectoplasma
2007-11-25, 21:51:26
omg, muss man sich bei Hibernate echt mit so einem Scheiß wie Sessions und Transactions rumschlagen? Das ist ja übel und hätte ich von einem so bekannten ORM nicht erwartet.
Neben der Empfehlung das ORM zu wechseln und ein ordentliches zu verwenden, kann ich jetzt nur das wiedergeben, was ich in der Anleitung von Hibernate entdeckt habe.
Bei langen/großen Transaktionen ist es anscheinend notwendig (lol @ hibernate ;D), die Session zu flushen und anschließend zu clearen.


Ne, muss man nicht. Es kommt auf die Konfiguration an. Die Transaktion kann auch über AOP gesteuert werden. Da Hibernate im professionellen Umfeld eingesetzt wird, hat man auf jeden Fall Transaktionen. Sorry aber bei deinem Statement muss ich ein wenig den Kopf schütteln. Die Session muss man natürlich nicht flushen. Nach einem Commit sollte in jedem Fall alles geschrieben sein.

Aber ich muss zugeben, dass Hibernate ziemlich buggy ist. Ich arbeite zufällig gerade wieder damit in einem größeren Projekt. Wir arbeiten allerdings mit Weblogic und einem Transaktionsmonitor von Spring.

@Michl
Die Klasse WorkingTime sieht korrekt aus, hmmm. Vielleicht probiere ich morgen einmal deinen Code aus.

michl
2007-11-25, 22:31:07
Danke, für die Antworten, aber ich hab die Lösung gefunden:
Bei der HSQLDB gibt es mehrere Files, darunter eine Datei <dbname>.script
Und die schreibt man

SET WRITE_DELAY 0 MILLIS

Dann klappt's.

Und ein flush() braucht man nicht.

gereggter Gast
2007-11-25, 22:43:01
Ne, muss man nicht. Es kommt auf die Konfiguration an. Die Transaktion kann auch über AOP gesteuert werden. Da Hibernate im professionellen Umfeld eingesetzt wird, hat man auf jeden Fall Transaktionen.
Ich meinte nicht, dass es Transaktionen bei einem ordentlichen ORM nicht geben sollte, sondern dass man sich überhaupt noch darum kümmern muss. Die Verwendung von Transaktionen sollte Standard sein und höchstens durch ein Zusatzflag im Statement abschaltbar sein. Deswegen wundert es mich, dass man sich darüber überhaupt den Kopf zerbrechen muss. Auch das ganze Öffnen und Schließen erinnert mich stark an pures JDBC. Grauenvoll.

Sorry aber bei deinem Statement muss ich ein wenig den Kopf schütteln. Die Session muss man natürlich nicht flushen. Nach einem Commit sollte in jedem Fall alles geschrieben sein.
Habe ich von Hibernates Doku auf deren Seite übernommen. Kapitel 13. Das Kopf schütteln reiche ich also gerne an Hibernate weiter.
Das bei einem commit alle neuen Objekte in die DB geschrieben werden sollte, ist eine Selbstverständlichkeit - steht auch so in Kapitel 13. Das dies aber nicht immer klappt, sieht man ja an dem Problem des TS. Also lieber einmal mehr flushen und Session clearen. Ich hatte gehofft, das Clearen der Session würde den weiteren Programmverlauf stoppen, so dass es erst wieder weiter geht, sobald alle Änderungen geschrieben wurden.

Ganon
2007-11-25, 23:44:37
Neben der Empfehlung das ORM zu wechseln und ein ordentliches zu verwenden

z. B.? :)

gereggter Gast
2007-11-26, 00:09:45
Cayenne würde mir da einfallen.

Damit sähe oben genanntes Programm dann so aus:

try {
DataContext context = DataContext.createDataContext();

Date date = new Date();
for (int i = 101; --i > 0;) {
WorkingTime wt = (WorkingTime) context.createAndRegisterNewObject(WorkingTime.class);
wt.setDate(date);
}
context.commit();
}
catch(CayenneRuntimeException e) {
e.printStackTrace();
}

Durch das Fehlen der ganzen Opener und Closer ist es ein Tick übersichtlicher. Auch im Falle einer Exception braucht man nix zu beachten. Keine Connection zur DB bleibt gelockt.
Dazu noch der einfach zu bedienende Modeller, der es erlaubt, die Entitäten in einer GUI anzulegen und die Objekte dann per Mausklick zu generieren.

Ganon
2007-11-26, 08:49:47
Danke. :)

Ich suche nämlich für ein neues Projekt ein ORM-Framework für Java. Habe mir schon das Hibernate-Buch gekauft und gelesen, aber so wirklich gefallen hat es mir bisher nicht so.

Mal das angucken :)

Ganon
2007-11-28, 12:57:39
Übrigens hab ich gerade in der Cayenne-Wiki vllt. eine bessere Lösung für dein Problem gefunden:

http://cwiki.apache.org/CAY/hsqldb-shutdown.html

Also mehr ein HSQLDB-Problem, anstatt eines von Hibernate.