Spring Data JPA Transaction wird nicht erstellt


#1

Hallo,

ich stehe vor dem Problem, dass ich versuche eine Spring MVC Anwendung mit Derby als Datenbank und JPA (EclipseLink) zu konfigurieren. Transaktionen sollen über die @Transactional Spring Annotation abgebildet werden. Leider schaffe ich es nicht, dass eine neue Transaktion eröffnet wird. Der Schreibversuch erhält also kein Commit und die Abfrage ergibt danach eine Leere Liste. Wenn ich versuche EntityManager#flush() aufzurufen erhalte ich den Fehler, dass keine Transaktion verfügbar ist.

Spring configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
	                    http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
	                    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
	                    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

	<!-- Root Context: defines shared resources visible to all other web components -->

	<context:component-scan base-package="de.tms.ew" />
	<context:annotation-config />

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="derbyDB" />
		<property name="jpaProperties">
			<props>
				<prop key="eclipselink.target-database">Derby</prop>
				<prop key="eclipselink.ddl-generation">drop-and-create-tables</prop>
				<prop key="eclipselink.debug">ALL</prop>
				<prop key="eclipselink.weaving">static</prop>
				<prop key="eclipselink.logging.level">FINEST</prop>
				<prop key="eclipselink.logging.level.sql">FINEST</prop>
				<prop key="eclipselink.logging.level.cache">FINEST</prop>
			</props>
		</property>
		<property name="jpaVendorAdapter">
			<bean
				class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
			</bean>
		</property>
	</bean>

	<jdbc:embedded-database id="derbyDB" type="DERBY" />
	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>
	<tx:annotation-driven transaction-manager="transactionManager" mode="aspectj" />
</beans>

JPA-Entity:

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Data;

@Data
@Entity
@Table(name = "EW_GRILS")
public class Girl {

	@Id
	private String name;
	@Column(name = "DESCRIPTION")
	private String description;
	private int age;
	private int size;
	private int weight;
}```

**Controller:**
```import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;

import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import de.tms.ew.model.Girl;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {

	@PersistenceUnit
	private EntityManagerFactory emf;

	@RequestMapping(value = "/", method = RequestMethod.GET)
	@ResponseBody
	public String home() {

		Girl girl = new Girl();
		girl.setName("Marie");
		saveGirl(girl);
		return findAllGirls(girl) + "";
	}

	@Transactional
	public void saveGirl(Girl g) {
		EntityManager em = emf.createEntityManager();
		em.persist(g);
	}

	@SuppressWarnings("unchecked")
	public List<Girl> findAllGirls() {
		EntityManager em = emf.createEntityManager();

		return em.createQuery("from Girl g").getResultList();

	}

}

#2

Kannst du bitte deine persistence.xml auch noch posten?


#3

Sehr gern:


<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
	xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
	<persistence-unit name="ewsite">
	</persistence-unit>
</persistence>


#4

Ich seh’ den Thread leider erst jetzt. Ist das gewollt, dass Du einen PersistenceContext injizierst? Der dient in erster Linie zum Lifecycle Management von EntityManagern. Diese erzeugst Du in Deinem Controller immer neu und dann bekommen die neuen Instanzen von der Transaction nichts mit.

Hol’ Dir doch den EntityManager selbst:@PersistenceContext(unitName="ewsite") EntityManager entityManager;.

Es gibt auch die Möglichkeit, in die Transaktion mittels joinTransaction() einzusteigen.

em.joinTransaction();```