Hibernate: временно исключить столбец и обновить - PullRequest
2 голосов
/ 12 ноября 2010

Допустим, у меня есть такой стол

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'

Который сопоставлен с классом POJO, используя Hibernate, как это

@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, то это было бы хорошо, пока не придет время, когда пользователь войдет в систему между операциями загрузки и обновления. Это приведет к обновлению DATE_LAST_LOGIN в БД, но затем, когда пользовательская форма редактирования сохранит изменения, она переопределит DATE_LAST_LOGIN со старым, неправильным значением.

EDIT:

Не думаю, что я объяснил ситуацию полностью, так что здесь есть дополнительная информация .... Это конкретно в веб-приложении, обновление пользователя происходит так.

  1. Пользовательская запись загружена и используется для заполнения HTML-формы
  2. Форма редактируется и отправляется обратно на сервер
  3. Сервер фиксирует изменения в базе данных

Поскольку я не запрашиваю объект из базы данных еще раз перед обновлением при отправке формы, я просто заполняю новый объект полями из формы и сохраняю его в базе данных, это, конечно, означает, что dateLastLogin равен нулю во время сохранения обновления и так заменил бы правильное значение на нуль в БД. Это, очевидно, не может быть решено простой синхронизацией потоков. До перехода в режим гибернации я бы просто решил не обновлять поле DATE_LAST_LOGIN, но режим гибернации не позволяет мне принимать такое решение во время разработки.

Альтернативой может быть запрос объекта перед перезаписью полями из формы, однако это вынуждает меня выполнить запрос перед обновлением, которое мне не придется делать без спящего режима, и это заставит меня использовать синхронизация, которая была предложена в одном ответе. Проблема в том, что синхронизация будет применяться только в текущем приложении, если бы у меня было несколько приложений, обновляющих одну и ту же БД, это было бы бесполезно.

Возвращаясь к моему первоначальному вопросу, есть ли способ исключить поле из обновления, если не просто попросить hibernate сделать это, то, возможно, с помощью другой конструкции системы.

Ответы [ 4 ]

1 голос
/ 15 ноября 2010

Я бы предложил использовать для пользователя 2 разных объекта, например, User и UserLogin (где последний будет расширять обычное User и содержать свойство dateLastLogin) и использовать UserLogin во времяАутентификация и короткий User при редактировании пользовательских данных.

1 голос
/ 12 ноября 2010

Это проблема синхронизации больше, чем проблема Hibernate. Вы должны сделать ваши две операции (логин и издание пользователя) атомарными по отношению друг к другу. Это может быть достигнуто с помощью простой синхронизации Java (общий мьютекс или блокировка перед вводом этих операций в методы Java) или с помощью управления транзакциями базы данных (т.е. Hibernate).

0 голосов
/ 12 ноября 2010

Хорошо, поэтому я придумал свое собственное решение, которое работает для меня, хотя я не знаю, есть ли лучшее решение в настоящее время.

В основном в моем POJO я сделал поле getDateLastLogin только для чтениядобавив в аннотацию updatable = false, например, так:

   @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();
   }
}
0 голосов
/ 12 ноября 2010

Можно ли управлять этим с помощью значения переключателя (логического), которое можно переключать по мере необходимости, а затем добавить эту проверку в установщик?

Например:

boolean dateLastLoginUpdatable = false;

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

public void toggleLastLoginEditable( boolean newValue ) {
   dateLastLoginUpdatable = newValue;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...