3 Stimmen

JPA - Transaktionen werden nicht übertragen

Ich arbeite an einem Projekt, in dem ich JPA, Hibernate und all dieses Zeug zum ersten Mal verwenden, und ich lief in Problem mit Transaktionen nicht festgelegt werden. Ich verwende die Klasse User, die wie folgt aussieht:

 package org.tomasherman.JBTBackup.Resource.Entity;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Table(name = "users")
public class User implements Serializable {
    @Id
    @GeneratedValue
    private int id;

    private String login;
    private String email;
    private String password;
    private int credit;

    public User() {
    }

    public User(String login, String email, String password, int credit) {
        setLogin(login);
        setEmail(email);
        setPassword(password);
        setCredit(credit);
    }

    public int getId() {
        return id;
    }

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

    public String getLogin() {
        return login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getCredit() {
        return credit;
    }

    public void setCredit(int credit) {
        this.credit = credit;
    }
}

und verwenden Sie die HSQL-Datenbank, um sie in der Tabelle MEMORY zu speichern. Die Datei persistence.xml sieht wie folgt aus:

<?xml version="1.0" encoding="UTF-8"?>

<persistence-unit name="JBTBackupPersistance">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>org.tomasherman.JBTBackup.Resource.Entity.User</class>
    <properties>
        <property name="hibernate.connection.url" value="jdbc:hsqldb:file:./database/database.hsql"/>
        <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
        <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
        <property name="hibernate.connection.username" value="SA"/> <!--default hsql login-->
        <property name="hibernate.connection.password" value=""/>
        <property name="hibernate.archive.autodetection" value="class"/>
        <property name="hibernate.show_sql" value="true"/>
        <property name="hibernate.format_sql" value="true"/>
        <property name="connection.shutdown" value="true"/>
    </properties>
</persistence-unit>

und testen Sie es in einem JUnit-Test, der wie folgt aussieht:

package org.tomasherman.JBTBackup.Resource.Entity;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

/**
 * Created by IntelliJ IDEA.
 * User: arg
 * Date: Jun 29, 2010
 * Time: 11:24:35 PM
 * To change this template use File | Settings | File Templates.
 */

public class UserTest {
    private EntityManagerFactory emf;
    private EntityManager em;

    private final User u1 = new User("and","now","for",1234);
    private final User u2 = new User("something","completely","different",123123123);
    private final User u3 = new User("a","man","with",123123123);

    @Before
    public void initEmfAndEm() {
        emf = Persistence.createEntityManagerFactory("JBTBackupPersistance");
        em = emf.createEntityManager();
    }

    @After
    public void cleanup() {
        em.close();
    }

    @Test
    public void emptyTest() {
        System.out.println(em.createQuery("from User").getResultList().size());
        if(em.getTransaction().isActive()){
            System.out.println("FFfffffffffFFFFUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU");
            System.out.println("FFfffffffffFFFFUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU");
            System.out.println("FFfffffffffFFFFUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU");
            System.out.println("FFfffffffffFFFFUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU");
            System.out.println("FFfffffffffFFFFUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU");
        }else{
            em.getTransaction().begin();
            em.persist(u1);
            em.persist(u2);
            em.persist(u3);         
        em.getTransaction().commit();
        }
        System.out.println(em.createQuery("from User").getResultList().size());

    }
}

Das Problem ist nun, dass die Einfügung oft nicht in die Datenbank geschrieben wird. Die Ausgabe des Tests sieht wie folgt aus:

