Hibernate Lazy Loading patch

I was frustrated with the way that Hibernate handles lazy initialization, because there are certain cases, especially in a Swing application, where it is very difficult to efficiently preload all the data, and where unacceptable architecture modifications are required to ensure that all objects which might be lazy loaded are in an open, connected session.

To fix this, I've created what I think is a very small, non-disruptive patch to allow lazy loading outside of an open, connected session.

Steps 1 through 3 add pluggable collection loading to Hibernate, but do not actually change the way that Hibernate currently functions. Steps 4 and 5 are optional steps that takes advantage of this pluggable loading behavior to implement lazy loading with closed or disconnected sessions.

Step 1:

Modify the AbstractPersistenceCollection class. This is the only change to existing Hibernate code. Overwrite the initialize(boolean) method with the following code:

	protected final void initialize(boolean writing) {
		if (!initialized) {
			ProxyInitializer.sharedInstance().initializeCollection( this, initializing, session, getCollectionSnapshot() );
		}
	}
Step 2:

Create two new subclasses of LazyInitializationException:

public class SessionDisconnectedException extends LazyInitializationException {
	public SessionDisconnectedException(String msg) {
		super(msg);
	}
}

public class SessionMissingException extends LazyInitializationException {
	public SessionMissingException(String msg) {
		super(msg);
	}
}
Step 3:

Create a new class, org.hibernate.ProxyInitializer:

public class ProxyInitializer {
	private static ProxyInitializer sharedInstance;
	
	public static ProxyInitializer sharedInstance() {
		if( sharedInstance == null ) {
			sharedInstance = new ProxyInitializer();
		}
		return sharedInstance;
	}
	
	public static void setSharedInstance( ProxyInitializer initializer ) {
		sharedInstance = initializer;
	}
	
	public void initializeCollection(PersistentCollection collection, boolean initializing, SessionImplementor session, CollectionSnapshot snapshot) throws SessionMissingException, SessionDisconnectedException {
		if (initializing) {
			throw new LazyInitializationException("illegal access to loading collection");
		}
		if( session == null ) throwSessionMissingException("no session", snapshot);
		if( ! session.isOpen() ) throwSessionMissingException("session was closed", snapshot);
		if( ! session.isConnected() ) throwSessionDisconnectedException("session is disconnected", snapshot);
		
		session.initializeCollection( collection, false );
	}
	
	private void throwSessionMissingException(String msg, CollectionSnapshot snapshot) {
		String name = snapshot==null ? "" : " of role: " + snapshot.getRole();
		throw new SessionMissingException("failed to lazily initialize a collection" + name + " - " + msg);
	}
	
	private void throwSessionDisconnectedException(String msg, CollectionSnapshot snapshot) {
		String name = snapshot==null ? "" : " of role: " + snapshot.getRole();
		throw new SessionDisconnectedException("failed to lazily initialize a collection" + name + " - " + msg);
	}
}
Step 4:

If you do nothing at this point, then Hibernate will continue to work exactly as it previously did. However, you may choose to subclass ProxyInitializer and override the initializeCollection() method. You can call the super method, catch the exception, and then take some other action if you wish. For example, here is how I've implemented my lazy loading. Feel free to use this verbatim, or come up with your own implementation:

private class MyLazyLoader extends ProxyInitializer {
	public void initializeCollection(PersistentCollection collection, boolean initializing, SessionImplementor session, CollectionSnapshot snapshot) {
		try {
			super.initializeCollection(collection, initializing, session, snapshot);
		} catch( SessionDisconnectedException e) {
			session.reconnect();
			try {
				fetchInOpenSession(session, collection, initializing, snapshot);
			} finally {
				session.disconnect();
			}
		} catch(SessionMissingException e) {
			SessionImplementor lazySession = (SessionImplementor)mySessionFactory.openSession();
			try {
				fetchInOpenSession(lazySession, collection, initializing, snapshot);
			} finally {
				lazySession.close();
			}
		}
	}

	private void fetchInOpenSession(SessionImplementor lazySession, PersistentCollection collection, boolean initializing, CollectionSnapshot snapshot) {
		Transaction tx = null;
		try {
			tx = lazySession.beginTransaction();
			lazySession.lock( collection.getOwner(), LockMode.NONE );
			super.initializeCollection( collection, initializing, lazySession, snapshot );
			tx.commit();
		} catch(HibernateException e1) {
			if( tx != null ) tx.rollback();
			throw e1;
		}
	}
}
Step 5:

If you create your own subclass as in step 4, you need to set it as the shared static instance in ProxyInitializer, like this:

ProxyInitializer.setSharedInstance( new MyLazyLoader() );

That should be it... please let me know how well this works for you. I've tested this and it seems to work fine, but I have not used it in a complex application yet. I'd love to know what you think of this

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值