hibernate: LazyInitializationException: could not

2019-01-03 01:52发布

Here's one that has me perplexed. I'm trying to implement a basic Hibernate DAO structure, but am having a problem.

Here's the essential code:

int startingCount = sfdao.count();
sfdao.create( sf );
SecurityFiling sf2 = sfdao.read( sf.getId() );
sfdao.delete( sf );
int endingCount = sfdao.count();

assertTrue( startingCount == endingCount );
assertTrue( sf.getId().longValue() == sf2.getId().longValue() );
assertTrue( sf.getSfSubmissionType().equals( sf2.getSfSubmissionType() ) );
assertTrue( sf.getSfTransactionNumber().equals( sf2.getSfTransactionNumber() ) );

It fails on the third assertTrue where it's trying to compare a value in sf to the corresponding value in sf2. Here's the exception:

org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:86)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:140)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
    at com.freightgate.domain.SecurityFiling_$$_javassist_7.getSfSubmissionType(SecurityFiling_$$_javassist_7.java)
    at com.freightgate.dao.SecurityFilingTest.test(SecurityFilingTest.java:73)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:40)

14条回答
何必那么认真
2楼-- · 2019-01-03 02:26

If you using Spring and JPA annotation, the simpliest way to avoid problem with session in lazy initialize is replaysing:

@PersistenceContext   

to

@PersistenceContext(type = PersistenceContextType.EXTENDED)
查看更多
我命由我不由天
3楼-- · 2019-01-03 02:30

See my article. I had the same problem - LazyInitializationException - and here's the answer I finally came up with:
http://community.jboss.org/wiki/LazyInitializationExceptionovercome
Setting lazy=false is not the answer - it can load everything all at once, and that's not necessarily good. Example:
1 record table A references:
5 records table B references:
25 records table C references:
125 records table D
...
etc. This is but one example of what can go wrong.
--Tim Sabin

查看更多
混吃等死
4楼-- · 2019-01-03 02:32

If you are managing the Hibernate session manually, you may want to look into sessionFactory.getCurrentSession() and associated docs here:

http://www.hibernate.org/hib_docs/v3/reference/en/html/architecture-current-session.html

查看更多
仙女界的扛把子
5楼-- · 2019-01-03 02:34

We encountered this error as well. What we did to solve the issue is we added a lazy=false in the Hibernate mapping file.

It appears we had a class A that's inside a Session that loads another class B. We are trying to access the data on class B but this class B is detached from the session.

In order for us to access this Class B, we had to specify in the class A's Hibernate mapping file the lazy=false attribute. For example,

     <many-to-one name="classA" 
                 class="classB"
                 lazy="false">
        <column name="classb_id"
                sql-type="bigint(10)" 
                not-null="true"/>
    </many-to-one>  
查看更多
老娘就宠你
6楼-- · 2019-01-03 02:36

By default, all one-to-many and many-to-many associations are fetched lazily upon being accessed for the first time.

In your use case, you could overcome this issue by wrapping all DAO operations into one logical transaction:

transactionTemplate.execute(new TransactionCallback<Void>() {
    @Override
    public Void doInTransaction(TransactionStatus transactionStatus) {

        int startingCount = sfdao.count();

        sfdao.create( sf );

        SecurityFiling sf2 = sfdao.read( sf.getId() );

        sfdao.delete( sf );

        int endingCount = sfdao.count();

        assertTrue( startingCount == endingCount );
        assertTrue( sf.getId().longValue() == sf2.getId().longValue() );
        assertTrue( sf.getSfSubmissionType().equals( sf2.getSfSubmissionType() ) );
        assertTrue( sf.getSfTransactionNumber().equals( sf2.getSfTransactionNumber() ) );

        return null;
    }
});

Another option is to fetch all LAZY associations upon loading your entity, so that:

SecurityFiling sf2 = sfdao.read( sf.getId() );

should fetch the LAZY submissionType too:

select sf
from SecurityFiling sf
left join fetch.sf.submissionType

This way, you eagerly fetch all lazy properties and you can access them after the Session gets closed too.

You can fetch as many [one|many]-to-one associations and one "[one|many]-to-many" List associations (because of running a Cartesian Product).

To initialize multiple "[one|many]-to-many", you should use Hibernate.initialize(collection), right after loading your root entity.

查看更多
混吃等死
7楼-- · 2019-01-03 02:37

It seems only your DAO are using session. Thus a new session is open then close for each call to a DAO method. Thus the execution of the program can be resumed as:

// open a session, get the number of entity and close the session
int startingCount = sfdao.count();

// open a session, create a new entity and close the session
sfdao.create( sf );

// open a session, read an entity and close the session
SecurityFiling sf2 = sfdao.read( sf.getId() );

// open a session, delete an entity and close the session
sfdao.delete( sf );

etc...

By default, collection and association in an entity are lazy: they are loaded from the database on demand. Thus:

sf.getSfSubmissionType().equals( sf2.getSfSubmissionType() )

is throwing an exception because it request a new loading from the database, and the session associated with the loading of the entity has already been closed.

There is two approaches to resolve this problem:

  • create a session to enclosed all our code. Thus it would mean changing your DAO content to avoid opening a second session

  • create a session then update (i.e. reconnect) your entity to this session before the assertions.

    session.update(object);

查看更多
登录 后发表回答