第一次保存后发生TransientObjectException错误

Nooby Noob先生

每当我进行连续保存时,我都会收到一个TransientObjectException;第一次保存或刷新屏幕/页面时,没有出现此错误。这让我很困惑,因为成功保存对象后,它就不应是瞬态的,因为它在我的数据库中有一个表示形式。

我下面的文件(User和UserPasswordInfo)具有一对多关系,其中一个User可以具有多个UserPasswordInfo(或UPI),并且通过我的用户的主键user_id进行链接

我很确定问题出在以下文件中,而不是其他地方,因为TOE错误仅在添加此文件后才出现,并且据我所知,该软件在其生命周期(几年)中从未出现此问题。

这是我的休眠文件:

User.hbm.xml

<hibernate-mapping>
    <class name="com.app.common.domain.User" table="users"  >
        <id name="id" type="java.lang.Integer">
            <column name="user_id" />
            <generator class="identity" />
        </id>

       <set name="passwordInfos" table="user_password_info" lazy="false" cascade="all" fetch="select">
            <key>
                <column name="user_id"></column>
            </key>
            <one-to-many class="com.app.common.domain.UserPasswordInfo" />
        </set>        

    </class>
</hibernate-mapping>

UserPasswordInfo.hbm.xml

<hibernate-mapping>
   <class name="com.app.common.domain.UserPasswordInfo" table="user_password_info">
      <id name="passwordInfoId" type="java.lang.Integer">
            <column name="password_info_id" />
            <generator class="identity" />
       </id>

      <property name="password" column="password" type="java.lang.String"/>
      <property name="passwordTS" column="password_ts" type="java.sql.Timestamp"/>
      <property name="pwdChange" column="initial_password_change" type="java.lang.Boolean"/>
      <property name="userId" column="user_id" type="java.lang.Integer"/>

   </class>
</hibernate-mapping>

这是他们的Java文件:

User.java

import java.sql.Timestamp;
import java.util.Collections;
import java.util.Comparator;

import java.util.HashSet;
import java.util.Set;

public class User extends DBObject {//DBObject has a getter and setter for the id

    private Set<UserPasswordInfo> passwordInfos = new HashSet<UserPasswordInfo>(0);

    public User() {
        super();
    }

    .
    .
    .

    public Set<UserPasswordInfo> getPasswordInfos() {
        return passwordInfos;
    }

    public void setPasswordInfos(Set<UserPasswordInfo> passwordInfos) {
        this.passwordInfos = passwordInfos;
    }

    public void addUPI(String pwd, Timestamp pwdTS, Boolean pwdChng){
        UserPasswordInfo upi = new UserPasswordInfo();
        upi.setPassword(pwd);
        upi.setPasswordTS(pwdTS);
        upi.setPwdChange(pwdChng);
        if(getId() != null)
            upi.setUserId(getId().intValue());
        passwordInfos.add(upi);
    }

    public String getLatestPassword(){
        return getSortedList().get(0).getPassword();
    }

    public UserPasswordInfo getLatestUPI(){
        ArrayList<UserPasswordInfo> list = getSortedList();
        return (list == null || list.size() == 0) ? null : list.get(0);
    }

    public ArrayList<String> getLastThreePasswords(){

        final ArrayList<UserPasswordInfo> upiList = getSortedList();

        if(upiList == null)
            return null;

        ArrayList<String> list = new ArrayList<String>();
        int i = 0; 
        while(i < 3 && i < list.size()){
            list.add(upiList.get(i++).getPassword());
        }
        return list;
    }

    public ArrayList<UserPasswordInfo> getSortedList(){

        ArrayList<UserPasswordInfo> upi = new ArrayList<UserPasswordInfo>(getPasswordInfos());
        if(upi == null || upi.size() == 0){
            return null;
        }

        Collections.sort(upi, new Comparator<UserPasswordInfo>() {
            public int compare(UserPasswordInfo o1, UserPasswordInfo o2) {
                if (o1.getPasswordTS() == null || o2.getPasswordTS() == null)
                    return 0;
                return o2.getPasswordTS().compareTo(o1.getPasswordTS());
            }
        });
        return upi;
    }
}

