使用并发请求线程保存数据时面临问题。详情如下:
- 春天 3.0.5
- 雄猫 1.6
- 休眠 3
通过示例应用程序模拟问题:
数据库详细信息:
- 用户
- 用户信息
一个用户可以包含多个用户信息,这意味着这些表之间将存在oneToMany关系。
领域类
用户类
@Entity
@Table(name = "user")
public class User implements java.io.Serializable {
private static final long serialVersionUID = 5753658991436258019L;
private Integer idUser;
private String Name;
private Set<UserInfo> userInfos = new HashSet<UserInfo>(0);
public User() {
}
@Id
@Column(name = "iduser", unique = true, nullable = false)
public Integer getIdUser() {
return idUser;
}
public void setIdUser(Integer idUser) {
this.idUser = idUser;
}
@Column(name = "name", nullable = false, length = 256)
public String getName() {
return this.Name;
}
public void setName(String tenantName) {
this.Name = tenantName;
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
public Set<UserInfo> getUserInfos() {
return userInfos;
}
public void setUserInfos(Set<UserInfo> userInfos) {
this.userInfos = userInfos;
}
}
用户信息类
@Entity
@Table(name = "userInfo")
public class UserInfo implements java.io.Serializable {
private static final long serialVersionUID = 5753658991436258019L;
private Integer iduserInfo;
private User user;
private String address;
public UserInfo() {
}
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "iduserInfo", unique = true, nullable = false)
public Integer getIduserInfo() {
return iduserInfo;
}
public void setIduserInfo(Integer iduserInfo) {
this.iduserInfo = iduserInfo;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userId", nullable = false)
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Column(name = "address", nullable = false, length = 256)
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
所以我试图通过休眠将UserInfo保存在db中但在保存UserInfo之前创建用户并尝试从DB中获取它,如果找到则在UserInfo对象中设置否则保存它(用户)然后再次从DB中获取(用于持久状态用户对象)。然后在 UserInfo 中设置并将 UserInfo 对象保存在 DB 中。
注意:这一切都适用于顺序请求
但是在多个 UserInfo 需要相同用户对象时的并发请求,即使保存后也无法加载用户对象。
ServiceLayer 方法saveUserAndInfo如下:
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
@Override
public void saveUserAndInfo(String tenantName) throws Exception {
User user = new User();
user.setName("Name - " + tenantName + " - "
+ System.currentTimeMillis());
UserInfo userInfo = new UserInfo();
userInfo.setAddress("India - " + tenantName + " - "
+ System.currentTimeMillis());
Set<UserInfo> setUserInfos = new HashSet<UserInfo>();
setUserInfos.add(userInfo);
user.setIdUser(1);
user = findByCriteria(user);
userInfo.setUser(user);
saveUserInfo(userInfo);
}
/**
* This method will return <code>User</code> object in persistent state,
*
* If exist fetch from DB, it NOT then insert and again fetch from db
* @param user
* @return
* @throws Exception
*/
public User findByCriteria(User user) throws Exception {
List<Criterion> criterionList = new ArrayList<Criterion>();
criterionList.add(Restrictions.eq("idUser", user.getIdUser()));
Criteria crit = openSession().createCriteria(User.class);
for (Criterion c : criterionList) {
crit.add(c);
}
List<User> entityList = null;
try {
entityList = crit.list();
} catch (Exception ex) {
ex.printStackTrace();
}
if (entityList == null || entityList.isEmpty()) {
log.error("No User Found - " + user.getIdUser() + " now adding...");
saveUser(user);
try {
crit = openSession().createCriteria(User.class);
entityList = crit.list();
} catch (Exception ex) {
ex.printStackTrace();
}
if (entityList != null && !entityList.isEmpty())
return entityList.get(0);
else {
log.error("No User Found - " + user.getIdUser() + " Even after adding");
throw new Exception("No User Found - " + user.getIdUser() + " Even after adding");
}
}
else {
return entityList.get(0);
}
}
请帮忙 !!!