Hibernate:暂时从列中排除并更新

时间:2010-11-12 08:52:46

标签: java hibernate

假设我有一张这样的表

USER_ID     USERNAME     PASSWORD     DATE_CREATED    DATE_LAST_LOGIN
1           'user1'      'password1'  '12-Jun-2010'   '12-Nov-2010'
2           'user2'      'password2'  '14-Jun-2010'   '12-Nov-2010'

使用hibernate映射到POJO类

@Entity
@Table( name="user" )
public class User {

   private Integer id;
   private String username;
   private String password;
   private Date dateCreated;
   private Date dateLastLogin;

   public User() {
   }

   @Id
   @GeneratedValue( strategy = GenerationType.IDENTITY )
   public IntegergetId() {
      return id;
   }

   public void setId(Integer id) {
      this.id = id;
   }

   @Colum( name="USERNAME" )
   public String getUsername() {
      return username;
   }

   public void setUsername(String username) {
      this.username = username;
   }

   @Colum( name="PASSWORD" )
   public String getPassword() {
      return password;
   }

   public void setPassword(String password) {
      this.password= password;
   }

   @Colum( name="DATE_CREATED" )
   public Date getDateCreated() {
      return dateCreated;
   }

   public void setDateCreated(Date dateCreated) {
      this.dateCreated= dateCreated;
   }

   @Colum( name="DATE_LAST_LOGIN" )
   public Date getDateLastLogin() {
      return dateLastLogin;
   }

   public void setDateLastLogin(Date dateLastLogin) {
      this.dateLastLogin = dateLastLogin;
   }

}

本课程将以两种方式使用, 1.验证用户是否登录,当用户登录时,将使用当前日期更新DATE_LAST_LOGIN。 2.在用户编辑表单中更新用户详细信息。

我的问题是我只想在用户登录时更新DATE_LAST_LOGIN字段,而不是在表单中编辑用户时。如果我要加载一个用户记录,然后在不调用setDateLastLogin的情况下保存它,那么在用户登录加载和更新操作之前,这将是正常的。这将导致在db中更新DATE_LAST_LOGIN,但是当用户编辑表单保存更改时,它将使用旧的不正确的值覆盖DATE_LAST_LOGIN。

编辑:

我认为我没有完全解释这种情况,所以这里有更多信息....这是特别在webapp中,用户的更新就是这样。

  1. 用户记录已加载并用于填充html表单
  2. 表格已编辑并提交回服务器
  3. 服务器将更改提交到数据库
  4. 我认为在更新表单提交之前不再从数据库中查询对象,我只是使用表单中的字段填充新对象并将其保存到数据库,这当然意味着dateLastLogin为null在保存更新时,因此将在DB中用null替换正确的值。这显然无法通过简单地同步线程来解决。在休眠之前,我只是选择不更新DATE_LAST_LOGIN字段,但是hibernate不允许我做出设计时间决定。

    另一种方法是在用表单中的字段覆盖之前查询对象,但是这迫使我必须在更新之前运行查询,如果没有hibernate,我不必这样做,这会迫使我使用在一个答案中建议的同步。问题是同步只适用于当前的应用程序,如果我有多个应用程序更新同一个数据库,那么它就没用了。

    回到我原来的问题,有没有办法从更新中排除字段,如果不是简单地要求hibernate这样做,那么可能是由不同的系统设计。

4 个答案:

答案 0 :(得分:1)

这是一个比Hibernate更多的同步问题。您应该使两个操作(用户的登录和版本)相互原子化。这可以通过简单的Java同步(在进入这些操作Java方法之前使用常见的互斥锁或锁)或通过数据库(即Hibernate)事务管理来实现。

答案 1 :(得分:1)

我的建议是为用户使用2个不同的实体,例如: UserUserLogin(后者会扩展常规User并保留dateLastLogin属性)并在身份验证期间使用UserLogin并使用User编辑用户详细信息时。

答案 2 :(得分:0)

您可以使用切换(布尔值)控制此值,您可以根据需要切换,然后将此检查添加到设置器中吗?

例如:

boolean dateLastLoginUpdatable = false;

public void setDateLastLogin(Date dateLastLogin) {
   if( dateLastLoginUpdatable ) {
      this.dateLastLogin = dateLastLogin;
   }
}

public void toggleLastLoginEditable( boolean newValue ) {
   dateLastLoginUpdatable = newValue;
}

答案 3 :(得分:0)

好的,所以我提出了自己的解决方案,虽然我不知道目前是否有更好的解决方案,但仍然适用于我。

基本上在我的POJO中,我通过向注释中添加updatable = false来读取getDateLastLogin字段,如此

   @Colum( name="DATE_LAST_LOGIN", updatable = false )
   public Date getDateLastLogin() {
      return dateLastLogin;
   }

然后在登录时我绕过POJO并直接使用我的登录控制器中的HQL更新更新数据库

public void login(String username, String password) {
   User user = getUser( username, password );
   if( user != null ) {
      Query userUpdate = getSession().createQuery( "update User set dateLastLogin = current_timestamp where id = :userId" );
      userUpdate.setInteger( "userId", user.getId() );
      userUpdate.executeUpdate();
   }
}