Reputation: 11
I use JPA and have the following issue, my table is automatically updated after I call a setter. Here is an example :
Persisted object :
@Entity
public class Product implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private String id;
String name;
/*+ getters & setters */
}
Facade to access my object :
@Stateless
public class ProductFacade {
@PersistenceContext(unitName = "PU")
private EntityManager em;
public Product find(Object id) {
Product p = em.find(Product.class, id);
return p;
}
public void create(Product p) {
em.persist(p);
}
}
But when I execute this code in my webapp :
@Stateless
public class ProductService {
@EJB
ProductFacade manager;
public void testMethod() {
id = new Long(1);
Product product = manager.find(id);
product.setName("newName");
}
}
The name value of product is changed in the database after the set, even if I don't make an explicit call to persist or merge.
What can I do to avoid these kind of automatic database changes ?
Here is also my persistence.xml :
<persistence .... >
<persistence-unit name="PU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/sample</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.ddl-generation" value="create-tables"/>
<property name="connection.autocommit" value="false"/>
<property name="eclipselink.persistence-context.flush-mode" value="COMMIT"/>
</properties>
</persistence-unit>
</persistence>
Thank you for your help.
Upvotes: 1
Views: 4319
Reputation: 21145
The spec requires entities returned from the EntityManager be managed, so that they can track changes and maintain object identity for you.
The simplest spec solution is to not wrap the EntityManager within a transaction (and if using JTA, make sure a non-JTA datasource is available for reads), and close or clear the EntityManager. Changes will only be synchronized to the database if the EntityManager is associated to a transaction, so your changes cannot not be persisted to the database. As long as you are using the same EntityManager, queries through it will return the same entity instance - so your changes will be picked up until you detach or clear the EntityManager, regardless of being in a transaction. This is why you might want to clear or close and re-obtain EntityManagers at logical points.
Within EclipseLink, you can mark your queries with hints to tell EclipseLink to return a detached object. See the eclipselink.maintain-cache hint described at http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching/Query_Options#EclipseLink_Cache_Query_Hints for info. It is also found at http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Query_Hints#Maintain_Cache but the default value specified is incorrect - the default is true.
query.setHint(QueryHints.MAINTAIN_CACHE, false);
or
Map properties = new HashMap();
properties.put(QueryHints.MAINTAIN_CACHE, false);
em.find(Product.class, id, properties)
Upvotes: 4