338

Java 有transient关键字。为什么 JPA 有@Transient而不是简单地使用已经存在的 java 关键字?

4

8 回答 8

534

Java 的transientkeyword 用来表示字段不被序列化,而JPA 的@Transientannotation 用来表示字段不被持久化到数据库中,即它们的语义不同。

于 2010-01-28T13:03:20.333 回答
128

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

于 2010-01-28T13:04:01.310 回答
118

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

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 时,它会持久化gender并且id不会尝试持久化辅助布尔方法——如果没有@Transient底层系统会抱怨Person缺少Entity 类setMale()setFemale()方法,因此根本不会持久化Person

于 2010-01-28T13:29:01.640 回答
66

目的不同:

transient关键字和注解有两种不同的@Transient用途:一种处理序列化,一种处理持久化。作为程序员,我们经常将这两个概念合二为一,但这通常并不准确。持久性是指状态的特征,它比创建它的过程更长。Java中的序列化是指将对象的状态编码/解码为字节流的过程。

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

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

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

例子

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

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

@Entity
public class ProgressReport implements Serializable{

    private static final long serialVersionUID = 1L;

    @Transient
    long estimatedMinutesRemaining;
    String statusMessage;
    Solution currentBestSolution;

}

该类Solution可能如下所示:

@Entity
public class Solution implements Serializable{

    private static final long serialVersionUID = 1L;

    double[][] dataArray;
    Properties properties;
}

服务器将每个持久化ProgressReport到其数据库中。服务器不关心持久estimatedMinutesRemaining化,但客户端当然关心这些信息。因此,estimatedMinutesRemaining使用 注释@Transient。当 finalSolution被算法定位时,JPA 直接将其持久化,而不使用ProgressReport.

于 2016-02-26T01:55:26.033 回答
21

如果您只是想要一个字段不会被持久化,那么瞬态@Transient都可以工作。但问题是为什么@Transient因为transient已经存在。

因为@Transient 字段仍然会被序列化!

假设您创建一个实体,进行一些 CPU 消耗计算以获得结果,并且该结果不会保存在数据库中。但是您想将实体发送给其他 Java 应用程序以供 JMS 使用,那么您应该使用@Transient,而不是 JavaSE 关键字transient。因此,在其他 VM 上运行的接收器可以节省重新计算的时间。

于 2015-11-18T04:15:45.947 回答
3

对于Kotlin开发人员,请记住 Javatransient关键字成为内置的 Kotlin@Transient注释。@Transient因此,如果您在实体中使用 JPA,请确保您具有 JPA 导入:

import javax.persistence.Transient
于 2020-12-02T12:14:26.320 回答
3

通俗的讲,如果在实体的某个属性上使用@Transient注解:这个属性会被单挑出来,不会存入数据库。实体内对象的其余属性仍将被保存。

例子:

我使用保存方法中内置的 jpa 存储库将对象保存到数据库,如下所示:

userRoleJoinRepository.save(user2);

于 2020-12-19T08:26:44.797 回答
1

我将尝试回答“为什么”的问题。想象一下这样一种情况,你有一个巨大的数据库,表中有很多列,你的项目/系统使用工具从数据库生成实体。(Hibernate 有这些,等等......)现在,假设根据您的业务逻辑,您需要一个特定的字段不被持久化。您必须以特定方式“配置”您的实体。虽然 Transient 关键字适用于对象 - 因为它在 Java 语言中运行,但 @Transient 仅设计用于回答仅与持久性任务相关的任务。

于 2015-12-16T19:36:37.560 回答