有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java LazyInitializationException春季启动

我知道有很多类似的线程,但我就是不能从这些线程中找出如何克服这个问题

我有三类车,品牌,颜色。 一辆汽车只有一个品牌和一系列颜色。 布兰德有一份汽车清单。 颜色没有任何关系

为了简单起见,不提供getter、setter、ToString和构造函数。 我能够将对象保存到数据库中,并且数据库已经填充

--------------------------------------------------------------------------------

@Entity
@Table(catalog = "spring_project")
public class Car {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String model;

@ManyToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable( name = "car_color", catalog = "spring_project",
            joinColumns         = { @JoinColumn(name = "car_id") },
            inverseJoinColumns  = { @JoinColumn(name = "colors_id") }
)
private List<Color> colors = new ArrayList<>();

@ManyToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name="brand_id", referencedColumnName="id")
private Brand brand;

--------------------------------------------------------------------------------

@Entity
@Table(catalog = "spring_project")
public class Brand {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

@OneToMany(mappedBy = "brand", fetch = FetchType.LAZY)
private List<Car> cars = new ArrayList<>();

--------------------------------------------------------------------------------

@Entity
@Table(catalog = "spring_project")
public class Color {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;

--------------------------------------------------------------------------------

如果我像Earge一样抓取,一切都正常,但我知道这是一种不好的做法,应该改用惰性加载。但我总是遇到LazyInitializationException

我从错误中了解到需要一个会话,但我不知道如何提供会话,因为我正在使用Spring数据JPA,我也不知道应该在哪里声明会话

@SpringBootApplication
public class SrpingJpaApplication {

private static final Logger log = 
LoggerFactory.getLogger(SrpingJpaApplication.class);

public static void main(String[] args) {
    SpringApplication.run(SrpingJpaApplication.class, args);
}

@Bean
public CommandLineRunner demo(CarRepository carRepository,
                              ColorRepository colorRepository,
                              BrandRepository brandRepository) {
    return (args) -> {

        log.info("Reads all cars....");
        for (Car c : carRepository.findAll()) {
            System.out.println(c.toString());
        }

    };
}

}

非常感谢你

编辑------>&燃气轮机&燃气轮机

在c.toString()上抛出错误

错误:由:org引起。冬眠LazyInitializationException:无法初始化 代理[com.readiness.moita.SrpingJPA.Models.Brand#1]-无会话


共 (2) 个答案

  1. # 1 楼答案

    因为BrandFetchType是惰性的,它不会通过调用fetchAll()自动加载到会话中。要将其自动加载到会话中,您需要:

    改变

    @ManyToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name="brand_id", referencedColumnName="id")
    private Brand brand;
    

    @ManyToOne(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
    

    前任

    @ManyToOne(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name="brand_id", referencedColumnName="id")
    private Brand brand;
    

    如果不想将fetch type设置为eager,那么需要将对toString的调用移动到服务方法Ex

    @Component
    public CarService implements ICarService {
    
        @Autowired
        CarRepository carRepository;
    
        @Transactional
        public void printAllCars() {
            for (Car c : carRepository.findAll()) {
                System.out.println(c.toString());
            }
        }   
    }
    

    然而,正确的方法是编写一个条件查询或hql

  2. # 2 楼答案

    @OneToMany注释的默认值为FetchType.LAZY,因此您的集合将被延迟加载

    为了能够在检索对象后访问该集合,您需要处于事务上下文中(您需要一个打开的会话)

    当你打电话时:

    carRepository.findAll();
    

    在内部创建一个新会话,检索对象,一旦findAll方法返回,会话就关闭

    你应该做的是确保每当你访问汽车对象中的惰性集合时,你有一个打开的会话(这个toString就是这么做的)

    最简单的方法是让另一个服务处理汽车装载,并用@Transactional注释showCars方法。由于处理AOP代理的方式,该方法位于另一个服务中

    @Service
    public CarService {
    
        final CarRepository carRepository;
    
        public CarService(CarRepository carRepository) {
            this.carRepository = carRepository;
        }    
    
        @Transactional
        public void showCars(String... args) {
            for (Car c : carRepository.findAll()) {
                System.out.println(c.toString());
            }
        }   
    }
    

    然后你打电话:

    @Bean
    public CommandLineRunner demo(CarService carService) {
        return (args) -> service.showCars(args);
    }