`
michaelxz
  • 浏览: 21314 次
  • 性别: Icon_minigender_1
  • 来自: 遂宁
社区版块
存档分类
最新评论

胡扯OpenSessionIViewFilter

阅读更多

OpenSessionInViewFilter在网上已经有很多分析资料了,看人家写得那么好,心里痒痒的。于是决定自己也写一篇

 

protected void doFilterInternal(
			HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		SessionFactory sessionFactory = lookupSessionFactory(request);
		boolean participate = false;

		if (isSingleSession()) {
			// single session mode
			if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
				// Do not modify the Session: just set the participate flag.
				participate = true;
			}
			else {
				logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
				Session session = getSession(sessionFactory);
				TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
			}
		}
		else {
			// deferred close mode
			if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {
				// Do not modify deferred close: just set the participate flag.
				participate = true;
			}
			else {
				SessionFactoryUtils.initDeferredClose(sessionFactory);
			}
		}

		try {
			filterChain.doFilter(request, response);
		}

		finally {
			if (!participate) {
				if (isSingleSession()) {
					// single session mode
					SessionHolder sessionHolder =
							(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
					logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
					closeSession(sessionHolder.getSession(), sessionFactory);
				}
				else {
					// deferred close mode
					SessionFactoryUtils.processDeferredClose(sessionFactory);
				}
			}
		}
	}

  

这里面需要了解几个要点:

1.isSingleSession() 这个默认是true,代表使用OpenSessionInViewFilter

2.TransactionSynchronizationManager.hasResource(sessionFactory)

TransactionSynchronizationManager这个类中有一属性

private static final ThreadLocal resources = new ThreadLocal();

resources 里面存放的是map,而这个map里面存放的是sessionFactory和SessionHolder

public static void bindResource(Object key, Object value) throws IllegalStateException {
		Assert.notNull(key, "Key must not be null");
		Assert.notNull(value, "Value must not be null");
		Map map = (Map) resources.get();
		// set ThreadLocal Map if none found
		if (map == null) {
			map = new HashMap();
			resources.set(map);
		}
		if (map.containsKey(key)) {
			throw new IllegalStateException("Already value [" + map.get(key) + "] for key [" + key +
					"] bound to thread [" + Thread.currentThread().getName() + "]");
		}
		map.put(key, value);
		if (logger.isDebugEnabled()) {
			logger.debug("Bound value [" + value + "] for key [" + key + "] to thread [" +
					Thread.currentThread().getName() + "]");
		}
	}

 3.再接着就是比较重要的方法

Session session = getSession(sessionFactory);

	protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
		Session session = SessionFactoryUtils.getSession(sessionFactory, true);
		FlushMode flushMode = getFlushMode();
		if (flushMode != null) {
			session.setFlushMode(flushMode);
		}
		return session;
	}

因为有属性:private FlushMode flushMode = FlushMode.NEVER;

 session.setFlushMode(flushMode);
所以OpenSessionInViewFilter默认的FlushMode 是NEVER

private static Session doGetSession(
			SessionFactory sessionFactory, Interceptor entityInterceptor,
			SQLExceptionTranslator jdbcExceptionTranslator, boolean allowCreate)
			throws HibernateException, IllegalStateException {

		Assert.notNull(sessionFactory, "No SessionFactory specified");

		SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
		if (sessionHolder != null && !sessionHolder.isEmpty()) {
			// pre-bound Hibernate Session
			Session session = null;
			if (TransactionSynchronizationManager.isSynchronizationActive() &&
					sessionHolder.doesNotHoldNonDefaultSession()) {
				// Spring transaction management is active ->
				// register pre-bound Session with it for transactional flushing.
				session = sessionHolder.getValidatedSession();
				if (session != null && !sessionHolder.isSynchronizedWithTransaction()) {
					logger.debug("Registering Spring transaction synchronization for existing Hibernate Session");
					TransactionSynchronizationManager.registerSynchronization(
							new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false));
					sessionHolder.setSynchronizedWithTransaction(true);
					// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
					// with FlushMode.NEVER, which needs to allow flushing within the transaction.
					FlushMode flushMode = session.getFlushMode();
					if (flushMode.lessThan(FlushMode.COMMIT) &&
							!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
						session.setFlushMode(FlushMode.AUTO);
						sessionHolder.setPreviousFlushMode(flushMode);
					}
				}
			}
			else {
				// No Spring transaction management active -> try JTA transaction synchronization.
				session = getJtaSynchronizedSession(sessionHolder, sessionFactory, jdbcExceptionTranslator);
			}
			if (session != null) {
				return session;
			}
		}

		logger.debug("Opening Hibernate Session");
		Session session = (entityInterceptor != null ?
				sessionFactory.openSession(entityInterceptor) : sessionFactory.openSession());

		// Use same Session for further Hibernate actions within the transaction.
		// Thread object will get removed by synchronization at transaction completion.
		if (TransactionSynchronizationManager.isSynchronizationActive()) {
			// We're within a Spring-managed transaction, possibly from JtaTransactionManager.
			logger.debug("Registering Spring transaction synchronization for new Hibernate Session");
			SessionHolder holderToUse = sessionHolder;
			if (holderToUse == null) {
				holderToUse = new SessionHolder(session);
			}
			else {
				holderToUse.addSession(session);
			}
			if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
				session.setFlushMode(FlushMode.NEVER);
			}
			TransactionSynchronizationManager.registerSynchronization(
					new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true));
			holderToUse.setSynchronizedWithTransaction(true);
			if (holderToUse != sessionHolder) {
				TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse);
			}
		}
		else {
			// No Spring transaction management active -> try JTA transaction synchronization.
			registerJtaSynchronization(session, sessionFactory, jdbcExceptionTranslator, sessionHolder);
		}

		// Check whether we are allowed to return the Session.
		if (!allowCreate && !isSessionTransactional(session, sessionFactory)) {
			closeSession(session);
			throw new IllegalStateException("No Hibernate Session bound to thread, " +
			    "and configuration does not allow creation of non-transactional one here");
		}

		return session;
	}

if (sessionHolder != null && !sessionHolder.isEmpty()) 里面的内容感觉只有在多线程并发时才会触发

这里在介绍一个类SessionHolder,这个类用于包装session和transaction

 

接下来谈下事务和session的关系吧

首先看看Hibernate中对事务的一些方法的封装吧

public void begin() throws HibernateException {
		if (begun) {
			return;
		}
		if (commitFailed) {
			throw new TransactionException("cannot re-start transaction after failed commit");
		}

		log.debug("begin");

		try {
			toggleAutoCommit = jdbcContext.connection().getAutoCommit();
			if ( log.isDebugEnabled() ) {
				log.debug("current autocommit status: " + toggleAutoCommit);
			}
			if (toggleAutoCommit) {
				log.debug("disabling autocommit");
				jdbcContext.connection().setAutoCommit(false);
			}
		}
		catch (SQLException e) {
			log.error("JDBC begin failed", e);
			throw new TransactionException("JDBC begin failed: ", e);
		}

		callback = jdbcContext.registerCallbackIfNecessary();

		begun = true;
		committed = false;
		rolledBack = false;

		if ( timeout>0 ) {
			jdbcContext.getConnectionManager()
					.getBatcher()
					.setTransactionTimeout(timeout);
		}

		jdbcContext.afterTransactionBegin(this);
	}

 

jdbcContext.connection()是获取当前数据库的一个连接,大家可以看看c3p0的实现

public class C3P0ConnectionProvider implements ConnectionProvider {

	private DataSource ds;
	private Integer isolation;
	private boolean autocommit;

	private static final Log log = LogFactory.getLog(C3P0ConnectionProvider.class);

	public Connection getConnection() throws SQLException {
		final Connection c = ds.getConnection();
		if (isolation!=null) c.setTransactionIsolation( isolation.intValue() );
		if ( c.getAutoCommit()!=autocommit ) c.setAutoCommit(autocommit);
		return c;
	}

最后了解一个东东

Session.setFlushMode()用于设定清理缓存的时间点:
清理缓存的模式 Session的查询方法 Session.commit() Session.flush() FlushMode.AUTO 清理清理清理 FlushMode.COMMIT 不清理清理清理 FlushMode.NEVER 不清理不清理清

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics