行被另一个事务多线程更新或删除

时间:2016-09-30 09:44:08

标签: java multithreading hibernate

我希望在两个线程协同工作时重新计算用户表更新,这会抛出“Row被另一个事务更新或删除(或者unsaved-value映射不正确):[com.dmainc.commons.security.User#4 ]” 。当第二个线程首先命中时开始回滚并抛出异常。 实际上每个线程都在修改passwordAttemptDate。我需要在每次用户登录时更新该字段,如何同时为两个线程执行此操作。我在一个交易中调用这个方法。

任何意见都会得到赞赏。

 public AuthenticationStatus authenticateEncrypted(User user, String password, ISecurityParameters params,
     Boolean encryptedPassword)
  {
  AuthenticationStatus status = new AuthenticationStatus();
  status.setUser(user);
  status.setStatus(AuthenticationStatus.Status.UNKNOWN_ERROR);

     // hash password
     String hashedPass = (encryptedPassword == true ? password : hashPassword(password, user.getSalt()));

     // compare to stored password and check on attempts if failed
     if(hashedPass.equals(user.getPassword()))
     {
        user.setPasswordAttempts(0);
        //THIS IS GETTING UPDATED EACH TIME
        user.setPasswordAttemptDate(Calendar.getInstance());

        if(getPasswordNotify(user, params) >= 0)
        {
           status.setStatus(AuthenticationStatus.Status.SUCCESS_NOTIFY);
        }
        else if(isPasswordExpired(user, params))
        {
           status.setStatus(AuthenticationStatus.Status.PASSWORD_EXPIRED);
        }
        else
        {
           status.setStatus(AuthenticationStatus.Status.SUCCESS);
        }

        status.setArg(arg);
        return status;
     }
     else
     {
        user.setPasswordAttempts((user.getPasswordAttempts() == null) ? 1 : user.getPasswordAttempts() + 1);
        user.setPasswordAttemptDate(Calendar.getInstance());
        status.setStatus(AuthenticationStatus.Status.FAIL);
     }
  }
  catch(Exception pe)
  {
     if(LOG.isErrorEnabled())
        LOG.error(pe, pe);
  }

  return status;

}

User.hbm.xml

<hibernate-mapping>
<class name="com.dmainc.commons.security.User" table="userdata">
    <id name="userId" type="long">
        <column name="UserId" />
        <generator class="native" />
    </id>
    <version name="version" type="int">
        <column name="Version" not-null="true" />
    </version>
    <property name="username" type="string">
        <column name="Username" length="50" not-null="true" />
    </property>
    <property name="firstName" type="string">
        <column name="FirstName" length="50" />
    </property>
    <property name="lastName" type="string">
        <column name="LastName" length="50" />
    </property>
    <property name="email" type="string">
        <column name="Email" length="50" />
    </property>
    <property name="status" type="string">
        <column name="Status" length="2" />
    </property>

    <property name="passwordAttempts" type="int">
        <column name="PasswordAttempts" />
    </property>
    <property name="passwordAttemptDate" type="calendar">
        <column name="PasswordAttemptDate" length="19" />

    <many-to-one name="organization" class="com.dmainc.commons.security.Organization" fetch="select">
        <column name="OrganizationId" />
    </many-to-one>
    <set name="userpasswords" table="userpasswords" inverse="true" lazy="true" fetch="select" cascade="all,delete-orphan">
        <key>
            <column name="UserId" not-null="true" />
        </key>
        <one-to-many class="com.dmainc.commons.security.UserPassword" />
    </set>
    <bag name="userroles" table="userrole" inverse="true" lazy="false" fetch="select"  cascade="all,delete-orphan">
        <key>
            <column name="UserId" not-null="true" />
        </key>
        <one-to-many class="com.dmainc.commons.security.UserRole" />
    </bag>
</class>

1 个答案:

答案 0 :(得分:0)

您可以尝试将代码封闭在事务块中吗?

类似的东西:

Session session = null;  
Transaction tx = null;  

try {  
session = sessionFactory.openSession();  
tx = session.beginTransaction();  
//YOUR CODE HERE 

tx.commit();  

}catch (Exception ex) {  
ex.printStackTrace();  
tx.rollback();  
}  
finally {session.close();}