为什么JPA有@Transient注释?

时间:2010-01-28 13:00:20

标签: java jpa java-ee annotations transient

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

8 个答案:

答案 0 :(得分:388)

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

答案 1 :(得分:102)

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

答案 2 :(得分:85)

正如其他人所说,@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

答案 3 :(得分:40)

目的不同:

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

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;

}

Solution类可能如下所示:

@Entity
public class Solution implements Serializable{

    private static final long serialVersionUID = 1L;

    double[][] dataArray;
    Properties properties;
}

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

答案 4 :(得分:17)

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

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

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

答案 5 :(得分:1)

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

example:

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

userRoleJoinRepository.save(user2);

答案 6 :(得分:0)

我会尝试回答"为什么"的问题。 想象一下,如果您拥有一个包含表中大量列的庞大数据库,并且您的项目/系统使用工具从数据库生成实体。 (Hibernate有那些等等......) 现在,假设您的业务逻辑需要一个特定的字段不被保留。你必须"配置"你的实体以特定的方式。 虽然Transient关键字适用于对象 - 因为它在java语言中运行,但@Transient仅用于回答仅与持久性任务相关的任务。

答案 7 :(得分:0)

对于 Kotlin 开发人员,请记住Java @Transient关键字成为内置的Kotlin @Transient批注。因此,如果您在实体中使用JPA import javax.persistence.Transient ,请确保已导入JPA:

library(tidyverse)
set.seed(1)
bmi <- runif(100, 10, 50)
income <- rnorm(100, 400, 10)
id <- 1:100

df <- data.frame(id = id, bmi = bmi, income = icnome)

res <- df %>% 
  mutate(BMI_cat = cut(
    x = bmi,
    breaks = c(0, 18.5, 25, 30, 35, Inf),
    labels = c("underweight", "normal", "overweight", "obese", "extreme"),
    ordered_result = T
  ))

ggplot(res, aes(income)) +
  geom_histogram(bins = 10) +
  facet_wrap(~BMI_cat, scales = "fixed")