Updated entity not being retrieved correctly - spring

I have a spring mvc application running on glassfish. I don't know the source of my problem so ill elaborate as much as possible. I have 2 Classes
A User Class
#Entity
#Table(name="Users")
public class User extends BaseEntity<User> {
// other fields
#OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
#OrderBy(value = "id DESC")
private Set<OtherClass> objs;
// getters and setters
}
and an OtherClass:
#Entity
#Table(name="OtherObjects")
public class OtheClass extends BaseEntity<OtheClass> {
// other fields
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "User", nullable = false)
private User user;
// getters and setters
}
i retrieve a user object when the application starts and put it in the session object. while runtime, the user can add to the DB a "OtherClass" object. the otherClass object is saved correctly in the DB (with a relation to the correct user row in the Users table). the thing is that after the user added the otherClass object at runtime, the Set of other objects doesn't update. the weirder thing is that even if i retrieve the user object from the DB again, i don't get the updated Set of OtherClass.
This is my persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence 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"
version="2.0">
<persistence-unit name="myPU" transaction-type="JTA">
<jta-data-source>jdbc/MyDataSource</jta-data-source>
<class>org.company.entities.OtherClass</class>
<class>org.company.entities.User</class>
<exclude-unlisted-classes />
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.current_session_context_class" value="thread" />
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider" />
<property name="hibernate.hbm2ddl.auto" value="create" />
</properties>
</persistence-unit>
</persistence>
I recently changed my transaction manager from the jpa transaction manager of spring to JTA transaction manager. (i suppose it has something to do with it). Any ideas? if further code or configuration is required, please tell and i'll post an update.

JPA doesn't maintain bidirectional associations automatically, it's up to the developer to update both sides of the relationship. In this case upon creating the OtherClass object you should add it to the objs collection in the User object.

Related

Unable to delete row : TransactionRequiredException: Executing an update/delete query

There are several posts on this question but still not getting the solution.
This the parent class Userr.
In a #OneToMany relationship I want to remove a particular child Account.
Now When I do this by "DELETE" query I am getting following exception.
org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query
#RooJavaBean
#RooToString
#RooJpaEntity
#RooJpaActiveRecord(finders = { "findUserrsByUserName"})
public class Userr {
#NotNull
#Column(unique = true)
private String userName;
#NotNull
private int userType;
#OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Account> accounts = new ArrayList<Account>();
}
Child class
#RooJavaBean
#RooToString
#RooJpaActiveRecord
#RooJpaEntity
public class Account {
#OneToMany(mappedBy="account", fetch=FetchType.LAZY, cascade = CascadeType.ALL)
List<Message> messages = new ArrayList<Message>();
/*#OneToMany(mappedBy="account", fetch=FetchType.LAZY, cascade = CascadeType.ALL)
List<PremiumPlayPositionCombination> premiumPlayPosition = new ArrayList<PremiumPlayPositionCombination>();*/
#OneToMany(mappedBy="account", fetch=FetchType.LAZY, cascade = CascadeType.ALL)
List<PositionCombinationArc> allPositionsArc = new ArrayList<PositionCombinationArc>();
#ManyToOne
#JoinColumn(name="user_id")
private Userr user;
}
Here is my delete query
#Transactional
public static void deleteClientByClientId(Long clientId) {
System.out.println("Delete query findUsersClientsByUser" + clientId);
int deleteCount= entityManager().createQuery("DELETE FROM Account where id =:clientId").setParameter("clientId", clientId).executeUpdate();
System.out.println("Delete query findUsersClientsByUser" + deleteCount);
}
I have added in ApplicationContext-security.xml like this
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!--
This will automatically locate any and all property files you have
within your classpath, provided they fall under the META-INF/spring
directory. The located property files are parsed and their values can
then be used within application context files in the form of
${propertyKey}.
-->
<context:property-placeholder location="classpath*:META-INF/spring/*.properties"/>
<!--
Turn on AspectJ #Configurable support. As a result, any time you
instantiate an object, Spring will attempt to perform dependency
injection on that object. This occurs for instantiation via the "new"
keyword, as well as via reflection. This is possible because AspectJ
is used to "weave" Roo-based applications at compile time. In effect
this feature allows dependency injection of any object at all in your
system, which is a very useful feature (without #Configurable you'd
only be able to dependency inject objects acquired from Spring or
subsequently presented to a specific Spring dependency injection
method). Roo applications use this useful feature in a number of
areas, such as #PersistenceContext injection into entities.
-->
<context:spring-configured/>
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.gmail.com"/>
<property name="port" value="587"/>
<property name="username" value="noreply#uforic.in"/>
<property name="password" value="noreply#123"/>
<property name="javaMailProperties">
<props>
<prop key="mail.transport.protocol">smtp</prop>
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.starttls.enable">true</prop>
<prop key="mail.debug">true</prop>
</props>
</property>
</bean>
<!--
This declaration will cause Spring to locate every #Component,
#Repository and #Service in your application. In practical terms this
allows you to write a POJO and then simply annotate the new POJO as an
#Service and Spring will automatically detect, instantiate and
dependency inject your service at startup time. Importantly, you can
then also have your new service injected into any other class that
requires it simply by declaring a field for your service inside the
relying class and Spring will inject it. Note that two exclude filters
are declared. The first ensures that Spring doesn't spend time
introspecting Roo-specific ITD aspects. The second ensures Roo doesn't
instantiate your #Controller classes, as these should be instantiated
by a web tier application context. Refer to web.xml for more details
about the web tier application context setup services.
Furthermore, this turns on #Autowired, #PostConstruct etc support. These
annotations allow you to use common Spring and Java Enterprise Edition
annotations in your classes without needing to do any special configuration.
The most commonly used annotation is #Autowired, which instructs Spring to
dependency inject an object into your class.
-->
<context:component-scan base-package="com.uforic.optionstrader">
<context:exclude-filter expression=".*_Roo_.*" type="regex"/>
<!--context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/-->
</context:component-scan>
You can check following things in your code:
If you are using spring based transaction then make sure you import org.springframework.transaction.annotation.Transactional class for #Transactional annotation
In your case it might be javax.transaction.Transactional
I see deleteClientByClientId method in your code as static. #Transactional in spring does not have support for static methods. Make your method non static which is annotated as transactional.
You can refer #Transactional with static method
Let me know, which option works for you.
In Spring context file you need to add below code:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-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.xsd">
<tx:annotation-driven />
Also, add your spring security bean configuration.
When trying to update/delete using Hibernate, it is mendatory to surround the query by a transaction Begin() and Commit() example :
EntityTransaction tr=em.getTransaction();
tr.begin();
Query query = (Query) em.createQuery( "update etudiant set email= :em, adresse= :adr,telephone= :tele,password= :pwd"
+ " where email= :mail");
query.setParameter("em", email)
.setParameter("adr", adresse)
.setParameter("tele", tele)
.setParameter("pwd", pass)
.setParameter("mail", ancienEmail);
int a= query.executeUpdate();
tr.commit();

