You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring OneToMany CRUD项目添加课程遇User空指针及Session异常求助

Spring MVC OneToMany关联添加课程时User为空的问题排查

问题背景

我是Spring新手,正在搭建一个OneToMany关联的CRUD项目,数据库包含user和course表,course表的user_id外键关联user表的id字段。用户登录成功后进入homePage.jsp,页面展示该用户的课程列表;点击“Add Course”按钮跳转至course-form.jsp进行课程添加操作。目前遇到的问题是:添加课程时Spring MVC处理过程中丢失user模型属性,提交addedCourse表单时出现错误。

错误信息

Cannot invoke "com.veg.entity.User.addCourse(com.veg.entity.Course)" because "user" is null

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread

代码实现

Controller代码

@PostMapping("/showFormForAdd")
public String showFormForAdd(@ModelAttribute("user") User theUser, Model theModel) {
    
    Course theCourse = new Course();
    
    theCourse.setUser(theUser);
    
    theModel.addAttribute("course", theCourse);
    
    theModel.addAttribute("user", theUser);
    
    return "course-form";
}   

@PostMapping("addedCourse")
public String addedCourse(@ModelAttribute("course") Course theCourse, Model theModel) {
    
    User user = theCourse.getUser();
    
    userService.save(user, theCourse);
    
    theModel.addAttribute("user", user);
    
    return "homePage";
}

homePage.jsp代码

<p>Welcome ${user.username}</p>

<span>
    <form:form action="showFormForAdd" modelAttribute="user" method="POST">
        <form:hidden path="username"/>
        <form:hidden path="password"/>
        <input type="submit" value="Add Course" class="add-course"/>
    </form:form>
</span>

<table>
    <tbody>
        <tr>
            <th>Course id</th>
            <th>Course title</th>
        </tr>
        <c:forEach var="temp" items="${user.courses}">
            <tr>
                <td> ${temp.id} </td>
                <td> ${temp.title} </td>
            </tr>           
        </c:forEach>
    </tbody>
</table>

course-form.jsp代码

<p>Welcome ${user.username}</p>

<span>
    <form:form action="loggedUser" modelAttribute="user" method="POST">
        <form:hidden path="username"/>
        <form:hidden path="password"/>
        <input type="submit" value="Back to Course List" class="add-course"/>
    </form:form>
</span>

<!-- In the below I lost my user modelAttribute because I should use course attribute -->
<form:form action="addedCourse" modelAttribute="course" method="POST">
    <table>
        <tbody>
            <tr>
                <td> Title </td>
                <td> <form:input path="title"/> </td>
            </tr>
            <tr>
                <td colspan="2"> 
                <input type="submit" value="Add Course" class="add-course"/> 
                </td>
            </tr>
        </tbody>
    </table>
</form:form>    

已完成的排查动作

  • Service层已添加@Transactional注解
  • DAO层添加了@Repository注解
  • SessionFactory配置无异常

问题修复方案

核心问题分析

  1. User对象丢失:course-form.jsp中提交course的表单未携带User的标识信息,Spring无法自动将User绑定到Course对象中,导致theCourse.getUser()返回null。
  2. 事务Session问题:即使传递了User信息,表单提交的User是脱离Hibernate Session的游离对象,直接操作可能引发Session管理异常。

具体修复步骤

1. 在course表单中添加User的隐藏字段

在course-form.jsp的course提交表单中,加入User的唯一标识字段(优先用id,避免用户名/密码重复问题),确保提交时Spring能将User信息绑定到Course的user属性:

<form:form action="addedCourse" modelAttribute="course" method="POST">
    <!-- 添加User的id隐藏字段,用于绑定Course关联的User -->
    <form:hidden path="user.id"/>
    
    <table>
        <tbody>
            <tr>
                <td> Title </td>
                <td> <form:input path="title"/> </td>
            </tr>
            <tr>
                <td colspan="2"> 
                <input type="submit" value="Add Course" class="add-course"/> 
                </td>
            </tr>
        </tbody>
    </table>
</form:form>    

2. 修改Controller的addedCourse方法,重新加载托管状态的User

表单传递的User是游离态对象,需要从数据库重新查询获取Hibernate托管的User实例,避免Session异常:

@PostMapping("addedCourse")
public String addedCourse(@ModelAttribute("course") Course theCourse, Model theModel) {
    
    // 通过User的id从数据库重新加载,确保是Hibernate托管状态
    User user = userService.findById(theCourse.getUser().getId());
    
    // 关联课程并保存
    user.addCourse(theCourse);
    userService.save(user);
    
    theModel.addAttribute("user", user);
    
    return "homePage";
}

3. 配置实体类的级联保存

在User实体类的@OneToMany注解中添加级联配置,确保保存User时自动保存关联的Course:

@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Course> courses;

4. 确认事务注解驱动配置

确保Spring配置中开启了事务注解支持:

  • XML配置:<tx:annotation-driven transaction-manager="transactionManager"/>
  • Spring Boot:在配置类上添加@EnableTransactionManagement注解

内容的提问来源于stack exchange,提问作者ravenharpy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 09:55:14