UserPasswordInfo.java

import java.sql.Timestamp;

public class UserPasswordInfo extends DBObject{

    private int passwordInfoId;
    private String password;
    private Timestamp passwordTS;
    private Boolean pwdChange;
    private int userId;

    public UserPasswordInfo(){}

    public UserPasswordInfo(String pwd, Timestamp pwdTS, Boolean pwdChng){
        password = pwd;
        passwordTS = pwdTS;
        pwdChange = pwdChng;
    }

    public UserPasswordInfo(int userId, String pwd, Timestamp pwdTS, Boolean pwdChng){
        this.userId = userId;
        password = pwd;
        passwordTS = pwdTS;
        pwdChange = pwdChng;
    }

    public int getPasswordInfoId(){
        return passwordInfoId;
    }
    public void setPasswordInfoId(int pid){
        passwordInfoId = pid;
    }
    public String getPassword(){
        return password;
    }
    public void setPassword(String pwd){
        password = pwd;
    }
    public Timestamp getPasswordTS(){
        return passwordTS;
    }
    public void setPasswordTS(Timestamp ts){
        passwordTS = ts;
    }
    public void setPwdChange(Boolean pwdChange) {
        this.pwdChange = pwdChange;
    }
    public Boolean getPwdChange() {
        return pwdChange;
    }
    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
}

这是错误消息:

ERROR BeanPopulator - 
propertyName=passwordInfos
readerMethod=public java.util.Set com.app.domain.User.getPasswordInfos()
setterMethod=public void com.app.common.domain.User.setPasswordInfos(java.util.Set)
fromBean=[User someUser, id: 268, role: front desk]
toBean=[User , id: null]

net.sf.gilead.exception.TransientObjectException
    at net.sf.gilead.core.hibernate.HibernateUtil.getId(HibernateUtil.java:316)
    at net.sf.gilead.core.hibernate.HibernateUtil.getId(HibernateUtil.java:224)
    at net.sf.gilead.core.hibernate.HibernateUtil.loadPersistentCollection(HibernateUtil.java:854)
    at net.sf.gilead.core.hibernate.HibernateUtil.createPersistentCollection(HibernateUtil.java:843)
    at net.sf.gilead.core.beanlib.merge.MergeCollectionReplicator.replicateCollection(MergeCollectionReplicator.java:119)
    at net.sf.beanlib.provider.replicator.ReplicatorTemplate.replicate(ReplicatorTemplate.java:112)
    at net.sf.beanlib.provider.BeanTransformer.transform(BeanTransformer.java:231)
    at net.sf.beanlib.provider.BeanPopulator.doit(BeanPopulator.java:201)
    at net.sf.beanlib.provider.BeanPopulator.processSetterMethod(BeanPopulator.java:172)
    at net.sf.beanlib.provider.BeanPopulator.populate(BeanPopulator.java:269)
    at net.sf.gilead.core.LazyKiller.populate(LazyKiller.java:288)
    at net.sf.gilead.core.LazyKiller.attach(LazyKiller.java:237)
    at net.sf.gilead.core.PersistentBeanManager.mergePojo(PersistentBeanManager.java:554)
    at net.sf.gilead.core.PersistentBeanManager.merge(PersistentBeanManager.java:318)
    at net.sf.gilead.core.PersistentBeanManager.mergeCollection(PersistentBeanManager.java:581)
    at net.sf.gilead.core.PersistentBeanManager.merge(PersistentBeanManager.java:290)
    at net.sf.gilead.gwt.GileadRPCHelper.parseInputParameters(GileadRPCHelper.java:94)
    at net.sf.gilead.gwt.GileadRPCHelper.parseInputParameters(GileadRPCHelper.java:137)
    at net.sf.gilead.gwt.PersistentRemoteService.processCall(PersistentRemoteService.java:172)

编辑以下是一些可能与此错误相关的链接和代码部分:

这是在我保存对象时进行的方法调用(在调用此方法之前引发了以上错误)

