i use JPA eclipse Toplink & EJB
everytime i receive entity from database then change some data inside of it,
database(MYSQL) automaticly change too without i commit or do something
Example:
Player p = em.findById(1);
p.setName(newName);
// i do nothing , but database automaticly change
i already read related question here, but i still can't figure it out
i think i must detach entity but i don't know how to do this, because
i have class GenericDAO generated from netbeans
GenericDAO (generated from netbeans)
public abstract class GenericDAO<T> {
private Class<T> entityClass;
public GenericDAO(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public void insert(T entity) {
getEntityManager().persist(entity);
}
public void edit(T entity) {
getEntityManager().merge(entity);
}
public void delete(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
}
public T findById(Object id) {
return getEntityManager().find(entityClass, id);
}
public List<T> findAll() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return getEntityManager().createQuery(cq).getResultList();
}
public List<T> findRange(int[] range) {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
javax.persistence.Query q = getEntityManager().createQuery(cq);
q.setMaxResults(range[1] - range[0] + 1);
q.setFirstResult(range[0]);
return q.getResultList();
}
public int count() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
cq.select(getEntityManager().getCriteriaBuilder().count(rt));
javax.persistence.Query q = getEntityManager().createQuery(cq);
return ((Long) q.getSingleResult()).intValue();
}
}
DaoPlayer
@Local
public interface DaoPlayer{
void insert(Player player);
void edit(Player player);
void delete(Player player);
Player findById(Object id);
List<Player> findAll();
List<Player> findRange(int[] range);
int count();
ImplPlayer
@Stateless
public class ImplPlayer extends GenericDAO<Player> implements DaoPlayer{
@PersistenceContext(unitName = "MonsterPuzzle")
private EntityManager em;
@Override
protected EntityManager getEntityManager() {
return em;
}
public ImplPlayer() {
super(Player.class);
}
}
My question is
You will need to look into how you are managing transactions in your application. Consider one of your methods:
Player findById(Object id){}
If you are using Container Managed Transactions in a Java EE environment, you just need to mark the transaction as not supported in the DAO.
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
Player findById(Object id) {}
This will make sure that the transaction is not open when the Dao passed the entity back to a different layer. Any changes you make to the entity will not be synchronized with the database.
Understand this: "every update in an attached entity will be reflected in the database".
When an entity is attached? To put it in a simple way, every entity that pass through the EntityManager with the methods: persist, merge, refresh, delete (maybe I am forgetting some any other here) or in the query (JPQL or find) methods inside a transaction.
Look at the sample below:
entityManager.getTransaction().begin();
Dog dog = entityManager.find(Dog.class, 1);
dog.setGoodBoyLevel(99);
entityManager.getTransaction().commit();
Since dog passed by the find method inside a transaction it can be considered managed.
If you are using EJB you must know that the default transaction is REQUIRED. The REQUIRED works like: If there is a transaction opened, let us use it. If there is no transaction opened, let us open it. (It is a nice guy)
Since your method is without any indicator to suspend the transaction every update in the entity will be reflected in the database. What could you do? Use the NOT_SUPPORTED transaction way:
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void yourMethod(){
// to awesome things
}
Since you are using the NOT_SUPPORTED transaction option your entity will be detached. What does detached means? The JPA will not analyse the updates in the entity. If you want just read some info, that is ok. But the code below will raise exception:
entityManager.getTransaction().begin();
Dog dog = new Dog();
Owner owner = getDetachedOwner(ownerId);
dog.setOwner(owner);
entityManager.persist(dog);
entityManager.getTransaction().commit();
The problem here is that the owner is detached, so the JPA do not knows it and would raise an exception.
Be careful with the NOT_SUPPORTED option. [=
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With