问:事务代码为何如此有效?

Q: Transactional Code why does this work so well?

你好,我的专业人士,我有一个简单的问题,我想请求解决这个问题..

这是会员实体

@Entity
@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
/*@ToString(of = {"id", "username", "age"})*/
public class Member {

    @Id
    /*@GeneratedValue(strategy = GenerationType.IDENTITY)*/
    @Column(name = "member_id")
    private Long id;

    private String username;

    private int age;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "member")
    private List<Team> teams;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL,  mappedBy = "member")
    private List<Coach> coachs;

}

这是 Coach 的一个实体

@Entity
@AllArgsConstructor
@Getter
@Builder
@Setter
@NoArgsConstructor
@ToString(of = {"id","name","career"})
public class Coach {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name= "coach_id")
    private Long id;

    @Column
    private String name;

    @Column
    private String career;

    @ManyToOne(fetch = FetchType.LAZY,cascade = ALL)
    @JoinColumn(name = "member_id")
    private Member member;

    @OneToOne(fetch = FetchType.LAZY,cascade = ALL)
    @JoinColumn(name = "team_id")
    private Team team;

}

这是控制器代码

    @GetMapping("/member")
public void createUser(){
     Member m = memberService.createMember();
     Coach c = m.getCoachs().get(0);
     log.info(c.getName());
}

这是服务代码

private final MemberRepository memberRepository;

    @Transactional
    public Member createMember(){
        return memberRepository.findMemberById(3L);
    }

最后一个是 RepositoryCode

Member findMemberById(Long id);

所以我的问题是,当我在控制台的控制器上打印出 Coach 的名字时

打印的真好。

但据我所知,事务已从服务结束,因此持久性容器已关闭,这意味着无法导入教练名称,因为它处于延迟加载状态,持久性容器已关闭,但打印效果很好

我想知道为什么...

这是控制台结果谢谢!!

[2022-01-10 23:27:46.835] [http-nio-9000-exec-2] [] INFO  o.a.c.c.C.[.[.[/] - Initializing Spring DispatcherServlet 'dispatcherServlet' 
[2022-01-10 23:27:46.835] [http-nio-9000-exec-2] [] INFO  o.s.w.s.DispatcherServlet - Initializing Servlet 'dispatcherServlet' 
[2022-01-10 23:27:46.855] [http-nio-9000-exec-2] [] INFO  o.s.w.s.DispatcherServlet - Completed initialization in 19 ms 
Hibernate: 
    /* select
        generatedAlias0 
    from
        Member as generatedAlias0 
    where
        generatedAlias0.id=:param0 */ select
            member0_.member_id as member_i1_1_,
            member0_.age as age2_1_,
            member0_.username as username3_1_ 
        from
            member member0_ 
        where
            member0_.member_id=?
[2022-01-10 23:27:47.007] [http-nio-9000-exec-2] [4c0222d3] INFO  p6spy - #1641824867007 | took 15ms | statement | connection 1| url jdbc:mariadb://patrick-lab.cjeq2ffynlc2.ap-northeast-2.rds.amazonaws.com:3306/patricklab?characterEncoding=UTF-8&serverTimezone=UTC
/* select generatedAlias0 from Member as generatedAlias0 where generatedAlias0.id=:param0 */ select member0_.member_id as member_i1_1_, member0_.age as age2_1_, member0_.username as username3_1_ from member member0_ where member0_.member_id=?
/* select generatedAlias0 from Member as generatedAlias0 where generatedAlias0.id=:param0 */ select member0_.member_id as member_i1_1_, member0_.age as age2_1_, member0_.username as username3_1_ from member member0_ where member0_.member_id=3; 
[2022-01-10 23:27:47.170] [http-nio-9000-exec-2] [4c0222d3] INFO  p6spy - #1641824867170 | took 12ms | commit | connection 1| url jdbc:mariadb://patrick-lab.cjeq2ffynlc2.ap-northeast-2.rds.amazonaws.com:3306/patricklab?characterEncoding=UTF-8&serverTimezone=UTC

; 
Hibernate: 
    select
        coachs0_.member_id as member_i4_0_0_,
        coachs0_.coach_id as coach_id1_0_0_,
        coachs0_.coach_id as coach_id1_0_1_,
        coachs0_.career as career2_0_1_,
        coachs0_.member_id as member_i4_0_1_,
        coachs0_.name as name3_0_1_,
        coachs0_.team_id as team_id5_0_1_ 
    from
        coach coachs0_ 
    where
        coachs0_.member_id=?
[2022-01-10 23:27:47.200] [http-nio-9000-exec-2] [4c0222d3] INFO  p6spy - #1641824867200 | took 12ms | statement | connection 1| url jdbc:mariadb://patrick-lab.cjeq2ffynlc2.ap-northeast-2.rds.amazonaws.com:3306/patricklab?characterEncoding=UTF-8&serverTimezone=UTC
select coachs0_.member_id as member_i4_0_0_, coachs0_.coach_id as coach_id1_0_0_, coachs0_.coach_id as coach_id1_0_1_, coachs0_.career as career2_0_1_, coachs0_.member_id as member_i4_0_1_, coachs0_.name as name3_0_1_, coachs0_.team_id as team_id5_0_1_ from coach coachs0_ where coachs0_.member_id=?
select coachs0_.member_id as member_i4_0_0_, coachs0_.coach_id as coach_id1_0_0_, coachs0_.coach_id as coach_id1_0_1_, coachs0_.career as career2_0_1_, coachs0_.member_id as member_i4_0_1_, coachs0_.name as name3_0_1_, coachs0_.team_id as team_id5_0_1_ from coach coachs0_ where coachs0_.member_id=3; 
[2022-01-10 23:27:47.213] [http-nio-9000-exec-2] [4c0222d3] INFO  m.p.l.m.c.MemberController - Coach1 

我相信这是因为您正在使用 spring-boot 默认设置,其中 spring.jpa.open-in-view 设置为 true。

此 属性 启用 模式,您可以简单地认为在处理任何 HTTP 请求时(例如在 Servlet 过滤器等中),事务将在一开始就自动为您打开.因此,在您的服务方法执行之前事务实际上已经打开,并且在您的服务方法完成后它仍然处于活动状态。因此,即使您在服务方法之外访问未初始化的属性,您也不会遇到任何 LazyInitializationException,因为事务仍然处于活动状态。

关于 spring-boot 是否应该在过去默认启用它存在激烈的争论。如果您有兴趣,可以参考 this 了解更多详情。我个人建议将其关闭。