现在的位置: 首页 > 综合 > 正文

Java对象以Blob存储,及序列化反序列化 (3)

2013年12月01日 ⁄ 综合 ⁄ 共 7387字 ⁄ 字号 评论关闭

在完成之前2篇文章内容之后,我们讨论下以下情况。

项目要改版,TUser或者User要修改属性,添加或者删除某些字段,那么数据库已保存的数据还能被反序列化为原有对象,并进行扩展么?

修改User.java

package cn.vicky.po.vo;

import java.io.Serializable;

/**
 *
 * @author Vicky.H
 */
public class User implements Serializable {

    private static final long serialVersionUID = 1L;
    /** 新增加的属性 **/
    private String address;
    
    private String username;
    private String password;
    private boolean sex;
    private short age;
    
    /** 新增加的属性 **/
    private int cardnum;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public short getAge() {
        return age;
    }

    public void setAge(short age) {
        this.age = age;
    }

    public String getPassword() {
        return password;
    }

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

    public boolean isSex() {
        return sex;
    }

    public void setSex(boolean sex) {
        this.sex = sex;
    }

    public String getUsername() {
        return username;
    }

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

    public int getCardnum() {
        return cardnum;
    }

    public void setCardnum(int cardnum) {
        this.cardnum = cardnum;
    }
    
}

修改App.java

package cn.vicky.tmp1;

import cn.vicky.po.TUser;
import cn.vicky.po.vo.User;
import java.io.IOException;
import java.sql.SQLException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

/**
 *
 */
public class App {

    public static void create1(EntityManager em) {
        User user = new User();
        user.setUsername("Vicky");
        user.setPassword("123456");
        short age = 25;
        user.setAge(age);
        user.setSex(true);

        TUser tUser = new TUser();
        tUser.setUser(user);
        em.persist(tUser);
    }

    public static void create2(EntityManager em) {
        User user = new User();
        user.setUsername("Jack");
        user.setPassword("654321");
        short age = 37;
        user.setAge(age);
        user.setSex(true);

        TUser tUser = new TUser();
        tUser.setUser(user);
        em.persist(tUser);
    }

    /**
     * 通过主键获得TUser对象,并且获得User对象
     * @param em 
     */
    public static void find1(EntityManager em) {
        TUser tUser = em.find(TUser.class, 1);
        User user = tUser.getUser();
        System.out.println("user.getUsername() = " + user.getUsername());
        System.out.println("user.getPassword() = " + user.getPassword());
        System.out.println("user.getAge() = " + user.getAge());
        System.out.println("user.isSex() = " + user.isSex());
        
        System.out.println("user.getAddress() = " + user.getAddress());
        System.out.println("user.getCardnum() = " + user.getCardnum());
    }

    /**
     * 直接查询Blob数据并强制转换为User对象
     * @param em 
     */
    public static void find2(EntityManager em) {
        User user = (User) em.createQuery("select o.user from t_user o where o.id = 1").getSingleResult();
        System.out.println("user.getUsername() = " + user.getUsername());
        System.out.println("user.getPassword() = " + user.getPassword());
        System.out.println("user.getAge() = " + user.getAge());
        System.out.println("user.isSex() = " + user.isSex());
        
        System.out.println("user.getAddress() = " + user.getAddress());
        System.out.println("user.getCardnum() = " + user.getCardnum());
    }
    
    public static void main(String[] args) throws SQLException, IOException, ClassNotFoundException {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("pu");
        EntityManager em = emf.createEntityManager();

        em.getTransaction().begin();

//        create1(em);
//        create2(em);
        find1(em);
        find2(em);

        em.getTransaction().commit();

        em.close();
        emf.close();
    }
}

运行:

Hibernate: select tuser0_.id as id0_0_, tuser0_.user as user0_0_ from t_user tuser0_ where tuser0_.id=?
user.getUsername() = Vicky
user.getPassword() = 123456
user.getAge() = 25
user.isSex() = true
user.getAddress() = null
user.getCardnum() = 0
Hibernate: select tuser0_.user as col_0_0_ from t_user tuser0_ where tuser0_.id=1 limit ?
user.getUsername() = Vicky
user.getPassword() = 123456
user.getAge() = 25
user.isSex() = true
user.getAddress() = null
user.getCardnum() = 0

 

尝试删除属性后,程序执行依然正确。似乎挺简单的,没有什么值得注意的。

但这里的确有个地方需要注意,那就是:

private static final long serialVersionUID = 1L;

我们尝试删除User.java 的 private static final long serialVersionUID = 1L;

再次运行App.java

Hibernate: select tuser0_.id as id0_0_, tuser0_.user as user0_0_ from t_user tuser0_ where tuser0_.id=?
Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.type.SerializationException: could not deserialize
 at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:614)
 at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:202)
 at cn.vicky.tmp1.App.find1(App.java:47)
 at cn.vicky.tmp1.App.main(App.java:81)
Caused by: org.hibernate.type.SerializationException: could not deserialize
 at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:188)
 at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:211)
 at org.hibernate.type.SerializableType.fromBytes(SerializableType.java:105)
 at org.hibernate.type.SerializableType.get(SerializableType.java:62)
 at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:184)
 at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:173)
 at org.hibernate.type.AbstractType.hydrate(AbstractType.java:105)
 at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2124)
 at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1404)
 at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1332)
 at org.hibernate.loader.Loader.getRow(Loader.java:1230)
 at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:603)
 at org.hibernate.loader.Loader.doQuery(Loader.java:724)
 at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
 at org.hibernate.loader.Loader.loadEntity(Loader.java:1881)
 at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:71)
 at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:65)
 at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3072)
 at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:434)
 at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:415)
 at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:165)
 at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:223)
 at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:126)
 at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:905)
 at org.hibernate.impl.SessionImpl.get(SessionImpl.java:842)
 at org.hibernate.impl.SessionImpl.get(SessionImpl.java:835)
 at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:182)
 ... 2 more
Caused by: java.io.InvalidClassException: cn.vicky.po.vo.User; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 993454148924749307
 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:562)
 at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1583)
 at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)
 at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)
 at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
 at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
 at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:181)
 ... 28 more

 

错误原因:

serialVersionUID用来表明类的不同版本间的兼容性 简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来 的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序 列化,否则就会出现序列化版本不一致的异常。

当实现java.io.Serializable接口的实体(类)没有显式地定义一个名为serialVersionUID,类型为long的变 量时,Java序列化机制会根据编译的class自动生成一个serialVersionUID作序列化版本比较用,这种情况下,只有同一次编译生成的 class才会生成相同的serialVersionUID 。

如果我们不希望通过编译来强制划分软件版本,即实现序列化接口的实体能够兼容先前版本,未作更改的类,就需要显式地定义一个名为serialVersionUID,类型为long的变量,不修改这个变量值的序列化实体都可以相互进行串行化和反串行化。

 

你可以很轻松的在google上查询到详细的解释。

抱歉!评论已关闭.