@SuppressWarnings({ "rawtypes" })
    private List saveObjectList(List<? extends DBObject> values) {
        Session session = sessionFactory.getCurrentSession();
        Transaction tx = null;

        try {
            tx = session.beginTransaction();
            for (DBObject value : values) {
                if (value.getIsDirty()) {
                    Integer clientId = value.getClientId();
                    if (value.getId() != null) {//enters here
                        value = (DBObject) session.merge(value);
                        session.persist(value);
                    }
                    else {
                        session.save(value);
                    }
                    value.setClientId(clientId);
                    value.setIsDirty(false);
                }
            }
            tx.commit();//fails here

            return values;
        }
        catch (Exception ex) {
            String msg = "Failed to save values. ";
            if (values == null) {
                msg += " Values to save were null.";
            }
            else {
                msg += " Values to save had length: " + values.size();
            }
            rollbackOrCloseSession(tx, session, "saveObjectList() - " + msg, ex);
            return null;
        }
    }

GileadRPC助手

/**
     * Parse RPC input parameters.
     * Must be called before GWT service invocation.
     * @param rpcRequest the input GWT RPC request
     * @param beanManager the Hibernate bean manager
     * @param session the HTTP session (for HTTP Pojo store)
     */
    public static void parseInputParameters(Object[] parameters, 
                                            PersistentBeanManager beanManager,
                                            HttpSession session)
    {
    //  Init classloader for proxy mode
    //
        if (beanManager.getClassMapper() instanceof ProxyClassMapper)
        {
            initClassLoader();
        }

    //  Set HTTP session of Pojo store in thread local
    //
        HttpSessionProxyStore.setHttpSession(session);

    //  Merge parameters if needed
    //
        if (parameters != null)
        {
            long start = System.currentTimeMillis();
            for (int index = 0 ; index < parameters.length; index ++)
            {
                if (parameters[index] != null)
                {
                    try
                    {
                        //***ERROR occurs when this is called
                        parameters[index] = beanManager.merge(parameters[index], true);
                    }
                    catch (NotAssignableException ex)
                    {
                        log.debug(parameters[index] + " not assignable");
                    }
                    catch (TransientObjectException ex)
                    {
                        log.info(parameters[index] + " is transient : cannot merge...");
                    }
                }
            }

            if (log.isDebugEnabled())
            {
                log.debug("Merge took " + (System.currentTimeMillis() - start) + " ms.");
            }
        }
    }

PersistentBeanManager

/**
     * Merge the clone POJO to its Hibernate counterpart
     */
    public Object merge(Object object) {
        // Explicit merge
        return merge(object, false);
    }

    /**
     * Merge the clone POJO to its Hibernate counterpart
     */
    @SuppressWarnings("unchecked")
    public Object merge(Object object, boolean assignable) {
        // Precondition checking
        //
        if (object == null) {
            return null;
        }

        if (_persistenceUtil == null) {
            throw new RuntimeException("No Persistence Util set !");
        }

        // Collection handling
        //
        if (object instanceof Collection) {
            return mergeCollection((Collection) object, assignable);
        } else if (object instanceof Map) {
            return mergeMap((Map) object, assignable);
        } else if (object.getClass().isArray()) {
            // Check primitive type
            //
            if (object.getClass().getComponentType().isPrimitive()) {
                return object;
            }

            // Merge as a collection
            //
            Object[] array = (Object[]) object;
            Collection result = mergeCollection(Arrays.asList(array), assignable);

            // Get the result as an array (much more tricky !!!)
            //
            Class<?> componentType = object.getClass().getComponentType();
            Object[] copy = (Object[]) java.lang.reflect.Array.newInstance(componentType, array.length);
            return result.toArray(copy);
        } else {
            return mergePojo(object, assignable);
        }
    }

