Reputation: 49077
I have used Java EE 6 before and I have created a connection resource (pooled) on the server and then bound it to a JNDI name which I have referenced inside the jta-data-source
element tag in the Persistence.xml file.
Now I use Spring 3 and I have a hard time understanding all the different beans that I need to set up and why need to do so. EJB 3 automatically wrap the methods in transactions. In Spring it seems like you need to configure a transaction manager, however I don't know. Need explanation.
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/myapp" expected-type="javax.sql.DataSource"/>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="packagesToScan" value="com.myapp.app"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.PostgreSQL82Dialect
</prop>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />
I understand the jndi lookup for the data source, however I don't understand the rest thourougly. I am not able to insert/persist objects with this configuration.
I need an explanation on how Spring 3 differs from Java EE 6 in this area, and how to do it the same way.
Upvotes: 0
Views: 1067
Reputation: 473
After thinking a little more on your original question, I'd like to add:
Spring doesn't automatically wrap every method with a Transaction. You have to tell Spring where you want your Transactional Boundaries to be. You do that with either XML config or by using the @Transactional annotation.
You should have a look at where you should declare transactions - here and here.
You should have a look at Spring's Transaction Management - here.
You should have a look at Transaction Config - here.
I am still of the opinion that your config is good and that the trouble you are having lies within the beans attempting to use your EntityManager. I renew my request for you to post that, as I'm certain I could get you going if I could see it.
I've looked at your configuration and I can't find anything wrong with it. As an example, I will provide (at the bottom) something I have in a working application right now.
I don't believe your problem is within your configuration, but in your usage of the configured beans. If you could provide code showing me (us) how you are interacting with your EntityManager, I could probably identify your issue(s).
I'll provide you with working examples of a Entity, Repository, and XML Config to try and help you locate your issue:
Spring Config (applicationContext.xml)
<?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:p="http://www.springframework.org/schema/p"
xmlns:jee="http://www.springframework.org/schema/jee"
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-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config />
<context:component-scan base-package="com.company.app.dao" />
<context:component-scan base-package="com.company.app.service" />
<jee:jndi-lookup id="dataSource"
jndi-name="jdbc/Test" />
<bean id="jpaDialect"
class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<bean id="jpaAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
<bean id="entityManager" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaAdapter" />
<property name="jpaDialect" ref="jpaDialect" />
<property name="packagesToScan" value="com.company.app.model" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManager" />
<tx:annotation-driven transaction-manager="transactionManager"
proxy-target-class="true" />
</beans>
Model
import org.hibernate.validator.constraints.Length;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@Entity
public class User {
@Id
private String id = UUID.randomUUID().toString();
@Column
@Length(min = 3, max = 25)
private String name;
@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER, orphanRemoval = true)
@JoinColumn(name = "userId", nullable = false)
private Set<Contact> contacts = new HashSet<Contact>();
public UUID getId() {
return UUID.fromString(id);
}
public void setId(UUID id) {
this.id = id.toString();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Contact> getContacts() {
return contacts;
}
public void setContacts(Set<Contact> contacts) {
this.contacts = contacts;
}
public void addContact(Contact contact) {
this.contacts.add(contact);
}
public void removeContact(Contact contact) {
this.contacts.remove(contact);
}
}
Repository
import com.company.app.model.User;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaQuery;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@Repository
public class UserDao {
@PersistenceContext
private EntityManager em;
@Transactional(propagation = Propagation.REQUIRED)
public void createUser(User user) {
em.persist(user);
}
@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
public User readUserById(UUID id) {
CriteriaQuery<User> query = em.getCriteriaBuilder().createQuery(User.class);
query.where (em.getCriteriaBuilder().equal(query.from(User.class).get("id"),id.toString()));
return em.createQuery(query).getSingleResult();
}
@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
public Set<User> readAll() {
CriteriaQuery<User> query = em.getCriteriaBuilder().createQuery(User.class);
query.from(User.class);
return new HashSet<User>(em.createQuery(query).getResultList());
}
@Transactional(propagation = Propagation.REQUIRED)
public User update(User user) {
return em.merge(user);
}
@Transactional(propagation = Propagation.REQUIRED)
public void delete(User user) {
em.remove(user);
}
}
Upvotes: 2