英文:
Hibirnate: failed to lazily initialize a collection of role with @Transactional
问题
我遇到了这样一个问题:当我惰性加载集合时,它会抛出异常。我使用了 Transactional 注解,以及 Hibernate.initialize,但在加载集合时仍然出错。只有使用 EAGER 可以解决,但这会导致开销过大。
实体类:
public class Release extends AbstractEntity {
    ...
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(
            name = "releases_artists",
            joinColumns = @JoinColumn(name = "release_id"),
            inverseJoinColumns = @JoinColumn(name = "artist_id")
    )
    private Set<Artist> artists = new HashSet<>();
    ...
}
异常抛出的类:
@Transactional
public class ReleaseXmlReader extends XmlReaderArrays<Release> {
    ...
    @Override
    protected void handle(Release release) {
        Release releaseFromDb = releaseRepository
                .findFirstByFonalId(release.getFonalId()).orElse(null);
        if (releaseFromDb != null) {
            for (Artist artist : release.getArtists()) {
                if (releaseFromDb.getArtists() <--- 在这里
                        .stream()
                        .noneMatch(artist1 -> artist1.getDiscogsArtistId() != null)
                ) {
        ....
        releaseRepository.save(releaseFromDb);
    }
}
抽象父类:
@Transactional
public abstract class XmlReaderArrays<T extends AbstractEntity> {
    ....
    public void parse() {
        try {
            XMLStreamReader reader = XMLInputFactory
                    .newInstance()
                    .createXMLStreamReader(inputStream);
            XmlMapper mapper = new XmlMapper();
            while (next(reader)) {
                limit--;
                try {
                    T obj = mapper.readValue(reader, type);
                    handle(obj); <--- 在这里
                } catch (Exception e) {
                    log.error("Error parse xml", e);
                }
            }
        } catch (Exception e) {
            log.error("Error parse xml", e);
        }
    }
    ...
}
我尝试过只在父类或者只在子类中使用注解。我还尝试将注解放在方法上,但没有帮助。
英文:
I have such a problem: when I load the collection lazily, it throws an exception. I used the Transactional annotation, Hibernate.initialize, but it still gives an error when loading the collection. Only EAGER helps, but it will be too expensive to use.
Entity:
public class Release extends AbstractEntity {
    ...
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(
            name = "releases_artists",
            joinColumns = @JoinColumn(name = "release_id"),
            inverseJoinColumns = @JoinColumn(name = "artist_id")
    )
    private Set<Artist> artists = new HashSet<>();
    ...
}
The class where the exception is thrown:
@Transactional
public class ReleaseXmlReader extends XmlReaderArrays<Release> {
    ...
    @Override
    protected void handle(Release release) {
        Release releaseFromDb = releaseRepository
                .findFirstByFonalId(release.getFonalId()).orElse(null);
        if (releaseFromDb != null) {
            for (Artist artist : release.getArtists()) {
                if (releaseFromDb.getArtists() <-- HERE
                        .stream()
                        .noneMatch(artist1 -> artist1.getDiscogsArtistId() != null)
                ) {
        ....
             
        releaseRepository.save(releaseFromDb);
    }
}
Parent abstract class:
@Transactional
public abstract class XmlReaderArrays<T extends AbstractEntity> {
    ....
    public void parse() {
        try {
            XMLStreamReader reader = XMLInputFactory
                    .newInstance()
                    .createXMLStreamReader(inputStream);
            XmlMapper mapper = new XmlMapper();
            while (next(reader)) {
                limit--;
                try {
                    T obj = mapper.readValue(reader, type);
                    handle(obj); <--- HERE
                } catch (Exception e) {
                    log.error("Error parse xml", e);
                }
            }
        } catch (Exception e) {
            log.error("Error parse xml", e);
        }
    }
  
    ...
}
I tried to match annotation only with the parent class or only with the inheritor. I also tried to put the annotation on the methods, but it did not help.
答案1
得分: 1
为了使 @Transactional 起作用,Spring AOP 需要在您的 bean 上创建代理。这里有两个问题:
- 
在这里,您并没有使用 bean,只是将
handle作为同一类的方法。您必须注入一个 bean 并将其用作代理。 - 
这个方法是
protected的,但是它必须是public的才能使@Transactional起作用。 
英文:
In order for @Transactional to work, spring AOP needs to create a proxy over your bean. There are 2 issues here:
- 
Here you're not using bean, just using
handleas the method of the same class. You would have to inject a bean to use it as proxy. - 
The method is
protected, but it has to bepublicfor the@Transactionalto work. 
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论