/**
     * Retrieve the Hibernate Pojo and merge the modification from GWT
     * 
     * @param clonePojo the clone pojo
     * @param assignable does the source and target class must be assignable
     * @return the merged Hibernate POJO
     * @exception UnsupportedOperationException if the clone POJO does not implements ILightEntity and the POJO store is
     *                stateless
     * @exception NotAssignableException if source and target class are not assignable
     */
    protected Object mergePojo(Object clonePojo, boolean assignable) {

        // Get Hibernate associated class
        Class<?> cloneClass = clonePojo.getClass();
        Class<?> hibernateClass = null;
        if (_classMapper != null) {
            hibernateClass = _classMapper.getSourceClass(cloneClass);
        }
        if (hibernateClass == null) {
            // Not a clone : take the inner class
            hibernateClass = clonePojo.getClass();
        }

        // Precondition checking : is the pojo managed by Hibernate
        if (_persistenceUtil.isPersistentClass(hibernateClass) == true) {
            // Assignation checking
            if ((assignable == true) && (hibernateClass.isAssignableFrom(cloneClass) == false)) {
                throw new NotAssignableException(hibernateClass, cloneClass);
            }
        }

        // Retrieve the pojo
        try {
            Serializable id = null;
            try {
                id = _persistenceUtil.getId(clonePojo, hibernateClass);
                if (id == null) {
                    _log.info("HibernatePOJO not found : can be transient or deleted data : " + clonePojo);
                }
            } catch (TransientObjectException ex) {
                _log.info("Transient object : " + clonePojo);
            } catch (NotPersistentObjectException ex) {
                if (holdPersistentObject(clonePojo) == false) {
                    // Do not merge not persistent instance, since they do not
                    // necessary
                    // implement the Java bean specification
                    //
                    if (_log.isDebugEnabled()) {
                        _log.debug("Not persistent object, merge is not needed : " + clonePojo);
                    }
                    return clonePojo;
                } else {
                    if (_log.isDebugEnabled()) {
                        _log.debug("Merging wrapper object : " + clonePojo);
                    }
                }
            }

            if (ClassUtils.immutable(hibernateClass)) {
                // Do not clone immutable types
                //
                return clonePojo;
            }

            // Create a new POJO instance
            //
            Object hibernatePojo = null;
            try {
                if (AnnotationsManager.hasGileadAnnotations(hibernateClass)) {
                    if (id != null) {
                        // ServerOnly or ReadOnly annotation : load from DB
                        // needed
                        //
                        hibernatePojo = _persistenceUtil.load(id, hibernateClass);
                    } else {
                        // Transient instance
                        //
                        hibernatePojo = clonePojo;
                    }
                } else {
                    Constructor<?> constructor = hibernateClass.getDeclaredConstructor(new Class<?>[] {});
                    constructor.setAccessible(true);
                    hibernatePojo = constructor.newInstance();
                }
            } catch (Exception e) {
                throw new RuntimeException("Cannot create a fresh new instance of the class " + hibernateClass, e);
            }

            // Merge the modification in the Hibernate Pojo
            //
            _lazyKiller.attach(hibernatePojo, clonePojo);
            return hibernatePojo;
        } finally {
            _persistenceUtil.closeCurrentSession();
            _proxyStore.cleanUp();
        }
    }

BeanPopulator

