简体   繁体   中英

Why is my EntityManagerHelper class returning previous query results and how do I fix it?

This question What is the right way to use entitymanager supplied a link to EntityManagerHelper.java which I added to my code base. When I use this helper class to make subsequent calls to the database it returns previous results to the same query.

The scenario I see this most in is retrieving the lastentry property of my User Class . On the browser I make an AJAX request and the servlet partial below gets the user object and calls a method to return my lastentry .

I've read about .clear() but I get server errors when I added it to my EntityManagerHelper. I would like to avoid creating an EntityManager every time I want to make a call to the db.

How can I fix this problem?

partial from servlet

User user = User.getUser();

response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(user.getLastentry());

User Class

package entities;

import java.io.Serializable;
import java.util.Date;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Persistence;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import org.apache.shiro.SecurityUtils;
import responseablees.EntityManagerHelper;

/**
 *
 * @author Christopher Loughnane <chrisloughnane1@gmail.com>
 */
@Entity
@Table(name = "user")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "User.findAll", query = "SELECT u FROM User u")
    , @NamedQuery(name = "User.findById", query = "SELECT u FROM User u WHERE u.id = :id")
    , @NamedQuery(name = "User.findByUsername", query = "SELECT u FROM User u WHERE u.username = :username")
    , @NamedQuery(name = "User.getUsernameByUserEmail", query = "SELECT u.username FROM User u WHERE u.useremail = :useremail")
    , @NamedQuery(name = "User.findByUserEmail", query = "SELECT u FROM User u WHERE u.useremail = :useremail")
    , @NamedQuery(name = "User.findByPassword", query = "SELECT u FROM User u WHERE u.password = :password")})
public class User implements Serializable {

    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 2048)
    @Column(name = "lastentry")
    private String lastentry;

    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 128)
    @Column(name = "useremail")
    private String useremail;
    @Basic(optional = false)
    @Column(name="created", insertable = false, updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date created;

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 100)
    @Column(name = "username")
    private String username;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 100)
    @Column(name = "password")
    private String password;

    public User() {
    }

    public User(Integer id) {
        this.id = id;
    }

    public User(Integer id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof User)) {
            return false;
        }
        User other = (User) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "DAOs.User[ id=" + id + " ]";
    }

    public String getUseremail() {
        return useremail;
    }

    public void setUseremail(String useremail) {
        this.useremail = useremail;
    }

    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public String getLastentry() {
        return lastentry;
    }

    public void setLastentry(String lastentry) {
        this.lastentry = lastentry;
    }

    public static User getUser(){

        String currentUser = (String) SecurityUtils.getSubject().getPrincipal();
        User user = (User) em.createNamedQuery("User.findByUserEmail")
                .setParameter("useremail", currentUser)
                .getSingleResult();
        return user;
    }
}

Requested Code

Verbose Approach

    String currentUser = (String) SecurityUtils.getSubject().getPrincipal();

    EntityManagerFactory emfactory = Persistence.createEntityManagerFactory("com.mycompany_responseableES_war_1.0-SNAPSHOTPU");
    EntityManager em = emfactory.createEntityManager();

    User user = (User) em.createNamedQuery("User.findByUserEmail")
            .setParameter("useremail", currentUser)
            .getSingleResult();
    em.getTransaction().begin();
    user.setLastentry(JSON);
    em.getTransaction().commit();

EntityManagerHelper Approach

    User user = User.getUser();
    EntityManager em = EntityManagerHelper.getEntityManager();
    em.getTransaction().begin();
    user.setLastentry(JSON);
    em.getTransaction().commit();

First of all, I would be careful to put ALL my data fetching/modification code between

em.getTransaction().begin()

and

em.getTransaction().commit()

This ensures that your entities are managed and your changes are automatically persisted . In your code it looks like the User instance comes from outside the transaction. I have not worked much with JPA and manual transactions, but I would not be surprised if the user is detached (that is, not managed by the EntityManager ) and so changes are not automatically persisted to the database. If that were the case I guess you could solve it by putting

// merge(...) takes an entity that is not managed, apply changes to
// the persistence context and returns a new *managed* entity.
// The original entity REMAINS *detached* or *non persistent*
User managedUser = em.merge(user);

// I assume that you have something like this to set your user in the
// current session or whatever
User.setUser(managedUser);

just before the commit.

JPA vocabulary can be a bit hard at first, read this for more details about the JPA entity lifecycle (specially the diagram at the bottom).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM