对JPA实体管理器和lazyload感到困惑

lia*_* xu 2 java spring hibernate jpa

我基于springboot创建了一个用户管理服务。

用户将有一个列表附件,这样用户和依恋的关系是一对多

我在这里忽略了插入逻辑,因为我的问题是关于延迟加载以及何时打开和关闭entitymanager。以下是实体,控制器,服务,Dao,存储库相关的代码。

实体

@Entity
@Table(name="User")
public class UserInfoEntity {

 private long id;
 private String mail;

 @OneToMany(fetch = FetchType.LAZY, mappedBy = "userInfoEntity", cascade = CascadeType.ALL)
 private List<UserAttachmentEntity> attachmentList = new ArrayList<>();

}


@Entity
@Table(name = "ATTACHMENT")
public class UserAttachmentEntity {
    private long id;

    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="userRequestId")
    private UserInfoEntity userInfoEntity;

}
Run Code Online (Sandbox Code Playgroud)

服务

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;


    @Override
    @Transactional
    public void save(UserInfoEntity userInfoEntity) throws RestException {
        userDao.save(userInfoEntity);
    }



    @Override
    // I did set @Transactional here
    public UserInfoEntity findByMail(String mail) {
        UserInfoEntity userInfoEntity = userDao.findByMail(mail);
        return userInfoEntity;
    }
}
Run Code Online (Sandbox Code Playgroud)

@Service
public class UserDaoImpl implements UserDao {

    @PersistenceContext
    private EntityManager entityManager;

    @Autowired
    private UserInfoEntityRepository userInfoRepository;

    @Override
    public UserInfoEntity findByMail(String mail) {
        return userInfoRepository.findFirstByMailOrderByIdDesc(mail);
    }
}
Run Code Online (Sandbox Code Playgroud)

资料库

@Repository
public interface UserInfoEntityRepository extends JpaRepository<UserInfoEntity, Integer> {
    UserInfoEntity findFirstByMailOrderByIdDesc(String mail);
}
Run Code Online (Sandbox Code Playgroud)

控制者

@Controller
@RequestMapping(value = "/user")
public class UserController {
    @RequestMapping(value = "load", method = RequestMethod.POST)
    @ResponseBody
    public UserInfoEntity load(UserInfoEntity userInfoEntityInput, HttpServletRequest request) throws Exception {
        UserInfoEntity userInfoEntity = userService.findByMail(userInfoEntityInput.getMail());
        System.out.println(userInfoEntity.getAttachmentList());
        return userInfoEntity;
    }
}
Run Code Online (Sandbox Code Playgroud)

在控制器中测试加载方法后,我发现即使我将

@OneToMany(取= FetchType.LAZY,...)UserInfoEntity

我仍然可以在controller中调用userInfoEntity.getAttachmentList()。(我可以看到在其中打印了来自附件查询的select *

lazyinitializationexception-in-spring-data-jpa后的回答说,您需要在事务内部时获取懒惰数据。

但是我没有在服务中的findByMail方法中设置@Transaction

我记得几天前我也遇到了这个例外。但是现在我可以在控制器中成功加载惰性数据了。

我主要有以下问题。

  1. 实体管理器何时打开和关闭?(它是在服务中打开还是道?)
  2. 为什么可以将延迟数据加载到控制器中?
  3. 实体管理器是线程安全的吗?(我用谷歌搜索,但找不到有用的答案)
  4. 实体经理是单身人士吗?(在上面的代码中,我将实体管理器注入到dao中,尽管我没有使用它,但我使用了spring数据,但是我可以将实体管理器注入到服务,控制器中,发现哈希码是不同的)

提前致谢。我在公司中写了这个问题,不允许在公司中将任何代码推送到github。如果可以的话,我认为这对您会更方便,因为带有h2数据库的spring boot项目在本地很容易设置。

Sha*_*mud 5

Spring Boot JPA默认情况下在View中打开会话

如果您查阅附录A.常见的应用程序属性,默认情况下会发现Spring boot定义

spring.jpa.open-in-view=true
Run Code Online (Sandbox Code Playgroud)

那实际上是登记OpenEntityManagerInViewInterceptor。将JPA绑定EntityManager到线程以完成请求的整个处理。这实际上导致混乱,请参阅社区报告的此问题

何时打开和关闭EntityManager?

基本上,EntityManager打开一个事务,在该事务中@Transaction声明了注释,或者在您的情况下,注释由OpenEntityManagerViewInterceptor每个请求打开,并且在做出响应之前保持打开状态。

实体管理器是线程安全的吗?

没有。它不是线程安全的,但是EntityManagerFactory是。并EntityManager从获得EntityManagerFatory。因此,EntityManager价格便宜,并且可以用于单个工作单元。EntityManagerFactory通常在应用程序初始化时创建An ,然后在应用程序端将其关闭。有关在Java SE环境中获取EntityManager的详细信息,请参见Hibernate文档。

实体经理是单身人士吗?

不会。EntityManager是一个接口,在您自动装配时注入到spring bean中的不是实体管理器本身,而是上下文感知的代理,它将在运行时委派给具体的实体管理器。通常,用于代理的具体类是SharedEntityManagerInvocationHandler

有关整个JPA事务如何进行的更多详细说明。我建议阅读这本Spring @Transactional如何真正起作用?