LazyLoading prevents RestController from returning the correct values

时间:2018-03-23 00:28:02

标签: spring hibernate spring-mvc spring-boot

I think Hibernate's lazy loading may be preventing my Controller from returning the appropriate response.

@RestController
@RequestMapping("/shifts")
public class ShiftController {
    private ShiftService shiftService;

    @Autowired
    public ShiftController(ShiftService shiftService) {
        this.shiftService = shiftService;
    }

    @GetMapping("")
    @PreAuthorize("hasAnyAuthority('ADMIN','SUPERVISOR')")
    Collection<Shift> getShifts() {
        return shiftService.fetchAll();
    }

    @GetMapping("/{id}")
    @PreAuthorize("hasAnyAuthority('ADMIN','SUPERVISOR')")
    ResponseEntity<Shift> getOneShift(@PathVariable("id") Long id) {
        Shift shift = shiftService.fetchOne(id);
        return new ResponseEntity<>(shift, HttpStatus.OK);
    }
}

Shift Class

@Entity
public class Shift {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "SHIFT_ID")
    private Long id;

    @Column(name = "START", nullable = false)
    private OffsetDateTime start;

    @Column(name = "END", nullable = false)
    private OffsetDateTime end;

    @ManyToOne(optional = false, fetch = FetchType.EAGER)
    @JoinColumn(name = "USER_ID", nullable = false)
    private User user;

    @ManyToOne(optional = false, fetch = FetchType.EAGER)
    @JoinColumn(name = "TASK_ID", nullable = false)
    private Task task;
}

When running my test without debugging I get the following response (Body is NULL).

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = {Content-Type=[application/json;charset=UTF-8], X-Content-Type-Options=[nosniff], X-XSS-Protection=[1; mode=block], Cache-Control=[no-cache, no-store, max-age=0, must-revalidate], Pragma=[no-cache], Expires=[0], X-Frame-Options=[DENY]}
     Content type = application/json;charset=UTF-8
             Body = null
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

When I add a breakpoint at the line Shift shift = shiftService.fetchOne(id); in the ShiftController,step-over, then resume, I get the response I want (Body Exists).

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = {Content-Type=[application/json;charset=UTF-8], X-Content-Type-Options=[nosniff], X-XSS-Protection=[1; mode=block], Cache-Control=[no-cache, no-store, max-age=0, must-revalidate], Pragma=[no-cache], Expires=[0], X-Frame-Options=[DENY]}
     Content type = application/json;charset=UTF-8
             Body = {"id":2,"start":"2018-03-22T17:17:57.387-07:00","end":"2018-03-22T17:17:57.389-07:00","user":{"id":1,"username":"testuser","email":null,"role":"STUDENT"},"task":{"id":1,"name":"CLEANUP"}}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

Some Googling leads me to believe that the issues stems from Hibernate's Lazy Loading. Whats the fix for this?

EDIT: Forgot to add that the shiftService.fetchOne() method just wraps the JpaRepository's getOne() method.

1 个答案:

答案 0 :(得分:1)

This seems to be the culprit of your problem.

Forgot to add that the shiftService.fetchOne() method just wraps the JpaRepository's getOne() method.

The getOne method returns only the reference from DB (lazy loading). So basically you are outside of the transaction (the Transactional you have been declared in service class is not considered), and hence the slow response time in lazy loading.

Instead of getOne(), you should use findOne() JPA API in your shiftService.fetchOne() implementation

Look at the API documentation here