JPA 的瞬态关键字未按预期工作
Posted
技术标签:
【中文标题】JPA 的瞬态关键字未按预期工作【英文标题】:transient keyword with JPA not working as expected 【发布时间】:2012-12-22 09:35:45 【问题描述】:我读过@transient 和transient 关键字之间的讨论:Why does JPA have a @Transient annotation?
但是当我使用 java 关键字而不是 @Transient 表示法使某些字段瞬态时,这些字段不会在创建表时在我的表中创建。这是为什么呢?
这是我的 persistence.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="someDB" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>somewhere.classnameA</class>
<class>somewhere.classnameB</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url"
value="jdbc:mysql://localhost:3306/project" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="" />
<!-- EclipseLink should create the database schema automatically -->
<property name="eclipselink.ddl-generation" value="create-or-extend-tables" />
<property name="eclipselink.ddl-generation.output-mode"
value="both" />
</properties>
这是一个示例实体:
import java.sql.Timestamp;
import com.google.gwt.user.client.rpc.IsSerializable;
@Entity
public class Session implements IsSerializable
@Id
@Basic(optional = false)
@Column(length = 36)
private String sessionID;
@Version
@Basic(optional = false)
transient private Timestamp lastModification;
@Basic(optional = false)
transient private Timestamp expireTime;
@OneToOne(optional = false)
private User user;
protected Session()
// constructor server side
public Session(String sessionID, User user, Timestamp expireTime)
this.sessionID = sessionID;
this.user = user;
this.expireTime = expireTime;
public String getSessionID()
return sessionID;
public void setSessionID(String sessionID)
this.sessionID = sessionID;
public Timestamp getLastModification()
return lastModification;
public void setLastModification(Timestamp lastModification)
this.lastModification = lastModification;
public Timestamp getExpireTime()
return expireTime;
public void setExpireTime(Timestamp expireTime)
this.expireTime = expireTime;
public User getUser()
return user;
public void setUser(User user)
this.user = user;
@Override
@Transient
public String toString()
String userID = (user != null) ? String.valueOf(user.getUserID()) : "?";
return String.format("(%s)%s", userID, sessionID);
注意:在上面的文件中,我删除了一些不重要的导入。 在生成的表中只有两个字段,即 SESSIONID 和 USER_USERID。 我也使用了persistence api 1.0
【问题讨论】:
persistence.xml 不足以回答这个问题。显示你在课堂上使用瞬态的地方。 我添加了Session实体作为例子 【参考方案1】:从 JPA 的角度来看,注解和修饰符是完全等价的,都意味着该字段不是持久化的。请参阅JSR 220 Specification 的第 2.1.1 段,其中写道:
If the entity has field-based access, the persistence provider runtime accesses
instance variables directly. All non-transient instance variables that are not
annotated with the Transient annotation are persistent.
【讨论】:
在这种情况下,有没有其他方法可以指定某些字段应该存储在数据库中,而不是通过网络发送?我正在寻找制作 DTO 的替代方法。 改为注释属性访问方法。但是,如果您在序列化对象中合并,映射瞬态字段会导致问题 - 数据库中的值最终可能会被 null 覆盖。 @GWT4Ever 这取决于您如何将实体发送给客户端。如果使用 JAX-WS 公开 Web 服务接口,您可以使用@XmlRootElement
对其进行注释,并使用 @XmlTransient
标记您不想传输的字段。
@Chris 这就是为什么transient
修饰符等同于@Transient
注释的原因,这两种方式字段都没有映射到任何数据库列。【参考方案2】:
瞬态字段不参与持久化,它们的值永远不会存储在数据库中,类似于 Java 中不参与序列化的瞬态字段
【讨论】:
【参考方案3】:书中的答案 - Pro JPA 掌握 JPA
.. 我们使用了 transient 修饰符而不是 @Transient 注释,因此如果 Employee(例如实体)从一个 VM 序列化到另一个 VM,则该字段将重新初始化以对应于新 VM 的语言环境。 如果在序列化过程中应保留非持久值,则应使用注释而不是修饰符。
【讨论】:
以上是关于JPA 的瞬态关键字未按预期工作的主要内容,如果未能解决你的问题,请参考以下文章
对象引用了一个未保存的瞬态实例 - Spring,JPA Hibernate