关于java:为什么JPA有一个@Transient注释?

Why does JPA have a @Transient annotation?

Java具有EDCOX1×0×关键字。为什么JPA有EDOCX1?1,而不是简单地使用已经存在的Java关键字?


Java的EDCOX1×0×关键字用于表示字段不被序列化,而JPA的EDOCX1×1注释用于指示字段不在数据库中持久化,即它们的语义不同。


因为它们有不同的含义。@Transient注释告诉JPA提供者不要持久化任何(非transient属性。另一个告诉序列化框架不要序列化属性。您可能希望拥有一个@Transient属性,并且仍然对其进行序列化。


正如其他人所说,@Transient用于标记不应持久化的字段。考虑这个简短的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public enum Gender { MALE, FEMALE, UNKNOWN }

@Entity
public Person {
    private Gender g;
    private long id;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    public long getId() { return id; }
    public void setId(long id) { this.id = id; }

    public Gender getGender() { return g; }    
    public void setGender(Gender g) { this.g = g; }

    @Transient
    public boolean isMale() {
        return Gender.MALE.equals(g);
    }

    @Transient
    public boolean isFemale() {
        return Gender.FEMALE.equals(g);
    }
}

当这个类被送入JPA时,它会继续使用genderid,但不会尝试继续使用辅助布尔方法-如果没有@Transient,底层系统会抱怨实体类Person缺少setMale()setFemale()方法,因此根本不会继续使用Person


目的不同:

transient关键字和@Transient注释有两个不同的用途:一个用于序列化,另一个用于持久性。作为程序员,我们经常将这两个概念结合在一起,但一般来说这并不准确。持久性是指状态的特征,它比创建它的过程要长。Java中的序列化是指将对象的状态编码为字节流的过程。

transient关键字是比@Transient强的条件:

如果一个字段使用transient关键字,当对象转换为字节流时,该字段将不会被序列化。此外,由于JPA将标记有transient关键字的字段视为具有@Transient注释,因此JPA也不会保留该字段。

另一方面,当对象被序列化时,仅注释@Transient的字段将被转换为字节流,但JPA不会将其持久化。因此,transient关键字是比@Transient注释更强的条件。

例子

这就引出了一个问题:为什么有人要序列化一个未持久化到应用程序数据库的字段?事实上,序列化不仅仅用于持久性。在企业Java应用程序中,需要有一种机制来在分布式组件之间交换对象;序列化提供了一种通用的通信协议来处理这一问题。因此,一个字段可以保存关键信息,以便进行组件间通信;但是从持久性的角度来看,同一个字段可能没有任何价值。

例如,假设一个优化算法在服务器上运行,并且假设这个算法需要几个小时才能完成。对于客户来说,拥有最新的解决方案集非常重要。因此,客户端可以订阅服务器,并在算法的执行阶段接收定期更新。这些更新是使用ProgressReport对象提供的:

1
2
3
4
5
6
7
8
9
10
11
@Entity
public class ProgressReport implements Serializable{

    private static final long serialVersionUID = 1L;

    @Transient
    long estimatedMinutesRemaining;
    String statusMessage;
    Solution currentBestSolution;

}

Solution类可能如下所示:

1
2
3
4
5
6
7
8
@Entity
public class Solution implements Serializable{

    private static final long serialVersionUID = 1L;

    double[][] dataArray;
    Properties properties;
}

服务器将每个ProgressReport保存到其数据库中。服务器不关心持久的estimatedMinutesRemaining,但是客户机当然关心这些信息。因此,使用@TransientestimatedMinutesRemaining进行注释。当最终的Solution由算法定位时,JPA直接将其持久化,而不使用ProgressReport


如果您只需要一个字段,那么它就不会被持久化,不管是瞬时工作还是@transient工作。但问题是,既然瞬态已经存在,为什么@transient?

因为@transient field仍将被序列化!

假设您创建了一个实体,进行一些CPU消耗计算以得到一个结果,这个结果将不会保存在数据库中。但是,您想将实体发送到其他Java应用程序,以便使用JMS,那么您应该使用EDCOX1 OR 1,而不是JavaScript关键字EDCOX1(0)。因此,在其他虚拟机上运行的接收器可以节省重新计算的时间。


我会尽量回答"为什么"这个问题。想象一下这样一种情况:您有一个巨大的数据库,表中有很多列,并且您的项目/系统使用工具从数据库生成实体。(冬眠有那些……)现在,假设根据您的业务逻辑,您需要一个特定的字段不被持久化。您必须以特定的方式"配置"您的实体。虽然瞬态关键字在一个对象上工作——因为它在Java语言中运行,所以@瞬态只被设计来回答只涉及持久任务的任务。