    ...some hibernate stuff...
Hibernate: 
    select
        user0_.id as id0_,
        user0_.credit as credit0_,
        user0_.email as email0_,
        user0_.login as login0_,
        user0_.password as password0_ 
    from
        users user0_
20
Hibernate: 
    insert 
    into
        users
        (id, credit, email, login, password) 
    values
        (null, ?, ?, ?, ?)
Hibernate: 
    insert 
    into
        users
        (id, credit, email, login, password) 
    values
        (null, ?, ?, ?, ?)
Hibernate: 
    insert 
    into
        users
        (id, credit, email, login, password) 
    values
        (null, ?, ?, ?, ?)
Hibernate: 
    select
        user0_.id as id0_,
        user0_.credit as credit0_,
        user0_.email as email0_,
        user0_.login as login0_,
        user0_.password as password0_ 
    from
        users user0_
23

Die Entites sind also im Speicher der Datenbank, aber wenn ich die Datenbank nach dem Unit-Test überprüfe, sind keine Daten vorhanden. Es wird jedoch von Zeit zu Zeit übertragen.

Wenn mir jemand helfen könnte, wäre das fantastisch.

EDIT: für den Fall, dass es jemandem helfen würde, gibt es eine Liste der Bibliotheksversionen (im Maven-Format):

<dependency>
      <groupId>javax.transaction</groupId>
      <artifactId>jta</artifactId>
      <version>1.1</version>
  </dependency>
  <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.6.0</version>
  </dependency>
  <dependency>
      <groupId>commons-collections</groupId>
      <artifactId>commons-collections</artifactId>
      <version>20040616</version>
  </dependency>
  <dependency>
      <groupId>org.hsqldb</groupId>
      <artifactId>hsqldb</artifactId>
      <version>2.0.0</version>
  </dependency>
  <dependency>
      <groupId>hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>
      <version>3.4.0.GA</version>
  </dependency>
  <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-simple</artifactId>
      <version>1.6.0</version>
  </dependency>
  <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-search</artifactId>
      <version>3.1.0.GA</version>
  </dependency>
  <dependency>
      <groupId>hibernate</groupId>
      <artifactId>hibernate</artifactId>
      <version>3.0.5</version>
  </dependency>
  <dependency>
      <groupId>javax.persistence</groupId>
      <artifactId>persistence-api</artifactId>
      <version>1.0</version>
  </dependency>

UPDATE2: Eine weitere interessante Sache, es scheint, dass wenn ich Thread.sleep(1000); am Ende des Tests hinzufüge, alle Transaktionen übertragen werden. Könnte es sein, dass das Programm schneller beendet wird, als die Datenbank aktualisiert werden kann?

2voto

Pascal Thivent Punkte 548176

Gemäß dem Benutzerhandbuch von HSQLDB:

Schließen der Datenbank

Ab Version 1.7.2 werden die in Bearbeitung befindlichen Datenbanken nicht mehr geschlossen, wenn die letzte Verbindung zur Datenbank explizit über JDBC geschlossen wird [und Daten nicht auf die Festplatte geschrieben werden], eine explizite SHUTDOWN ist erforderlich [in um die Daten beständig zu halten]. In 1.8.0 eine Verbindungseigenschaft, shutdown=true kann angegeben werden auf der ersten Verbindung zur Datenbank (die Verbindung, die die Datenbank öffnet), um ein Herunterfahren zu erzwingen, wenn die letzte Verbindung geschlossen wird.

Schicken Sie also entweder das SHUTDOWN Befehl durch eine native Abfrage oder Hinzufügen ;shutdown=true in die Verbindungszeichenfolge einfügen:

jdbc:hsqldb:file:./database/database.hsql;shutdown=true

Bezüglich der Frage nach write_delay nein, die Einstellung auf 0 wird in einem Unit-Testing-Kontext kein Problem verursachen (es hat "nur" Auswirkungen auf die Leistung). Eigentlich hätte ich erwartet, dass shutdown=true wie in der Dokumentation erwähnt, ausreichen:

Anwendungsentwicklung und -prüfung

...

Wenn Sie keine Server-Instanz betreiben wollen Instanz betreiben wollen und Persistenz benötigen zwischen Tests in verschiedenen Prozessen benötigen, dann sollten Sie eine file: Datenbank. Sie können die shutdown=true Verbindungseigenschaft zu sicherzustellen, dass die Datenbank vollständig persistiert wird nachdem die Verbindungen geschlossen wurden. Eine alternative Möglichkeit ist die Verwendung von hsqldb.write_delay=false Verbindung Eigenschaft, die jedoch etwas langsamer ist als die andere Option.

Es wurde berichtet, dass einige Daten Datenzugriffs-Frameworks nicht alle ihre Verbindung zur Datenbank nach den den Tests. In solchen Situationen müssen Sie müssen Sie null WRITE DELAY verwenden, wenn Sie die Daten am Ende der Tests erhalten bleiben sollen der Tests

Aber ich vermute, dass Sie sich in der im zweiten Absatz beschriebenen Situation befinden. Ich frage mich allerdings, ob die Datenzugriffsschicht wirklich schuldig ist.

0voto

Andy Punkte 13487

Anstelle des Aufrufs em.getTransaction() zweimal aufzurufen, müssen Sie sie einmal aufrufen und den Verweis auf sie speichern. Jedes Mal, wenn Sie die Funktion aufrufen, erhalten Sie eine neu Transaktion. Sie starten also eine Transaktion und führen dann eine weitere durch.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X