Spring MVC + Hibernate: could not initialize proxy - no Session

Note: See my own answer to this question for an example of how I solved this issue.
I am getting the following exception in my Spring MVC 4 + Hibernate 4 project:
org.hibernate.LazyInitializationException: failed to lazily initialize
a collection of role: com.mysite.Company.acknowledgements, could not
initialize proxy - no Session
After reading a lot of other questions about this issue, I understand why this exception occurs, but I am not sure how to fix it in a good way. I am doing the following:
My Spring MVC controller calls a method in a service
The service method invokes a method in a DAO class
The method in the DAO class fetches an entity object through Hibernate and returns it to the calling service
The service returns the fetched object to the controller
The controller passes the object to the view (JSP)
The view tries to iterate on a many-to-many association that is lazily loaded (and is thus a proxy object)
The exception is thrown because the session is closed at this point, and the proxy cannot load the associated data
I have previously worked with PHP and doctrine2, and this way of doing things caused no problems. I am trying to figure out the best way to solve this, because the solutions that I found so far don't seem so great:
Load the association eagerly, potentially loading lots of unnecessary data
Call Hibernate.initialize(myObject.getAssociation()); - this means that I have to loop through associations to initialize them (I guess), and just the fact that I have to do this, kind of makes the lazy loading less neat
Using a Spring filter to leave the session open in the views, but I doubt that this is a good thing to do?
I tried to use #Transactional in my service, but without luck. This makes sense because I am trying to access data that has not yet been loaded after my service method returns. Ideally I would like to be able to access any association from within my view. I guess the drawback of initializing the associations within my service is that I have to explicitly define which data I need - but this depends on the context (controller) in which the service is used. I am not sure if I can do this within my controller instead without losing the abstraction that the DBAL layer provides. I hope that makes sense. Either way, it would be great if I didn't have to always explicitly define which data I want to be available to my view, but just let the view do its thing. If that is not possible, then I am just looking for the most elegant solution to the problem.
Below is my code.
View
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<h1><c:out value="${company.name}" /> (ID: <c:out value="${company.id}" />)</h1>
<c:forEach var="acknowledgement" items="${company.acknowledgements}">
<p><c:out value="${acknowledgement.name}" /></p>
</c:forEach>
Controller
#Controller
public class ProfileController {
#Autowired
private CompanyService companyService;
#RequestMapping("/profile/view/{id}")
public String view(Model model, #PathVariable int id) {
Company company = this.companyService.get(id);
model.addAttribute("company", company);
return "viewCompanyProfile";
}
}
Service
#Service
public class CompanyServiceImpl implements CompanyService {
#Autowired
private CompanyDao companyDao;
#Override
public Company get(int id) {
return this.companyDao.get(id);
}
}
DAO
#Repository
#Transactional
public class CompanyDaoImpl implements CompanyDao {
#Autowired
private SessionFactory sessionFactory;
#Override
public Company get(int id) {
return (Company) this.sessionFactory.getCurrentSession().get(Company.class, id);
}
}
Company entity
#Entity
#Table(name = "company")
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
// Other fields here
#ManyToMany
#JoinTable(name = "company_acknowledgement", joinColumns = #JoinColumn(name = "company_id"), inverseJoinColumns = #JoinColumn(name = "acknowledgement_id"))
private Set<Acknowledgement> acknowledgements;
public Set<Acknowledgement> getAcknowledgements() {
return acknowledgements;
}
public void setAcknowledgements(Set<Acknowledgement> acknowledgements) {
this.acknowledgements = acknowledgements;
}
// Other getters and setters here
}
Acknowledgement entity
#Entity
public class Acknowledgement {
#Id
private int id;
// Other fields + getters and setters here
}
mvc-dispatcher-servlet.xml (a part of it)
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">
<list>
<value>com.mysite.company.entity</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven />
Thanks in advance!
As #Predrag Maric said writing service methods with different initialization for entity assotiations might be an option.
OpenSessionInView is a quit discussable pattern, which can be a solution in your case, though.
Another option is to set
<prop key="hibernate.enable_lazy_load_no_trans">true</prop>
property. It is designed to solve org.hibernate.LazyInitializationException problem and is available since hibernate 4.1.6.
So what does this property do? It simply signals Hibernate that it
should open a new session if session which is set inside current
un-initialised proxy is closed. You should be aware that if you have
any other open session which is also used to manage current
transaction, this newly opened session will be different and it may
not participate into the current transaction unless it is JTA. Because
of this TX side effect you should be careful against possible side
effects in your system.
Find more information here: http://blog.harezmi.com.tr/hibernates-new-feature-for-overcoming-frustrating-lazyinitializationexceptions and
Solve Hibernate Lazy-Init issue with hibernate.enable_lazy_load_no_trans
The simplest and most transparent solution is the OSIV pattern. As I'm sure you aware, there is plenty of discussion about this (anti)pattern and the alternatives both on this site and elsewhere so no need to go over that again. For example:
Why is Hibernate Open Session in View considered a bad practice?
However, in my opinion, not all criticisms of OSIV are entirely accurate (e.g. the transaction will not commit till your view is rendered? Really? If you are using the Spring implementation then https://stackoverflow.com/a/10664815/1356423)
Also, be aware that JPA 2.1 introduced the concept of Fetch Graphs which give you more control over what is loaded. I haven't tried it yet but maybe this if finally a solution for this long standing problem!
http://www.thoughts-on-java.org/2014/03/jpa-21-entity-graph-part-1-named-entity.html
For others who are looking for a solution, here is how I solved the problem.
As Alan Hay pointed out, JPA 2.1+ supports entity graphs, which ended up solving my problem. To make use of it, I change my project to use the javax.persistence.EntityManager class instead of the SessionFactory, which would then hand me the current session. Here is how I configured it in my dispatcher servlet configuration (some things excluded):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">
<jee:jndi-lookup id="dataSource" jndi-name="java:/comp/env/jdbc/postgres" expected-type="javax.sql.DataSource"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="dk.better.company.entity, dk.better.user.entity" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven />
</beans>
Below is an example of a DAO class.
#Transactional
public class CompanyDaoImpl implements CompanyDao {
#PersistenceContext
private EntityManager entityManager;
#Override
public Company get(int id) {
EntityGraph<Company> entityGraph = this.entityManager.createEntityGraph(Company.class);
entityGraph.addAttributeNodes("acknowledgements");
Map<String, Object> hints = new HashMap<String, Object>();
hints.put("javax.persistence.loadgraph", entityGraph);
return this.entityManager.find(Company.class, id, hints);
}
}
I found that if I did not use #PersistenceContext but Autowired instead, then the database session was not closed when rendering the view, and data updates were not reflected in subsequent queries.
For more information on entity graphs, I encourage you to read the following articles:
http://www.thoughts-on-java.org/2014/03/jpa-21-entity-graph-part-1-named-entity.html
http://www.thoughts-on-java.org/2014/04/jpa-21-entity-graph-part-2-define.html
My vote goes to Hibernate.initialize(myObject.getAssociation()) in service layer (which also means #Transactional should be moved from DAO to service methods)
IMHO, service methods should return all data that is required by the caller. If the caller wants to display some association on the view, it is service's responsibility to supply that data. This means you could have several methods that apparently do the same thing (return Company instance), but depending on the caller, different associations could be fetched.
On one project we had kind of configuration class, which contained information on what associations should be fetched, and we had a single service method which also accepted that class as a parameter. This approach meant we have only one method which is flexible enough to support all callers.
#Override
public Company get(int id, FetchConfig fc) {
Company result = this.companyDao.get(id);
if (fc.isFetchAssociation1()) {
Hibernate.initialize(result.getAssociation1());
}
...
return result;
}
Trigger in the service layer requires lazy loading of the Set's size method.
Tools:
public class HibernateUtil {
/**
* Lazy = true when the trigger size method is equal to lazy = false (load all attached)
*/
public static void triggerSize(Collection collection) {
if (collection != null) {
collection.size();
}
}
}
in your service method:
Apple apple = appleDao.findById('xxx');
HibernateUtil.triggerSize(apple.getColorSet());
return apple;
then use apple in controller, everything is ok!

JPA + Spring: UnexpectedRollbackException when Transaction is REQUIRED, REQUIRES_NEW or NESTED

I'm doing my first project with Spring, JPA, and GlassFish 3.1 and I'm having some troubles. I've been looking for a solution for a week, but I have found nothing.
I have an Entity (called Role), a GeneralReposiroty with general methods to access any entity, a RoleRepository which implements particular methods about Role, and a Service class, which calls RoleRepository. Methods of Service class are transactional, but I get RollBackException if the propagation property is REQUIRED, REQUIRES_NEW or NESTED. If propagation is MANDATORY, it's thrown an exception saying:
org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:339)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:262)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:101)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
...
If it's NOT_SUPPORTED, NEVER or SUPPORT, select queries work fine, but I get the same RollbackException if I try to execute a create, update or delete query.
I've debugged the select queries, and before they throw the RollBackException, the query gets the result fine, and the exception is thrown just at the end of the function. In adition, if I get the Entities with find() of EntityManager and the service method doesn't have the #Transactional anotation, works fine, but if I make it transactional, it crashes with the same exception.
This happens with all entities I have, but I use that to explain the problem.
I think there is something wrong with my Spring configuration, but I don't know what.
This is the full trace of the exception (In some lines there are references to AuthenticationSuccessHandler class, because it's where I call to the service class from):
WARNING: StandardWrapperValve[default]: PWC1406: Servlet.service() for servlet default threw exception
org.springframework.transaction.UnexpectedRollbackException: JTA transaction unexpectedly rolled back (maybe due to a timeout); nested exception is javax.transaction.RollbackException: Transaction marked for rollback.
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:845)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:662)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:632)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:314)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:116)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
at com.citius.reservas.service.service$$EnhancerByCGLIB$$37b50d4.tryJPAFind(<generated>)
at com.citius.reservas.AuthenticationSuccessHandlerImpl.onAuthenticationSuccess(AuthenticationSuccessHandlerImpl.java:47)
...
Caused by: javax.transaction.RollbackException: Transaction marked for rollback.
at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:428)
at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:855)
at com.sun.enterprise.transaction.UserTransactionImpl.commit(UserTransactionImpl.java:208)
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:842)
... 45 more
I have the following entity:
#Entity
#Table(name = "roles", catalog = "reservas")
#XmlRootElement
public class Role implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotNull
#Size(min = 1, max = 50)
private String name;
private static final long serialVersionUID = 1L;
GenericRepository, a general class, which is implemented by all the repositories:
public class GenericRepositoryImpl<T> implements GenericRepository<T> {
#PersistenceContext
private EntityManager em;
private Class<T> type;
public GenericRepositoryImpl( ){
Type t = getClass().getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) t;
type = (Class) pt.getActualTypeArguments()[0];
}
#Override
public T find(Object pk) {
try{
return em.find(type, pk);
}catch(java.util.NoSuchElementException ex){
return null;
}
}
#Override
public T create(T t) {
em.persist(t);
em.flush();
em.refresh(t);
return t;
}
#Override
public List<T> query(Query q) {
List<T> list= q.getResultList();
if(list==null)
list=new ArrayList<T>();
return list;
}
}
This is the role repository:
#Repository
public class RoleRepositoryImpl extends GenericRepositoryImpl<Role>
implements RoleRepository{
#PersistenceContext
private EntityManager em;
#Override
public Role findByName(String name) {
Query q = (Query) this.em.createNamedQuery("Role.findByName");
q.setParameter("name", name);
Role r = (Role) q.getSingleResult();
return r;
}
#Override
public List<Role> findAll() {
Query q = (Query) this.em.createNamedQuery("Role.findAll");
return this.query(q);
}
}
The Service class:
#Service
public class service {
#Autowired
private RoleRepository roleRepository;
#Transactional
//This throws a RollBackException
public void tryJPAEmpty(){
roleRepository.findByName("example");
}
//This doesn't
public Role tryJPAFind(){
return roleRepository.find(new Integer(1));
}
}
Spring configuration (applicationContext.xml) is:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
">
<context:component-scan base-package="com.***.***" />
<jpa:repositories base-package="com.***.***.repositories" />
<tx:annotation-driven />
<tx:annotation-driven transaction-manager="transactionManager" />
<context:annotation-config />
<beans>
<bean id="EntityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="JPAReservas"/>
</bean>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager" >
<property name="allowCustomIsolationLevels">
<value>true</value>
</property>
</bean>
</beans>
</beans>
Persistence.xml (I have a data source and a connection pool created in my GlassFish server):
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.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_1_0.xsd">
<persistence-unit name="JPAReservas" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>Reservas_mysql</jta-data-source>
<!--Named queries-->
<mapping-file>META-INF/mapping/Role.xml</mapping-file>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
</persistence-unit>
</persistence>
And finally, I have named queires in a xml file, like that:
SELECT r FROM Role r
<named-query name="Role.findByName">
<query>SELECT r FROM Role r WHERE r.name = :name</query>
</named-query>
I'm really noob with Spring and JPA, so if you know some improvements, or changes I can do, please tell me.
Ok, I've solved it changing transaction-type to RESOURCE_LOCAL, but at the beggining, Glassfish gives me a lot of troubles. That's the way I solved it:
I've add metadata-complete="true" to the header of web.xml. Here is explained why is this necesary:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0" metadata-complete="true">
I've changed my persistence.xml, because with RESOURCE_LOCAL the application won't use the connection pool of Glassfish, I have to put information about database connection:
<persistence-unit name="JPAReservas" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<mapping-file>META-INF/mapping/User.xml</mapping-file>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/reservas"/>
<property name="javax.persistence.jdbc.user" value="admin"/>
<property name="javax.persistence.jdbc.password" value="adminpassword"/>
</properties>
</persistence-unit>
And at the end, I've changed the applicationContext.xml (Spring configuration), because I can't use the same EntityManager class with RESOURCE_LOCAL as with JTA:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="EntityManagerFactory" />
</bean>
And that's all. I don't know why I can't use JTA like I was doing before, but I've solved it!!! :). Thank you!

