Hibernate 在更新父实体的同时更新子实体

标签 hibernate jakarta-ee annotations hibernate-mapping

我有两个实体作为用户和项目,它们之间具有如下@ManyToMany 关系。

实体类

import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column (name = "id")
    private int id;
    @Column (name = "email")
    private String email;
    @Column (name = "password")
        private String password;
    @Column (name = "last_login")
    private Date lastLogInDate; 
    @ManyToMany(fetch = FetchType.EAGER)
        @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
        @JoinTable(name = "project_assigned", joinColumns = { @JoinColumn(name = "fk_user_id")  }, inverseJoinColumns = { @JoinColumn(name = "fk_project_id") } )
    private Set<Projects> projects = new HashSet<Projects>(0);  

    // setter and getter methods.
}

@Entity
@Table(name = "projects")
public class Projects {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;
    @Column (name = "name")
    private String name;    
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "user_projects", joinColumns = { @JoinColumn(name = "fk_project_id") }, inverseJoinColumns = { @JoinColumn(name = "fk_user_id") })
    private Set<User> userSet = new HashSet<User>(0);   

}

DAO 类

@Repository
public class UserDAO {

    public User findByCredentials(String email, String password) {
        String queryString = " from User u where u.email = ? and u.password = ?";
        Query query = sessionFactory.getCurrentSession().createQuery(queryString);
        query.setString(0, email);
        query.setString(1, password);       
        return (User) query.uniqueResult();     
    }

    public boolean updateUser(User user) {
        boolean result = true;
        Session session = null;
        try {
            session = sessionFactory.getCurrentSession();
            session.update(user);
        } catch (HibernateException e) {
            result = false;
            logger.error("Can not Update User"+e);
            e.printStackTrace();
        } 
        return result;
    }           
}

服务等级

@Service
@Transactional(readOnly = true,propagation=Propagation.SUPPORTS)
public class UserService {

    @Autowired
    private UserDAO userDAO;

    public User findByCredentials(String userName, String lastName) {
        return userDAO.findByCredentials(userName, lastName);   
    }

    @Transactional(readOnly = false,propagation=Propagation.REQUIRED)
    public boolean updateUser(User user) {
        return userDAO.updateUser(user);
    }
}

其他代码

User user = userService.findByCredentials("xyz@pqr.com", "abc");
user.setLastLogInDate(new Date());
userService.updateUser(user);

我的问题是,当我更新用户的“LastLogInDate”时 然后分配给该用户的所有项目实体都得到更新(不必要的火灾更新声明) 因此,我的应用程序性能很低。我怎么解决这个问题。我怎样才能更好地做到这一点。感谢您的帮助。

这是我的 SQL 日志

DEBUG org.hibernate.SQL#log  - update users set email=?, password=?, last_login=? where id=?
DEBUG org.hibernate.SQL#log  - update user_projects set name=? where id=?
DEBUG org.hibernate.SQL#log  - update user_projects set name=? where id=?
DEBUG org.hibernate.SQL#log  - update user_projects set name=? where id=?
DEBUG org.hibernate.SQL#log  - update user_projects set name=? where id=?
DEBUG org.hibernate.SQL#log  - update user_projects set name=? where id=?

最佳答案

你必须设置级联,因为级联不能在运行时设置(保存):

@Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})

您至少必须删除 CascadeType.MERGE。因为 MERGE 意味着一些复杂的东西,它近似于“保存”,但更像是“将这个分离的实体推回托管状态并保存其状态更改”。级联意味着所有关联的实体都以相同的方式被推回,并且您从 .merge() 返回的托管实体句柄具有与之关联的所有托管实体。

关于Hibernate 在更新父实体的同时更新子实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17835533/

相关文章:

gwt - Intellij IDEA 和 mvp4g APT 注解检查

java - JPA/Hibernate - 将枚举保留为常量表

hibernate - Tomcat/Hibernate 问题 "SEVERE: Error listenerStart"

java - 使用 Hibernate 将原始 boolean 值映射到字符 Y/N

javax.net.ssl.SSLHandshakeException : Received fatal alert: handshake_failure

java - org.apache.xerces.impl.dv.DVFactoryException : DTD factory class org. apache.xerces.impl.dv.dtd.DTDDVFactoryImpl 不从 DTDDVFactory 扩展

java - hibernate:如果父层是新的,则不会将更新级联到子层

hibernate - 如何以编程方式检索持久性单元使用的数据源

java - 在编译时为方法添加注解

java - @Tag注解的作用是什么