尝试读取加密文本时,使用JPA / Hibernate进行OptimisticLockException

时间:2012-02-01 13:21:47

标签: hibernate jpa encryption jasypt

我们需要在使用JPA存储它们时对其进行加密,并在读取时对其进行解密。首先,我们不能使用一些hibernate配置或任何其他配置文件,因为我们的属性是通用的。这意味着我们的属性看起来像这样(简单来说,我们已经在这里实现了一些处理):

@Entity
@Table(name = "PROPERTY")
@Access(AccessType.FIELD)
public class Property implements Serializable
{
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "PRO_ID")
    private long id;

    @Version
    @Temporal(value = TemporalType.TIMESTAMP)
    @Column(name = "PRO_VERSION")
    private Date version;

    @Column(name = "PRO_KEY")
    private String key;

    @Transient
    private String value;

    @Column(name = "PRO_ENCRYPTED")
    private boolean encrypted = false;

    public long getId()
    {
        return id;
    }

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

    public Date getVersion()
    {
        return version;
    }

    public void setVersion(Date version)
    {
        this.version = version;
    }

    public String getKey()
    {
        return key;
    }

    public void setKey(String key)
    {
        this.key = key;
    }

    public String getValue()
    {
        return value;
    }

    public void setValue(String value)
    {
        this.value = value;
    }

    public boolean isEncrypted()
    {
        return encrypted;
    }

    public void setEncrypted(boolean encrypted)
    {
        this.encrypted = encrypted;
    }

    @Access(AccessType.PROPERTY)
    @Column(name = "PRO_VALUE")
    protected String getValueDatabase()
    {
        // TODO: add decryption
        return value;
    }

    protected void setValueDatabase(String value)
    {
        // TODO: add encryption
        this.value = value;
    }
}

(我们可以通过isEncrypted()方法区分要加密的属性。根据属性设置为true或false)。 Out Encryptor类(简化)适用于Jasypt:

public final class MyEncrypter
{
    private static final String password = "AHKG@a4SjHH5%j%974";
    private static final StandardPBEStringEncryptor encryptor;

    static 
    {
        encryptor = new StandardPBEStringEncryptor();
        encryptor.setPassword(password);
    }

    public final static String encrypt(String string)
    {
           return encryptor.encrypt(string);
    }

        public final static String decrypt(String encrypted)
        {
            return encryptor.decrypt(encrypted);
        }
}

加密/解密有效。实际上我们的整个持久性处理工作。我们可以保存加密数据。但是,当我们读取加密数据时,我们得到以下结果:

javax.persistence.OptimisticLockException: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [at.jit.remind.jee.domain.context.model.Property#10]

奇怪的是,只有当Hibernates尝试更新加密文本时才会发生这种情况。但是当我们对我们的文本进行伪加密和伪解密时,它不会发生。这意味着我们反转文本,用Hibernate存储反向文本,并在Hibernate尝试更新它时“解密”它。所以我们的整个处理工作,但是当我们使用“真正的”加密时它可能不起作用的原因是什么?有什么想法吗?

(同样,en-和解密本身也可以。我让它在不同的JUnit类中运行以确保这一点。)

2 个答案:

答案 0 :(得分:1)

我们决定使用另一种加密方式,因为显然jasypt对Hibernate做了一些奇怪的事情。似乎这种加密/解密在某种程度上会产生Hibernate的“脏标志”,因此Hibernate会尝试更新数据库条目,尽管加密会同时更改值。无法隔离它。

答案 1 :(得分:0)

这是因为您的对象仍然附加到hibernate会话并且其内部状态已更改。首先尝试调用session.evict(object),然后更改要加密的文本。