OptimisticLockException JPA

时间:2014-02-03 18:42:21

标签: java jsf jpa

我编程的项目有问题。
这是一个jsf 2.1版应用程序。我使用eclipse链接作为jpa实现。

我正在处理的类称为User,Logentry和LoginLogManager。用户仅包含有关网站用户和Logentries列表的信息。每次用户登录时,都会创建Logentry并将其写入数据库。这发生在LoginLogmanager中。

所以这是我的问题: 当我的Logentry表为空时,我可以创建一个没有问题的logentry并将其写入表中,但是当我再次执行它时会抛出一个OptimisticLockException。
我是JPA的新手,但直到现在我发现当我上次阅读它时我想要保存的一行被更新或删除时会发生这种情况。
这真让我感到困惑,因为我以前从未读过这种情况。在将其写入db之前创建此对象。

@Entity
@Table(name="LOGENTRY")
@NamedQuery(name="Logentry.findAll", query="SELECT l FROM Logentry l")
public class Logentry implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = IDENTITY)
    private int LE_ID;

    @Column(nullable=false)
    private Timestamp CREATE_TIMESTAMP;

    private boolean DELETED;

    @Column(nullable=false, length=1000)
    private String DESCRIPTION;

    @Column(nullable=false)
    private Timestamp MODIFIEDTS;

    @Version
    @Column(nullable=false)
    private int VERSION_ID;

    //bi-directional many-to-one association to Logtype
    @ManyToOne
    @JoinColumn(name="LT_ID", nullable=false)
    private Logtype LOGTYPE;

    //bi-directional many-to-one association to User
    @ManyToOne
    @JoinColumn(name="US_ID", nullable=false)
    private User USER;

    public Logentry() {
    }

    public int getLE_ID() {
        return this.LE_ID;
    }

    public void setLE_ID(int LE_ID) {
        this.LE_ID = LE_ID;
    }

    public Timestamp getCREATE_TIMESTAMP() {
        return this.CREATE_TIMESTAMP;
    }

    public void setCREATE_TIMESTAMP(Timestamp CREATE_TIMESTAMP) {
        this.CREATE_TIMESTAMP = CREATE_TIMESTAMP;
    }

    public boolean getDELETED() {
        return this.DELETED;
    }

    public void setDELETED(boolean DELETED) {
        this.DELETED = DELETED;
    }

    public String getDESCRIPTION() {
        return this.DESCRIPTION;
    }

    public void setDESCRIPTION(String DESCRIPTION) {
        this.DESCRIPTION = DESCRIPTION;
    }

    public Timestamp getMODIFIEDTS() {
        return this.MODIFIEDTS;
    }

    public void setMODIFIEDTS(Timestamp MODIFIEDTS) {
        this.MODIFIEDTS = MODIFIEDTS;
    }

    public int getVERSION_ID() {
        return this.VERSION_ID;
    }

    public void setVERSION_ID(int VERSION_ID) {
        this.VERSION_ID = VERSION_ID;
    }

    public Logtype getLOGTYPE() {
        return this.LOGTYPE;
    }

    public void setLOGTYPE(Logtype LOGTYPE) {
        this.LOGTYPE = LOGTYPE;
    }

    public User getUSER() {
        return this.USER;
    }

    public void setUSER(User USER) {
        this.USER = USER;
    }

}`

我的用户Pojo:

@Entity
@Table(name="USER")
@NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    private static Logger log = Logger.getLogger(User.class.getName());

    @Id
    @GeneratedValue(strategy = IDENTITY)
    private int US_ID;

    private Timestamp BIRTHDAY;

    @Column(length=50)
    private String CITY;

    @Column(length=50)
    private String COUNTRY;

    @Column(length=20)
    private String DEGREE;

    private boolean DELETED;

    @Column(nullable=false, length=75)
    private String EMAIL;

    @Column(length=45)
    private String FAX;

    @Column(length=100)
    private String FIRST_NAME;

    @Column(length=45)
    private String FIXED_LINE;

    private Timestamp INACTIVATION_TIMESTAMP;

    @Column(nullable=false, length=100)
    private String LAST_NAME;

    @Column(length=45)
    private String MOBILE_PHONE;

    @Column(nullable=false)
    private Timestamp MODIFIEDTS;

    @Column(nullable=false, length=50)
    private String PASSWORD;

    @Column(length=50)
    private String STATE;

    @Column(length=100)
    private String STREET_NAME;

    @Column(length=20)
    private String STREET_NO;

    @Column(length=20)
    private String TITLE;

    @Column(nullable=false, length=75)
    private String USER_NAME;

    @Version
    @Column(nullable=false)
    private int VERSION_ID;

    @Column(length=10)
    private String ZIP;

    //bi-directional many-to-one association to Logentry
    @OneToMany(mappedBy="USER")
    private List<Logentry> LOGENTRIES;

    //bi-directional many-to-one association to SupplierUserRole
    @OneToMany(mappedBy="USER")
    private List<Supplier_User_Role> SUPPLIER_USER_ROLES;

    //bi-directional many-to-one association to Taskbox
    @OneToMany(mappedBy="FROM_USER")
    private List<Taskbox> TASKBOX_AS_USERS;

    //bi-directional many-to-one association to Taskbox
    @OneToMany(mappedBy="TO_USER")
    private List<Taskbox> TASKBOX_AS_TOS;

    //bi-directional many-to-one association to Language
    @ManyToOne(fetch = LAZY)
    @JoinColumn(name="LA_ID", nullable=false)
    private Language LANGUAGE;

    public User() {
    }

    public int getUS_ID() {
        return this.US_ID;
    }

    public void setUS_ID(int US_ID) {
        this.US_ID = US_ID;
    }

    public Timestamp getBIRTHDAY() {
        return this.BIRTHDAY;
    }

    public void setBIRTHDAY(Timestamp BIRTHDAY) {
        this.BIRTHDAY = BIRTHDAY;
    }

    public String getCITY() {
        return this.CITY;
    }

    public void setCITY(String CITY) {
        this.CITY = CITY;
    }

    public String getCOUNTRY() {
        return this.COUNTRY;
    }

    public void setCOUNTRY(String COUNTRY) {
        this.COUNTRY = COUNTRY;
    }

    public String getDEGREE() {
        return this.DEGREE;
    }

    public void setDEGREE(String DEGREE) {
        this.DEGREE = DEGREE;
    }

    public boolean getDELETED() {
        return this.DELETED;
    }

    public void setDELETED(boolean DELETED) {
        this.DELETED = DELETED;
    }

    public String getEMAIL() {
        return this.EMAIL;
    }

    public void setEMAIL(String EMAIL) {
        this.EMAIL = EMAIL;
    }

    public String getFAX() {
        return this.FAX;
    }

    public void setFAX(String FAX) {
        this.FAX = FAX;
    }

    public String getFIRST_NAME() {
        return this.FIRST_NAME;
    }

    public void setFIRST_NAME(String FIRST_NAME) {
        this.FIRST_NAME = FIRST_NAME;
    }

    public String getFIXED_LINE() {
        return this.FIXED_LINE;
    }

    public void setFIXED_LINE(String FIXED_LINE) {
        this.FIXED_LINE = FIXED_LINE;
    }

    public Timestamp getINACTIVATION_TIMESTAMP() {
        return this.INACTIVATION_TIMESTAMP;
    }

    public void setINACTIVATION_TIMESTAMP(Timestamp INACTIVATION_TIMESTAMP) {
        this.INACTIVATION_TIMESTAMP = INACTIVATION_TIMESTAMP;
    }

    public String getLAST_NAME() {
        return this.LAST_NAME;
    }

    public void setLAST_NAME(String LAST_NAME) {
        this.LAST_NAME = LAST_NAME;
    }

    public String getMOBILE_PHONE() {
        return this.MOBILE_PHONE;
    }

    public void setMOBILE_PHONE(String MOBILE_PHONE) {
        this.MOBILE_PHONE = MOBILE_PHONE;
    }

    public Timestamp getMODIFIEDTS() {
        return this.MODIFIEDTS;
    }

    public void setMODIFIEDTS(Timestamp MODIFIEDTS) {
        this.MODIFIEDTS = MODIFIEDTS;
    }

    public String getPASSWORD() {
        return this.PASSWORD;
    }

    public void setPASSWORD(String PASSWORD) {
        this.PASSWORD = PASSWORD;
    }

    public String getSTATE() {
        return this.STATE;
    }

    public void setSTATE(String STATE) {
        this.STATE = STATE;
    }

    public String getSTREET_NAME() {
        return this.STREET_NAME;
    }

    public void setSTREET_NAME(String STREET_NAME) {
        this.STREET_NAME = STREET_NAME;
    }

    public String getSTREET_NO() {
        return this.STREET_NO;
    }

    public void setSTREET_NO(String STREET_NO) {
        this.STREET_NO = STREET_NO;
    }

    public String getTITLE() {
        return this.TITLE;
    }

    public void setTITLE(String TITLE) {
        this.TITLE = TITLE;
    }

    public String getUSER_NAME() {
        return this.USER_NAME;
    }

    public void setUSER_NAME(String USER_NAME) {
        this.USER_NAME = USER_NAME;
    }

    public int getVERSION_ID() {
        return this.VERSION_ID;
    }

    public void setVERSION_ID(int VERSION_ID) {
        this.VERSION_ID = VERSION_ID;
    }

    public String getZIP() {
        return this.ZIP;
    }

    public void setZIP(String ZIP) {
        this.ZIP = ZIP;
    }

    public List<Logentry> getLOGENTRIES() {
        return this.LOGENTRIES;
    }

    public void setLOGENTRIES(List<Logentry> LOGENTRIES) {
        this.LOGENTRIES = LOGENTRIES;
    }

    public Logentry addLOGENTRy(Logentry LOGENTRy) {
        getLOGENTRIES().add(LOGENTRy);

        if(this.getLOGENTRIES()!=null)
        log.info("Liste mit Logs ist nicht null!");

        LOGENTRy.setUSER(this);

        return LOGENTRy;
    }

    public Logentry removeLOGENTRy(Logentry LOGENTRy) {
        getLOGENTRIES().remove(LOGENTRy);
        LOGENTRy.setUSER(null);

        return LOGENTRy;
    }

    public List<Supplier_User_Role> getSUPPLIER_USER_ROLES() {
        return this.SUPPLIER_USER_ROLES;
    }

    public void setSUPPLIER_USER_ROLES(List<Supplier_User_Role> SUPPLIER_USER_ROLES) {
        this.SUPPLIER_USER_ROLES = SUPPLIER_USER_ROLES;
    }

    public Supplier_User_Role addSUPPLIER_USER_ROLE(Supplier_User_Role SUPPLIER_USER_ROLE) {
        getSUPPLIER_USER_ROLES().add(SUPPLIER_USER_ROLE);
        SUPPLIER_USER_ROLE.setUSER(this);

        return SUPPLIER_USER_ROLE;
    }

    public Supplier_User_Role removeSUPPLIER_USER_ROLE(Supplier_User_Role SUPPLIER_USER_ROLE) {
        getSUPPLIER_USER_ROLES().remove(SUPPLIER_USER_ROLE);
        SUPPLIER_USER_ROLE.setUSER(null);

        return SUPPLIER_USER_ROLE;
    }

    public List<Taskbox> getTASKBOX_AS_USERS() {
        return this.TASKBOX_AS_USERS;
    }

    public void setTASKBOX_AS_USERS(List<Taskbox> TASKBOX_AS_USERS) {
        this.TASKBOX_AS_USERS = TASKBOX_AS_USERS;
    }

    public Taskbox addTASKBOX_AS_USER(Taskbox TASKBOX_AS_USER) {
        getTASKBOX_AS_USERS().add(TASKBOX_AS_USER);
        TASKBOX_AS_USER.setFROM_USER(this);

        return TASKBOX_AS_USER;
    }

    public Taskbox removeTASKBOX_AS_USER(Taskbox TASKBOX_AS_USER) {
        getTASKBOX_AS_USERS().remove(TASKBOX_AS_USER);
        TASKBOX_AS_USER.setFROM_USER(null);

        return TASKBOX_AS_USER;
    }

    public List<Taskbox> getTASKBOX_AS_TOS() {
        return this.TASKBOX_AS_TOS;
    }

    public void setTASKBOX_AS_TOS(List<Taskbox> TASKBOX_AS_TOS) {
        this.TASKBOX_AS_TOS = TASKBOX_AS_TOS;
    }

    public Taskbox addTASKBOX_AS_TO(Taskbox TASKBOX_AS_TO) {
        getTASKBOX_AS_TOS().add(TASKBOX_AS_TO);
        TASKBOX_AS_TO.setTO_USER(this);

        return TASKBOX_AS_TO;
    }

    public Taskbox removeTASKBOX_AS_TO(Taskbox TASKBOX_AS_TO) {
        getTASKBOX_AS_TOS().remove(TASKBOX_AS_TO);
        TASKBOX_AS_TO.setTO_USER(null);

        return TASKBOX_AS_TO;
    }

    public Language getLANGUAGE() {
        return this.LANGUAGE;
    }

    public void setLANGUAGE(Language LANGUAGE) {
        this.LANGUAGE = LANGUAGE;
    }

}

和我的LoginLogManager:

@ManagedBean(name="loginLogManager")
@SessionScoped
public class LoginLogManager implements Serializable{

    private static final long serialVersionUID = 1L;
    private static Logger log = Logger.getLogger(LoginLogManager.class.getName());

    @ManagedProperty(value="#{logtypeDaoImpl}")
    private LogtypeDao logTypeDao;

    @ManagedProperty(value="#{logentryDaoImpl}")
    private LogentryDao logEntryDao;

    @ManagedProperty(value="#{userDaoImpl}")
    private UserDao userDao;

    private Timestamp timeStamp;            
    private Logentry logEntry;
    private Logtype logtype;


    public void createLog(String description,int logTypeId,User user){

        timeStamp=new Timestamp(System.currentTimeMillis());
        logtype=logTypeDao.findByID(logTypeId);


        logEntry=new Logentry();
        logEntry.setCREATE_TIMESTAMP(timeStamp);
        logEntry.setDESCRIPTION(description);
        logEntry.setLOGTYPE(logtype);
        logEntry.setMODIFIEDTS(timeStamp);


        user.addLOGENTRy(logEntry);
        userDao.update(user);

    }


    public static Logger getLog() {
        return log;
    }


    public static void setLog(Logger log) {
        LoginLogManager.log = log;
    }


    public LogtypeDao getLogTypeDao() {
        return logTypeDao;
    }


    public void setLogTypeDao(LogtypeDao logTypeDao) {
        this.logTypeDao = logTypeDao;
    }


    public UserDao getUserDao() {
        return userDao;
    }


    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }


    public Timestamp getTimeStamp() {
        return timeStamp;
    }


    public void setTimeStamp(Timestamp timeStamp) {
        this.timeStamp = timeStamp;
    }


    public Logentry getLogEntry() {
        return logEntry;
    }


    public void setLogEntry(Logentry logEntry) {
        this.logEntry = logEntry;
    }


    public Logtype getLogtype() {
        return logtype;
    }


    public void setLogtype(Logtype logtype) {
        this.logtype = logtype;
    }


    public static long getSerialversionuid() {
        return serialVersionUID;
    }


    public LogentryDao getLogEntryDao() {
        return logEntryDao;
    }


    public void setLogEntryDao(LogentryDao logEntryDao) {
        this.logEntryDao = logEntryDao;
    }



}

这是我的UserDao:

@ManagedBean(name = "userDaoImpl")
@SessionScoped
public class UserDaoImpl extends GenericDaoImpl<User> implements UserDao,
        Serializable {

    private static Logger log = Logger.getLogger(UserDaoImpl.class.getName());

    /**
     * 
     */
    private static final long serialVersionUID = -5280393555113818663L;

    /**
     * Loads a User by his Username
     * 
     * @param username
     * @return founded User
     */
    @Override
    public User findUserByUserName(String username) {
        em = EMF.getEMF().createEntityManager();
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<User> cq = cb.createQuery(User.class);
        Root<User> user = cq.from(User.class);
        cq.where(cb.and(cb.equal(user.get(User_.USER_NAME), username)));

        // EntityType<User>user_=entityManager.getMetamodel().entity(User.class);

        TypedQuery<User> typedQuery = em.createQuery(cq);
        List<User> userList = typedQuery.getResultList();
        em.close();
        return userList.get(0);
    }

    /**
     * Loads a User by his Username and Password
     * 
     * @param username
     * @param password
     * @return founded User
     */
    @Override
    public User findUserByUsernameAndPassword(String username, String password) {
        em = EMF.getEMF().createEntityManager();
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<User> cq = cb.createQuery(User.class);
        Root<User> user = cq.from(User.class);
        cq.where(cb.and(cb.equal(user.get(User_.USER_NAME), username),
                cb.equal(user.get(User_.PASSWORD), password)));

        log.info(""+username + " "+password);
        log.info(""+user.get(User_.USER_NAME)+ " "+(user.get(User_.PASSWORD)));

        // EntityType<User>user_=entityManager.getMetamodel().entity(User.class);

        TypedQuery<User> typedQuery = em.createQuery(cq);
        List<User> userList = typedQuery.getResultList();
        em.close();
        return userList.get(0);
    }
}

和实施的GenericDAO:

public abstract class GenericDaoImpl<T> implements GenericDao<T> {

    protected EntityManager em = null;

    private Class<T> type;

    @SuppressWarnings("unchecked")
    public GenericDaoImpl() {
        Type t = getClass().getGenericSuperclass();
        ParameterizedType pt = (ParameterizedType) t;
        type = (Class<T>) pt.getActualTypeArguments()[0];
    }

    /**
     * Inserts a new row to the database
     * 
     *
     * @param t
     *            : Object to insert
     * @return Object with key and new version
     */
    @Override
    public T insert(final T t) {
        em = EMF.getEMF().createEntityManager();
        em.getTransaction().begin();
        em.persist(t);
        // em.flush();
        // em.refresh(t);
        em.getTransaction().commit();
        em.close();
        return t;
    }

    /**
     * Deletes a row in the database by id
     * 
     *
     * @param id
     *            : id of the Object
     */
    @Override
    public void delete(final Object id) {
        em = EMF.getEMF().createEntityManager();
        em.getTransaction().begin();
        em.remove(em.getReference(type, id));
        em.getTransaction().commit();
        em.close();
    }

    /**
     * Finds a row in the database by id and return it
     * 
     * 
     * @param id
     *            : id of the Object
     * @return Object, which is found
     */
    @Override
    public T findByID(final Object id) {
        em = EMF.getEMF().createEntityManager();
        em.getTransaction().begin();
        T te = (T) em.find(type, id);
        em.getTransaction().commit();
        em.close();
        return te;
    }

    /**
     * Updates a row in the database
     * 
     * 
     * @param t
     *            : Object to update
     * @return Object with new version
     */
    @Override
    public T update(final T t) {
        em = EMF.getEMF().createEntityManager();
        em.getTransaction().begin();
        T te = em.merge(t);
        em.getTransaction().commit();
        em.close();
        return te;
    }

    /**
     * Counts the number of rows in this database table
     * 
     *
     * @param params
     *            : database arguments for counting
     * @return number of rows
     */
    @Override
    public long countAll(final Map<String, Object> params) {

        final StringBuffer queryString = new StringBuffer(
                "SELECT count(o) from ");

        queryString.append(type.getSimpleName()).append(" o ");
        queryString.append(getQueryClauses(params, null));

        em = EMF.getEMF().createEntityManager();
        em.getTransaction().begin();
        final Query query = em.createQuery(queryString.toString());
        em.getTransaction().commit();
        em.close();

        return (Long) query.getSingleResult();

    }

    /**
     * Finds All Objects in this database table
     * 
     * 
     * @return all Objects in the database table
     */
    @SuppressWarnings("unchecked")
    public List<T> findAll() {
        em = EMF.getEMF().createEntityManager();
        em.getTransaction().begin();
        List<T> teList = em.createQuery(
                "Select t from " + type.getSimpleName() + " t").getResultList();
        em.getTransaction().commit();
        em.close();
        return teList;
    }

    /**
     * Creates a part of a String for a Query
     * 
     * @return created String
     */
    private String getQueryClauses(final Map<String, Object> params,
            final Map<String, Object> orderParams) {
        final StringBuffer queryString = new StringBuffer();
        if ((params != null) && !params.isEmpty()) {
            queryString.append(" where ");
            for (final Iterator<Map.Entry<String, Object>> it = params
                    .entrySet().iterator(); it.hasNext();) {
                final Map.Entry<String, Object> entry = it.next();
                if (entry.getValue() instanceof Boolean) {
                    queryString.append(entry.getKey()).append(" is ")
                            .append(entry.getValue()).append(" ");
                } else {
                    if (entry.getValue() instanceof Number) {
                        queryString.append(entry.getKey()).append(" = ")
                                .append(entry.getValue());
                    } else {
                        // string equality
                        queryString.append(entry.getKey()).append(" = '")
                                .append(entry.getValue()).append("'");
                    }
                }
                if (it.hasNext()) {
                    queryString.append(" and ");
                }
            }
        }
        if ((orderParams != null) && !orderParams.isEmpty()) {
            queryString.append(" order by ");
            for (final Iterator<Map.Entry<String, Object>> it = orderParams
                    .entrySet().iterator(); it.hasNext();) {
                final Map.Entry<String, Object> entry = it.next();
                queryString.append(entry.getKey()).append(" ");
                if (entry.getValue() != null) {
                    queryString.append(entry.getValue());
                }
                if (it.hasNext()) {
                    queryString.append(", ");
                }
            }
        }
        return queryString.toString();
    }
}

正如我之前所说,当我第二次登录并且数据库中已经存在日志时,它会抛出OLE。

无法合并对象[at.dccs.csm.database.entity.Logentry@419a7187],因为它自上次读取后已更改或被删除。

这是异常描述 我不知道为什么会抛出这个例外。
我希望你能给我建议并帮助解决我的问题。

1 个答案:

答案 0 :(得分:0)

首先,在Java Word中,大写属性用于静态最终字段。您可以搜索JavaBeans规范。

private Long id; public Long getId(){return id;} public void setId(Long id){this.id=id;}

我建议你使用原始包装器代替基元的原语。我的意思是,使用Integer而不是int。如果id为null,则表示您的实体不会保留。

其次,您不需要重写equals / hashcode以使其工作。

第三,在JPA世界中,你不需要任何DAO。您可以搜索域存储模式。实体经理已经完成了“CRUD”工作。

关闭实体管理器时,所有实体都与持久性上下文分离。因此,每次调用DAO都会有不同的上下文,因为您创建了不同的实体/事务。

在DAO世界中,您不能打开和关闭实体管理器并在dao中创建事务。您希望在提交事务之前执行多个请求。如果您创建多个事务,则只有最后一部分将在发生错误时回滚。那太糟糕了。

您需要有一个服务层来完成这项工作。

对于您的问题,在同一事务中,合并您的用户,合并您的日志条目(设置用户),然后在您的用户中添加日志条目。