EntityManager persist() method does not insert record to database

I have problem with using EntityManager.persist(Object) method. Now when i get rid of other problems, by app work without Exception but object is not put in my database.
my entity class:
#Entity
#Table(name ="Chain")
public class Chain implements Serializable{
#Id
#Column(name = "id")
private Long id;
#Column(name = "date")
private Date date;
#Column(name = "name")
private String name;
//setters and getters
}
my dao class:
#Transactional
#Repository("ChainDao")
public class ChainDaoImpl implements ChainDao{
private EntityManager em;
#PersistenceContext
public void setEntityManager(EntityManager em) {
this. em = em;
}
public int saveChain(Chain chain) {
chain.setDate(new Date());
chain.setId((long)44);
Boolean a;
em.persist(chain);
return 222;
}
}
my xml context:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml"></property></bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"
ref="entityManagerFactory" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
and pereistence.xml:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name="sample">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<!-- Scan for annotated classes and Hibernate mapping XML files -->
<properties>
<property name="hibernate.archive.autodetection" value="class, hbm"/>
<property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/>
<property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/database"/>
<property name="hibernate.connection.username" value="postgres"/>
<property name="hibernate.connection.password" value="pwd"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
<property name="hibernate.show_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
Do anyone have a idea what am i missing?
Are you getting a specific exception? It would be helpful to know what it is if you are.
There are a number of similar problems to this already on Stackoverflow:
Spring transactional context doesn't persist data
Spring, Hibernate & JPA: Calling persist on entitymanager does not seem to commit to database
These suggest that you should try adding em.flush() after the em.persist(chain), and altering the #transactional annotations
You should also check that you have enabled transactional annotations through a line such as :
<tx:annotation-driven transaction-manager="transactionManager"/>
in your .xml configuration
Try this:
em.getTransaction().begin();
em.persist(entity);
em.getTransaction().commit();
PS: You should set a generation method for your ID as well.
Can you post what exception are you getting? I will assume that your error is that your persistence.xml you don't specified your "Chain" Object.
You can specify using this tag
<exclude-unlisted-classes>false</exclude-unlisted-classes>
Or just
<class>your.package.Chain</class>
Put this above provider tag.
Also, never set a number for a column tagged as #Id
When you use method save() with a Id column with setted value, hibernate
will try to UPDATE NOT INSERT your data.
Do this:
Create getEntityManager Method
public EntityManager getEntityManager() {
return entityManager;
}
Then
#Transactional
public void saveChain(Chain chain) {
chain.setDate(new Date());
getEntityManager().persist(chain);
}
Adding these to your web.xml may solve this problem:
<!-- Open Entity Manager in View filter -->
<filter>
<filter-name>openEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
solved my problem using
org.springframework.transaction.jta.JtaTransactionManager
hope this work!
Use #EnableTransactionManagement in AppConfig Configuration file header
You can open the new Transaction and then commit your records.
#PersistenceUnit(unitName = "NameOfPersistenceUnit")
private EntityManagerFactory entityManagerFactory;
void someMethod(AccountCommodity accountCommodity){
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
entityManager.persist(accountCommodity);
entityManager.flush();
entityManager.getTransaction().commit();
entityManager.close();
}
You will need to assign id generation strategy as below:
#Entity
#Table(name ="Chain")
public class Chain implements Serializable{
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column(name = "date")
private Date date;
#Column(name = "name")
private String name;
//setters and getters
}
and in save method
public int saveChain(Chain chain) {
chain.setDate(new Date());
//chain.setId((long)44); remove this line
Boolean a;
em.persist(chain);
return 222;
}
if you assign Id, then hibernate/jpa will try to update record, which is not available, instead of inserting new record and I think will not throw exception.
I was able to fix the same problem by adding the Entity to persistence.xml:
<persistence-unit name="OwnerPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.test.domain.local.Entity</class>
<exclude-unlisted-classes />
</persistence-unit>
</persistence>

In Spring MVC 3.0.5 controller JPA entity not getting persisted to the database

In the code below, persist() returns w/o an exception but the entity is not stored in the database.
#RequestMapping(method = RequestMethod.POST)
public String form() {
EntityManager em = this.emf.createEntityManager();
TaxRates t = new TaxRates();
t.setCountry("US");
// set more properties
em.persist(t);
em.close();
...
}
persistence.xml:
<?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="TT-SpringMVCPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
...
<class>com.sajee.db.TaxRates</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:jtds:sqlserver://localhost:1234/mydb"/>
<property name="javax.persistence.jdbc.password" value="Password1"/>
<property name="javax.persistence.jdbc.driver" value="net.sourceforge.jtds.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="sa"/>
</properties>
</persistence-unit>
</persistence>
I don't need any transaction support or any fancy enterprise feature support. I simply want to create an entity and save it to the database.
Where am I going wrong?
persist() doesn't write your object to the database immediately. Instead, it marks your object as persistent, so that it will be written to the database before transaction commit (or before executing a query, or during explicit flush() operation).
So, even if you don't need transactional behaviour you still have to manage transactions. You can do it manually as follows:
#RequestMapping(method = RequestMethod.POST)
public String form() {
EntityManager em = this.emf.createEntityManager();
TaxRates t = new TaxRates();
t.setCountry("US");
// set more properties
em.getTransaction().begin();
em.persist(t);
em.getTransaction().commit();
em.close();
...
}
But Spring's declarative transaction support is a more convenient way to do it.

Resources