为什么JPA有一个@Transient注释?

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

402459 次浏览

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

因为它们有不同的含义。@Transient注释告诉JPA提供者不要持久化任何(非-transient)属性。另一个告诉序列化框架不要序列化某个属性。你可能想要有一个@Transient属性并仍然序列化它。

正如其他人所说,@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,但不会尝试持久化helper布尔方法——没有@Transient,底层系统会抱怨实体类Person缺少setMale()setFemale()方法,因此根本不会持久化Person

如果你只是想要一个字段不会被持久化,瞬态@Transient都可以。但问题是既然瞬态已经存在,为什么要用@Transient

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

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

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

目的不同:

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

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

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

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

例子

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

例如,假设在服务器上运行一个优化算法,并假设该算法需要几个小时才能完成。对于客户来说,拥有最新的解决方案集非常重要。因此,客户端可以订阅服务器,并在算法执行阶段定期接收更新。这些更新是使用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

对于芬兰湾的科特林开发人员,请记住Java transient关键字将成为内置的Kotlin @Transient注释。因此,如果你在你的实体中使用JPA @Transient,请确保你有JPA导入:

import javax.persistence.Transient

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

example: .

我保存对象到数据库使用jpa存储库内置的保存方法,这样:

userRoleJoinRepository.save(user2);