为什么JPA有@Transient注释?

dea*_*mon 269 java annotations jpa transient java-ee

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

小智 417

Java的transient关键字用于表示字段不是序列化的,而JPA的@Transient注释用于指示字段不在数据库中持久化,即它们的语义不同.

  • 这很方便,因为您可能不希望将数据存储在数据库中,但您确实希望将其存储在JPA Chaching系统中,该系统使用序列化来存储/恢复实体. (29认同)
  • 是的,语义是不同的.但是为什么JPA这样设计呢? (3认同)

Pas*_*ent 109

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

  • 感谢帕斯卡的回答。正如您的评论中的注释:“您可能希望拥有一个 @Transient 属性并仍然对其进行序列化。” (这就是我一直在寻找的)我还想补充一点,事实并非如此。如果将变量设置为瞬态变量,则无法持久保存它。 (3认同)

Esk*_*sko 90

正如其他人所说,@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

当这个类被输送到JPA,它坚持了genderid,但不会尝试坚持助手布尔方法-无@Transient底层系统会抱怨说,实体类Person丢失setMale()setFemale()方法,所以并不会持续Person的.

  • 这应该是恕我直言的接受答案,因为它更能解释当前接受的一个...... (6认同)

Aus*_*n D 47

目的不同:

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

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

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

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

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

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

@Entity
public class ProgressReport implements Serializable{

    private static final long serialVersionUID = 1L;

    @Transient
    long estimatedMinutesRemaining;
    String statusMessage;
    Solution currentBestSolution;

}
Run Code Online (Sandbox Code Playgroud)

Solution类可能是这样的:

@Entity
public class Solution implements Serializable{

    private static final long serialVersionUID = 1L;

    double[][] dataArray;
    Properties properties;
}
Run Code Online (Sandbox Code Playgroud)

服务器将每个持久保存ProgressReport到其数据库.服务器并不关心持久性estimatedMinutesRemaining,但客户端当然关心这些信息.因此,estimatedMinutesRemaining使用注释@Transient.当Solution算法找到最终结果时,JPA会直接保留它,而不使用ProgressReport.

  • 我个人喜欢`@Ephemeral`.根据梅里亚姆·韦伯斯特(Merriam Webster)的说法:当17世纪首次用英语印刷短篇小说时,"这是一个科学术语,适用于短期发烧,后来适用于寿命很短的生物(如昆虫和花卉).不久之后它获得了一种延伸的意义,指的是任何短暂的和短暂的(如"短暂的快乐")." (4认同)
  • 如果它们实际上是不同的关注点,那么肯定存在一个不同的词来捕捉细微差别。为什么要重载这个词?作为入门建议,`@Unpersisted`。 (2认同)
  • 我还喜欢这个答案的一点是,它提到 JPA 将“transient”字段视为隐式具有“@Transient”注释。因此,如果您使用“transient”关键字来防止字段序列化,那么它也不会最终出现在数据库中。 (2认同)
  • 这是最准确的答案 (2认同)

She*_*g.W 17

如果你只是想要一个字段不会被持久化,瞬态@Transient工作.但问题是为什么@Transient因为瞬态已经存在.

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

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


Lla*_*ama 6

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

例子:

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

userRoleJoinRepository.save(user2);
Run Code Online (Sandbox Code Playgroud)

  • 这并不能回答问题。问题不是“@Transient”做什么?而是“为什么不使用关键字”。 (6认同)

Pau*_*son 5

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

import javax.persistence.Transient
Run Code Online (Sandbox Code Playgroud)