Spring Boot + Spring Data JPA + Transaktionen, die nicht richtig funktioniert
Habe ich eine Spring-Boot-Anwendung mit version 1.2.0 mit spring-boot-starter-data-jpa, und ich bin mit MySQL.
Ich so konfiguriert haben, dass meine MySQL-Eigenschaften in der Anwendung.Eigenschaften-Datei korrekt.
Habe ich eine einfache JPA Entität, Spring Data JPA-Repository und ein Service, wie folgt:
@Entity
class Person
{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
//setters & getters
}
@Repository
public interface PersonRepository extends JpaRepository<Person, Integer>{
}
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
class PersonService
{
@Autowired PersonRepository personRepository;
@Transactional
void save(List<Person> persons){
for (Person person : persons) {
if("xxx".equals(person.getName())){
throw new RuntimeException("boooom!!!");
}
personRepository.save(person);
}
}
}
Habe ich die folgenden JUnit-test:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class ApplicationTests {
@Autowired
PersonService personService;
@Test
public void test_logging() {
List<Person> persons = new ArrayList<Person>();
persons.add(new Person(null,"abcd"));
persons.add(new Person(null,"xyz"));
persons.add(new Person(null,"xxx"));
persons.add(new Person(null,"pqr"));
personService.save(persons);
}
}
Die Erwartung hier ist sollte man es nicht einfügen aller Datensätze in die Tabelle PERSON, wie Sie werfen eine Ausnahme beim einfügen von 3rd-person-Objekt.
Aber es ist nicht immer rückgängig gemacht, die ersten 2 Platten werden immer eingesetzt und engagiert.
Dann dachte ich schnell versuchen, mit den JPA-EntityManager.
@PersistenceContext
private EntityManager em;
em.save(person);
Dann bin ich immer javax.die Persistenz.TransactionRequiredException: Keine transactional EntityManager zur Verfügung Ausnahme.
Nach googeln irgendwann stoße ich auf dieses JIRA-thread https://jira.spring.io/browse/SPR-11923 zum gleichen Thema.
Dann ich aktualisiert die Spring-Boot-version zu 1.1.2 zu bekommen, Spring-version, die älter als 4.0.6.
Dann em.save(person) wie erwartet funktioniert und die Transaktion ist in Ordnung (d.h. es ist rollbacking alle db-Einsätze, wenn RuntimeException aufgetreten).
Aber auch mit Feder 4.0.5 + Spring Data JPA-1.6.0-Versionen-Transaktionen werden nicht arbeiten, wenn personRepository.save(person) statt em.persist(person).
Scheint es, Spring Data JPA-repositories Begehen die Transaktionen.
Was bin ich? Wie stellen Sie Service-level - @Transactional Anmerkungen arbeiten?
PS:
Maven pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sivalabs</groupId>
<artifactId>springboot-data-jpa</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot-data-jpa</name>
<description>Spring Boot Hello World</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.0.RELEASE</version>
<relativePath />
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<start-class>com.sivalabs.springboot.Application</start-class>
<java.version>1.7</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
</project>
Application.java
@EnableAutoConfiguration
@Configuration
@ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
- Post Ihre Anwendung Klasse und maven-pom. Die Spring-Boot-version, die Sie verwenden sollten, verwenden Sie Spring 4.1.x und nicht etwas altes, wenn es gibt eine andere version in es Sie wahrscheinlich haben einige seltsame Abhängigkeiten in der Liste.
- Hinzugefügt pom.xml und Application.java
- Machen Sie Ihre
PersonService
public
sowie die Methode, die Sie aufrufen. - Vielen Dank Deinum. Öffentlich zu machen, war der trick. Verbrachte einige Stunden ziehen meine Haare 🙁 Bitte legen Sie es als Antwort, ich werde akzeptieren.
- BTW, wie man mit javax.die Persistenz.TransactionRequiredException: Keine transactional EntityManager verfügbar Ausnahme?
- Es bekam. Indem Sie eine öffentliche Methode läuft es im Transaktionalen Kontext und ich will nicht, dass Ausnahme.
- Machen Sie die Klasse und die Methode der öffentlichen arbeitete für mich auch. Sie sollten den Entwurf als eine Antwort!
Du musst angemeldet sein, um einen Kommentar abzugeben.
Vom Kommentar von @m-deinum:
Scheint dies bereits getan haben den trick für mehrere Benutzer. Das gleiche ist auch bedeckt in diese Antwort, unter Berufung auf Handbuch sagen:
Ändern Transactional annotation zu
@Transactional(rollbackFor=Exception.class)
@Transactional
im repository war bisher unnötig war, wenn ich die Entwicklung mit dem Spring automatisch konfiguriertEntityManagerFactory
aber jetzt, dass ich mich geändert habe, um mir diese Anmerkung ist notwendig, #SpringVoodooGetestet habe ich diese mit SpringBoot v1.2.0 und v1.5.2 und alles funktioniert wie erwartet, Sie brauchen nicht zu verwenden entity-manager weder @Transactional(rollbackFor=Exception.class).
Konnte ich nicht sehen, welcher Teil, den Sie falsch konfiguriert wird, scheint alles in Ordnung auf den ersten Blick, also ich bin gerade posten meine config als Referenz mit mehr aktualisiert, Anmerkungen und H2 embedded-memory-DB:
Anwendung.Eigenschaften
pom.xml
Person.java
PersonRepository.java
PersonService.java
Application.java
PersonServiceTest.java
*Die Datenbank wird gelöscht und neu initialisiert werden für jeden test, so dass wir immer validieren gegen einen bekannten Zustand