@Override
    public <T> T populate() {
        if (getBeanTransformerSpi() != null) {
            getBeanTransformerSpi().getClonedMap().put(fromBean, toBean);
        }
        // invoking all declaring setter methods of toBean from all matching getter methods of fromBean
        for (Method m : baseConfig.getSetterMethodCollector().collect(toBean)) {
            processSetterMethod(m);
        }
        @SuppressWarnings("unchecked")
        T ret = (T) toBean;
        return ret;
    }

 private void processSetterMethod(Method setterMethod) {
        String methodName = setterMethod.getName();
        final String propertyString = methodName.substring(baseConfig.getSetterMethodCollector().getMethodPrefix().length());

        if (baseConfig.isDebug()) {
            if (log.isInfoEnabled()) {
                log.info(new StringBuilder("processSetterMethod: processing propertyString=").append(propertyString).append("")
                        .append(", fromClass=").append(fromBean.getClass()).append(", toClass=").append(toBean.getClass()).toString());
            }
        }
        Method readerMethod = baseConfig.getReaderMethodFinder().find(propertyString, fromBean);

        if (readerMethod == null) {
            return;
        }
        // Reader method of fromBean found
        Class<?> paramType = setterMethod.getParameterTypes()[0];
        String propertyName = Introspector.decapitalize(propertyString);
        try {
            doit(setterMethod, readerMethod, paramType, propertyName);
        } catch (Exception ex) {
            baseConfig.getBeanPopulationExceptionHandler().initFromBean(fromBean).initToBean(toBean).initPropertyName(propertyName)
                    .initReaderMethod(readerMethod).initSetterMethod(setterMethod).handleException(ex, log);
        }
    }

    private <T> void doit(Method setterMethod, Method readerMethod, Class<T> paramType, final String propertyName) {
        if (baseConfig.getDetailedPropertyFilter() != null) {
            if (!baseConfig.getDetailedPropertyFilter().propagate(propertyName, fromBean, readerMethod, toBean, setterMethod)) {
                return;
            }
        }
        if (baseConfig.getPropertyFilter() != null) {
            if (!baseConfig.getPropertyFilter().propagate(propertyName, readerMethod)) {
                return;
            }
        }
        Object propertyValue = this.invokeMethodAsPrivileged(fromBean, readerMethod, null);

        if (baseConfig.getBeanSourceHandler() != null) {
            baseConfig.getBeanSourceHandler().handleBeanSource(fromBean, readerMethod, propertyValue);
        }

        if (transformer != null) {
            PropertyInfo propertyInfo = new PropertyInfo(propertyName, fromBean, toBean);
            propertyValue = transformer.transform(propertyValue, paramType, propertyInfo);
        }

        if (baseConfig.isDebug()) {
            if (log.isInfoEnabled()) {
                log.info("processSetterMethod: setting propertyName=" + propertyName);
            }
        }
        // Invoke setter method
        Object[] args = { propertyValue };
        this.invokeMethodAsPrivileged(toBean, setterMethod, args);
        return;
    }

Gilead HibernateUtil类

丹妮洛·扎托尔斯基

可能这是由以下代码引起的:

public void addUPI(String pwd, Timestamp pwdTS, Boolean pwdChng){
    UserPasswordInfo upi = new UserPasswordInfo();
    upi.setPassword(pwd);
    upi.setPasswordTS(pwdTS);
    upi.setPwdChange(pwdChng);
    if(getId() != null)
        upi.setUserId(getId().intValue());
    passwordInfos.add(upi);
}

如果您调用此方法然后存储您的User对象,我将假定将引发异常。问题是您需要首先附加UserPasswordInfo到上下文,然后才可以将其添加到User对象。

因此正确的顺序是先存储UserPasswordInfo:

entityManager.persist(upi);

然后将其添加到密码中并存储用户对象:

user.getPasswordInfos().add(upi);
entityManager.save(user);

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

第一次发生后中断flatMap

第一次 cout 后的错误值

硒 - 如何跳过自定记录了第一次发生后

用户默认值在SwiftUI中第一次保存后未保存并更新

如何在powershell中第一次发生错误时退出脚本?

第一次迁移时访问Microsoft.Extensions.Hosting服务时发生错误

动画仅发生第一次

Android - 第一次动画发生的行为不同

是否可以保证第一次保存后created_at和updated_at相等?

保存文件后,Ionic-native-file 无法第一次读取文件

Symfony 2:第一次保存后,将字段设置为只读

UICollectionView大小在第一次加载时在sizeForItemAt中是错误的-旋转后可以工作

我的 PyCFunction 第一次工作,但在连续迭代后导致段错误

WordPress: $wpdb->get_results(); 第一次循环后返回错误结果

使用 selenium 运行循环会在第一次迭代后引发错误

Django Heroku 推送在第一次后因 Grep 使用错误而失败

UITableviewCell 中的 UICollectionView 第一次给出错误的 contentSizeHeight 但滚动后变为 true

第一次输入错误后如何检查输入是否与列表中的项目相同?

Pytest 在第一次失败后停止运行

创建索引后的第一次查询很慢

为什么在第一次迭代后就停止了?

第一次后停止读取NFC标签

While 循环在第一次迭代后停止

inotify脚本在第一次更改后停止

toggleClass()在第一次后不起作用

While 循环在第一次迭代后中断

scheduleAtFixedRate第一次运行后未执行

第一次输入后隐藏占位符

第一次循环代码后,“闹钟”中断