当从 hibernate 4.3.11 迁移到 5.2.10 并使用 EntityManager 而不是 SessionFactory 时,hibernate session.get 不加载持久对象
hibernate session.get does not load persistent object when migrate from hibernate 4.3.11 to 5.2.10 and use EntityManager insteadof SessionFactory
多年来我在一个项目中使用了 hibernate 4.3.11.Final 和 spring 4.3.1.RELEASE 到操纵和持久化对象。最近我迁移到休眠 5.2.10.Final 并遇到描述它的问题。我有两个域 class,如下所示:
public class Post extends BaseEntity<Long> {
private String title;
private Set<PostComment> comments = new HashSet<>(0);
// getters and setters removed for brevity
}
public class PostComment extends BaseEntity<Long> {
private Post post;
private String descripton;
// getters and setters removed for brevity
}
public abstract class BaseEntity<T> implements Serializable {
private T id;
}
这些是休眠映射文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="" table="tbl_post">
<id name="id" type="long" >
<column name="ID" />
<generator class="sequence" >
<param name="sequence">RGH.SEQ_POST</param>
</generator>
</id>
<property name="title" column="title" type="string" not-null="true" />
<set name="comments" inverse="true" cascade="save-update,merge">
<key>
<column name="post_id" not-null="true" />
</key>
<one-to-many class="com.rgh.PostComment" />
</set>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="" table="tbl_post_comment">
<id name="id" type="long" >
<column name="ID" />
<generator class="sequence" >
<param name="sequence">RGH.SEQ_POST_COMMENT</param>
</generator>
</id>
<property name="descripton" column="descripton" type="string" not-null="true" />
<many-to-one name="post" column="post_id" entity-name="com.rgh.Post" not-null="true" />
</class>
</hibernate-mapping>
在 PostService
class 中存在两种方法,一种是主题保留 Post
实体,它是 PostComment
的主题,另一种是保存 Post
实体并记录其 PostCommment
的计数。
@Service
public class PostService {
@Autowired
private PostRepository repo;
@Autowired
private PostCommentRepository commentRepo;
@Transactional
public Long save() {
Post post = new Post();
post.setTitle("sample post");
repo.save(post);
Set<PostComment> postComments = new HashSet<>();
for (int i = 0 ; i < 3 ; i++) {
PostComment postComment = new PostComment();
postComment.setPost(post);
postComment.setDescription("description " + i);
commentRepo.save(postComment);
}
return post.getId();
}
@Transactional
public int saveAndGetDetailsCount(Post entity) {
entity.setTitle(entity.getTitle() + " updated!");
repo.save(entity);
Post post = repo.loadById(entity.getId());
System.out.println(post.Comments().size());
return post.Comments().size();
}
}
PostRepository
和 PostCommentRepository
都是从 GenericRepository
扩展而来的,您可以在下面看到它:
@Repository
public class PostRepository extends GenericRepository<Post, Long> {
@Override
protected Class<Post> getDomainClass() {
return Post.class;
}
}
@Repository
public class PostCommentRepository extends GenericRepository<PostComment, Long> {
@Override
protected Class<PostComment> getDomainClass() {
return PostComment.class;
}
}
@Repository
public abstract class GenericRepository<T extends BaseEntity,PK extends Serializable> {
protected Class<T> domainClass = getDomainClass();
@Autowired
private SessionFactory sessionFactory;
public Session getSession() {
try {
return sessionFactory.getCurrentSession();
} catch (Exception e) {
}
return sessionFactory.openSession();
}
public PK save(T Entity) {
Session session = getSession();
if(entity.getId() == null) {
session.save(entity);
}
else {
entity = (T)session.merge(entity);
session.update(entity);
}
return entity.getId();
}
public T loadByEntityId(PK entityId) {
Session session = getSession();
return (T) session.get(domainClass.getName(), entityId);
}
}
当我调用 save
方法然后调用 saveAndGetDetailsCount
它更新实体然后执行 select...
查询以加载 Post
实体然后记录时一切正常3 和 post 评论。
但是在我迁移到休眠模式后 5.2.10.Final 并应用了这些更改:
@Entity
@Table(schema = "RGH", name = "TBL_POST")
@SequenceGenerator(name = "sequence_db", sequenceName = "RGH.SEQ_POST", allocationSize = 1)
public class Post extends BaseEntity<Long> {
@Column
private String title;
@OneToMany(mappedBy = "post", fetch = FetchType.LAZY)
@Cascade(value = { CascadeType.SAVE_UPDATE, CascadeType.MERGE })
private Set<PostComment> comments = new HashSet<>(0);
// getters and setters removed for brevity
}
@Entity
@Table(schema = "RGH", name = "TBL_POST_COMMENT")
@SequenceGenerator(name = "sequence_db", sequenceName = "RGH.SEQ_POST_COMMENT", allocationSize = 1)
public class PostComment extends BaseEntity<Long> {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "POST_ID", nullable = false)
private Post post;
@Column
private String descripton;
// getters and setters removed for brevity
}
public abstract class BaseEntity<T> implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence_db")
private T id;
}
然后 GenericRepository
我使用 EntityManager
得到 Session
class 如下所示:
@Repository
public abstract class GenericRepository<T extends BaseEntity,PK extends Serializable> {
protected Class<T> domainClass = getDomainClass();
/* changed */
@PersistenceContext
private EntityManager em;
public Session getSession() {
/* changed */
return em.unwrap(Session.class);
}
public PK save(T Entity) {
Session session = getSession();
if(entity.getId() == null) {
session.save(entity);
}
else {
entity = (T)session.merge(entity);
session.update(entity);
}
return entity.getId();
}
public T loadByEntityId(PK entityId) {
Session session = getSession();
return (T) session.get(domainClass.getName(), entityId);
}
}
现在,问题是,当我 运行 以前的方法调用时,在 saveAndGetDetailsCount
中,hibernate 不执行 select...
查询并记录 0 因为评论很重要。
我想知道为什么会这样。
更新
也许你会问为什么我没有使用 EntityManager
而不是 Session
,我使用 EntityManager
.
有一些限制
更新
当我调用 saveAndGetDetailsCount
时,entity
参数仅包含 id
和 title
,在接下来的几行中,您可以看到我想加载 comments
字段并获取它的大小。
如果实体已经附加到当前会话,为什么要生成查询?
还有,为什么要调用merge和update呢?您应该使用其中之一。但不是两者。
您的问题不在于迁移到休眠 5。我认为您的问题在于 transaction.When 在同一事务中坚持或合并调用,loadById 直到方法 return 才执行。您可以在之后刷新保存合并工作正常和你的对象加载。
将您的代码更改为此
@Repository
public abstract class GenericRepository<T extends BaseEntity,PK extends Serializable> {
protected Class<T> domainClass = getDomainClass();
/* changed */
@PersistenceContext
private EntityManager em;
public Session getSession() {
/* changed */
return em.unwrap(Session.class);
}
public PK save(T Entity) {
Session session = getSession();
if(entity.getId() == null) {
em.persist(entity);
}
else {
em.merge(entity);
em.flush();
}
return entity.getId();
}
public T loadByEntityId(PK entityId) {
Session session = getSession();
return (T) session.get(domainClass.getName(), entityId);
}
}
多年来我在一个项目中使用了 hibernate 4.3.11.Final 和 spring 4.3.1.RELEASE 到操纵和持久化对象。最近我迁移到休眠 5.2.10.Final 并遇到描述它的问题。我有两个域 class,如下所示:
public class Post extends BaseEntity<Long> {
private String title;
private Set<PostComment> comments = new HashSet<>(0);
// getters and setters removed for brevity
}
public class PostComment extends BaseEntity<Long> {
private Post post;
private String descripton;
// getters and setters removed for brevity
}
public abstract class BaseEntity<T> implements Serializable {
private T id;
}
这些是休眠映射文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="" table="tbl_post">
<id name="id" type="long" >
<column name="ID" />
<generator class="sequence" >
<param name="sequence">RGH.SEQ_POST</param>
</generator>
</id>
<property name="title" column="title" type="string" not-null="true" />
<set name="comments" inverse="true" cascade="save-update,merge">
<key>
<column name="post_id" not-null="true" />
</key>
<one-to-many class="com.rgh.PostComment" />
</set>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="" table="tbl_post_comment">
<id name="id" type="long" >
<column name="ID" />
<generator class="sequence" >
<param name="sequence">RGH.SEQ_POST_COMMENT</param>
</generator>
</id>
<property name="descripton" column="descripton" type="string" not-null="true" />
<many-to-one name="post" column="post_id" entity-name="com.rgh.Post" not-null="true" />
</class>
</hibernate-mapping>
在 PostService
class 中存在两种方法,一种是主题保留 Post
实体,它是 PostComment
的主题,另一种是保存 Post
实体并记录其 PostCommment
的计数。
@Service
public class PostService {
@Autowired
private PostRepository repo;
@Autowired
private PostCommentRepository commentRepo;
@Transactional
public Long save() {
Post post = new Post();
post.setTitle("sample post");
repo.save(post);
Set<PostComment> postComments = new HashSet<>();
for (int i = 0 ; i < 3 ; i++) {
PostComment postComment = new PostComment();
postComment.setPost(post);
postComment.setDescription("description " + i);
commentRepo.save(postComment);
}
return post.getId();
}
@Transactional
public int saveAndGetDetailsCount(Post entity) {
entity.setTitle(entity.getTitle() + " updated!");
repo.save(entity);
Post post = repo.loadById(entity.getId());
System.out.println(post.Comments().size());
return post.Comments().size();
}
}
PostRepository
和 PostCommentRepository
都是从 GenericRepository
扩展而来的,您可以在下面看到它:
@Repository
public class PostRepository extends GenericRepository<Post, Long> {
@Override
protected Class<Post> getDomainClass() {
return Post.class;
}
}
@Repository
public class PostCommentRepository extends GenericRepository<PostComment, Long> {
@Override
protected Class<PostComment> getDomainClass() {
return PostComment.class;
}
}
@Repository
public abstract class GenericRepository<T extends BaseEntity,PK extends Serializable> {
protected Class<T> domainClass = getDomainClass();
@Autowired
private SessionFactory sessionFactory;
public Session getSession() {
try {
return sessionFactory.getCurrentSession();
} catch (Exception e) {
}
return sessionFactory.openSession();
}
public PK save(T Entity) {
Session session = getSession();
if(entity.getId() == null) {
session.save(entity);
}
else {
entity = (T)session.merge(entity);
session.update(entity);
}
return entity.getId();
}
public T loadByEntityId(PK entityId) {
Session session = getSession();
return (T) session.get(domainClass.getName(), entityId);
}
}
当我调用 save
方法然后调用 saveAndGetDetailsCount
它更新实体然后执行 select...
查询以加载 Post
实体然后记录时一切正常3 和 post 评论。
但是在我迁移到休眠模式后 5.2.10.Final 并应用了这些更改:
@Entity
@Table(schema = "RGH", name = "TBL_POST")
@SequenceGenerator(name = "sequence_db", sequenceName = "RGH.SEQ_POST", allocationSize = 1)
public class Post extends BaseEntity<Long> {
@Column
private String title;
@OneToMany(mappedBy = "post", fetch = FetchType.LAZY)
@Cascade(value = { CascadeType.SAVE_UPDATE, CascadeType.MERGE })
private Set<PostComment> comments = new HashSet<>(0);
// getters and setters removed for brevity
}
@Entity
@Table(schema = "RGH", name = "TBL_POST_COMMENT")
@SequenceGenerator(name = "sequence_db", sequenceName = "RGH.SEQ_POST_COMMENT", allocationSize = 1)
public class PostComment extends BaseEntity<Long> {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "POST_ID", nullable = false)
private Post post;
@Column
private String descripton;
// getters and setters removed for brevity
}
public abstract class BaseEntity<T> implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence_db")
private T id;
}
然后 GenericRepository
我使用 EntityManager
得到 Session
class 如下所示:
@Repository
public abstract class GenericRepository<T extends BaseEntity,PK extends Serializable> {
protected Class<T> domainClass = getDomainClass();
/* changed */
@PersistenceContext
private EntityManager em;
public Session getSession() {
/* changed */
return em.unwrap(Session.class);
}
public PK save(T Entity) {
Session session = getSession();
if(entity.getId() == null) {
session.save(entity);
}
else {
entity = (T)session.merge(entity);
session.update(entity);
}
return entity.getId();
}
public T loadByEntityId(PK entityId) {
Session session = getSession();
return (T) session.get(domainClass.getName(), entityId);
}
}
现在,问题是,当我 运行 以前的方法调用时,在 saveAndGetDetailsCount
中,hibernate 不执行 select...
查询并记录 0 因为评论很重要。
我想知道为什么会这样。
更新
也许你会问为什么我没有使用 EntityManager
而不是 Session
,我使用 EntityManager
.
更新
当我调用 saveAndGetDetailsCount
时,entity
参数仅包含 id
和 title
,在接下来的几行中,您可以看到我想加载 comments
字段并获取它的大小。
如果实体已经附加到当前会话,为什么要生成查询?
还有,为什么要调用merge和update呢?您应该使用其中之一。但不是两者。
您的问题不在于迁移到休眠 5。我认为您的问题在于 transaction.When 在同一事务中坚持或合并调用,loadById 直到方法 return 才执行。您可以在之后刷新保存合并工作正常和你的对象加载。
将您的代码更改为此
@Repository
public abstract class GenericRepository<T extends BaseEntity,PK extends Serializable> {
protected Class<T> domainClass = getDomainClass();
/* changed */
@PersistenceContext
private EntityManager em;
public Session getSession() {
/* changed */
return em.unwrap(Session.class);
}
public PK save(T Entity) {
Session session = getSession();
if(entity.getId() == null) {
em.persist(entity);
}
else {
em.merge(entity);
em.flush();
}
return entity.getId();
}
public T loadByEntityId(PK entityId) {
Session session = getSession();
return (T) session.get(domainClass.getName(), entityId);
}
}