【问题标题】:Why does JPA have a @Transient annotation?为什么 JPA 有 @Transient 注解?
【发布时间】:2011-01-10 09:49:40
【问题描述】:

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

【问题讨论】:

    标签: java jpa jakarta-ee annotations transient


    【解决方案1】:

    Java的transient关键字用来表示一个字段不被序列化,而JPA的@Transient注解用来表示一个字段不被持久化到数据库中,即它们的语义不同。

    【讨论】:

    • 是的,语义不同。但是为什么 JPA 是这样设计的呢?
    • 不确定我是否理解你,但看看“Pascal Thivent”的回答 ;)
    • 这很方便,因为您可能不想将数据存储在数据库中,但您确实希望将其存储在使用序列化来存储/恢复实体的 JPA Chaching 系统中。
    • 什么“JPA 缓存系统”使用序列化来存储/恢复实体? JPA 实现可以以任何他们希望的方式缓存对象,并且序列化不会进入其中。
    【解决方案2】:

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

    【讨论】:

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

    正如其他人所说,@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,底层系统会抱怨实体类 Person缺少 setMale()setFemale() 方法,因此根本不会持续存在 Person

    【讨论】:

    • @psp 你能解释一下它为什么/如何导致未指定的行为吗?谢谢!
    • @40Plot 规范说明
    • 这应该是恕我直言,接受的答案,因为它更多地解释了当前接受的答案......
    【解决方案4】:

    目的不同:

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

    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 使用@Transient 进行注释。当最终的Solution被算法定位后,直接被JPA持久化,不使用ProgressReport

    【讨论】:

    • 如果它们实际上是不同的关注点,那么肯定存在一个不同的词来捕捉细微差别。为什么要超载这个词?作为初学者的建议,@Unpersisted.
    • 我个人喜欢@Ephemeral。根据 Merriam Webster 的说法:当 ephemeral 在 1600 年代首次以英文印刷时,“它是一个科学术语,适用于短期发烧,后来适用于寿命很短的生物体(如昆虫和花卉)。不久之后,它获得了扩展的含义,指的是任何转瞬即逝的事物(如“短暂的快乐”)。”
    • 我还喜欢这个答案的一点是,它提到 JPA 将 transient 字段视为隐式具有 @Transient 注释。因此,如果您使用transient 关键字来防止字段序列化,那么它也不会在数据库中结束。
    【解决方案5】:

    如果您只想让字段不被持久化,transient@Transient 都可以。但问题是为什么 @Transient 因为 transient 已经存在。

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

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

    【讨论】:

    • 您能否提供示例以使其更清楚?
    • 是否有注释 jpa 将视为瞬态但杰克逊不会?
    【解决方案6】:

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

    import javax.persistence.Transient
    

    【讨论】:

      【解决方案7】:

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

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

      userRoleJoinRepository.save(user2);
      
      

      【讨论】:

        【解决方案8】:

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

        【讨论】:

          猜你喜欢
          • 2014-02-23
          • 1970-01-01
          • 2017-08-02
          • 2015-06-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-08-10
          • 1970-01-01
          相关资源
          最近更新 更多