【发布时间】:2021-07-03 10:34:46
【问题描述】:
我正在学习hibernate和Spring Boot(也是Thymeleaf),遇到了如下问题:
情况:我有一个表单,它根据 GET 方法中的 ID 参数处理创建和更新数据,如果 ID 等于数据库中的一行,则更新,否则保存。 ID 存储在隐藏的输入标签中,并与表单数据一起插入到实体对象中。然后将该对象发送到调用 DAO 以使用 saveOrUpdate() 方法保存或更新数据的服务。
问题总结:在我的服务中,我有一个用 @Transactional 注释的方法,它调用我的 DAO,然后打开一个会话并执行 saveOrUpdate()。问题是这段代码正确地将新数据保存到我的数据库中,但它不会更新现有数据,在日志中 saveOrUpdate() 只选择但不插入。
我尝试了什么:我发现如果我在 DAO 中打开一个新事务,然后提交该事务,一切都会正常工作,但是当我不这样做并且只依赖 @Transactional 注释时上面的服务方法我只能保存新数据但没有更新。
我的带有 Thymeleaf 的 HTML 表单
<form action="#" th:action="@{saveCustomer}" th:object="${newCustomer}" method="post">
<input type="hidden" th:field="*{id}" />
<table>
<tr>
<td><label>First Name:</label></td>
<td><input type="text" th:field="*{firstName}"/></td>
</tr>
<tr>
<td><label>Last Name:</label></td>
<td><input type="text" th:field="*{lastName}"/></td>
</tr>
<tr>
<td><label>Email:</label></td>
<td><input type="text" th:field="*{email}"/></td>
</tr>
<tr>
<td><label></label></td>
<td><input type="submit" value="Submit" class="save"/></td>
</tr>
<tr>
<td><label></label></td>
<td><input type="reset" value="Reset" class="save"/></td>
</tr>
</table>
</form>
控制器方法
@PostMapping("/saveCustomer")
public String saveCustomer(@ModelAttribute("newCustomer") Customer newCustomer) {
customerService.saveCustomer(newCustomer);
return "redirect:/list";
}
服务方式
import javax.transaction.Transactional;
@Override
@Transactional
public void saveCustomer(Customer newCustomer) {
customerDAO.saveCustomer(newCustomer);
}
DAO 方法
@Autowired
private EntityManagerFactory entityManagerFactory;
@Override
public void saveCustomer(Customer newCustomer) {
try (Session session = entityManagerFactory.unwrap(SessionFactory.class).openSession()) {
// If I use transaction like this everything works correctly!
// Transaction transaction = session.beginTransaction();
session.saveOrUpdate(newCustomer);
// transaction.commit();
} catch (Exception e) {
e.printStackTrace();
}
}
我的客户实体类
import javax.persistence.*;
@Entity
@Table(name = "customer")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "email")
private String email;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
'}';
}
}
发生这种情况时休眠日志
Hibernate: select customer0_.id as id1_0_, customer0_.email as email2_0_, customer0_.first_name as first_na3_0_, customer0_.last_name as last_nam4_0_ from customer customer0_ order by customer0_.last_name
Hibernate: select customer0_.id as id1_0_0_, customer0_.email as email2_0_0_, customer0_.first_name as first_na3_0_0_, customer0_.last_name as last_nam4_0_0_ from customer customer0_ where customer0_.id=?
Hibernate: select customer0_.id as id1_0_, customer0_.email as email2_0_, customer0_.first_name as first_na3_0_, customer0_.last_name as last_nam4_0_ from customer customer0_ order by customer0_.last_name
我省略了大部分导入以整理代码,因为我只包含了与问题相关的部分对象。
【问题讨论】: