为什么JPA具有@Transient批注?


Answers:


454

Java的transient关键字用于表示不对字段进行序列化,而JPA的@Transient注释用于表示不将字段保留在数据库中,即它们的语义不同。


3
是的,语义不同。但是,为什么JPA是这样设计的?
Dilum Ranatunga

1
不确定我是否了解您,但请看一下“帕斯卡·蒂万(Pascal Thivent)”的回答;)
Jawher 2010年

30
这很方便,因为您可能不想将数据存储在数据库中,但是您确实希望将其存储在使用序列化来存储/恢复实体的JPA Chaching系统中。
Kdeveloper 2010年

1
什么“ JPA缓存系统”使用序列化来存储/恢复实体?JPA实现可以按其希望的任何方式缓存对象,而序列化不会进入该对象。
DataNucleus

@Jawher,这里对于暂态不耐性意味着不要保留任何值,否则它将为该属性插入默认值。
Satish Sharma

115

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


感谢您的回答帕斯卡尔。作为注释的注释:“您可能想要拥有@Transient属性,并且仍对其进行序列化。” (这就是我一直在寻找的东西)我还想补充一点,事实并非如此。如果将一个变量设置为瞬时变量,那么您将无法持久保留该变量。
jfajunior

96

正如其他人所说的,@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时,它会持久化genderid并且不会尝试持久化辅助布尔方法-如果没有@Transient基础系统,则会抱怨Entity类Person丢失了setMale()setFemale()方法也就不会持久化Person


@psp您能解释为什么/如何导致未指定行为的更多信息吗?谢谢!
taiduckman

@ 40Plot规格说明如下
psp

7
这应该是恕我直言,是可以接受的答案,因为它更多地说明了当前接受的答案...
Honza Zidek 2015年

53

目的不同:

transient关键字和@Transient注释有两个不同的目的:一个交易序列化,并与一个交易的持久性。作为程序员,我们经常将这两个概念合而为一,但这通常并不准确。持久性是指状态的特性超过了创建状态的过程。Java中的序列化是指将对象的状态编码/解码为字节流的过程。

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

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

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

这就引出了一个问题:为什么有人要序列化一个未持久化到应用程序数据库的字段?现实情况是,序列化不仅用于持久性。在企业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使用注释了@TransientSolution通过算法定位最终版本后,JPA会直接将其持久化,而无需使用ProgressReport


1
如果它们实际上是不同的关注点,那么肯定存在一个包含细微差别的单词。为什么超载这个词?作为一个初步建议,@Unpersisted
Dilum Ranatunga

4
我个人喜欢@Ephemeral。根据梅里亚姆·韦伯斯特(Merriam Webster)的说法:短暂的东西在1600年代首次以英语印刷时,“它是一个科学术语,用于短期发烧,后来应用于寿命很短的生物(例如昆虫和花朵)。不久之后,它获得了一种泛指,指的是任何短暂而短暂的事物(例如“短暂的快乐”)。”
奥斯丁D

1
我也很喜欢这个答案,它提到JPA将transient字段视为隐含@Transient注释。因此,如果您使用transient关键字来防止字段的序列化,那么该字段也不会最终出现在数据库中。
neXus

17

如果只希望某个字段不会保留,那么瞬时@Transient都可以工作。但是问题是为什么@Transient因为瞬态已经存在。

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

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


您能否提供示例以使其更清楚?
严苛Kanakhara

有没有注释,jpa将其视为瞬态,而杰克逊则不会?
Kalpesh Soni

0

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.