`

hiberante获取session的故事

阅读更多
    使用hibernate时,接口SessionFactory中获取session的方法挺多:openSession, getCurrentSession.如果使用spring,则有更多的用法。这些用法不免迷惑,他们分别是什么意思,哪些会自动提交呢?
    下面是我结合实例与源码的分析。

没有使用spring管理的情况
主要区别openSession()和openCurrentSession(),openSession()即打开一个session,但程序中直接使用它,而是使用getCurrentSession(),典型用法如下(没有使用spring申明式管理管理事务)
private List listEvents() {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        List result = session.createQuery("from Event").list();
        session.getTransaction().commit();
        return result;
 }


openCurrentSession()即获取当前上下文session

/**
	 * Obtains the current session.  The definition of what exactly "current"
	 * means controlled by the {@link org.hibernate.context.CurrentSessionContext} impl configured
	 * for use.
	 * <p/>
	 * Note that for backwards compatibility, if a {@link org.hibernate.context.CurrentSessionContext}
	 * is not configured but a JTA {@link org.hibernate.transaction.TransactionManagerLookup}
	 * is configured this will default to the {@link org.hibernate.context.JTASessionContext}
	 * impl.
	 *
	 * @return The current session.
	 *
	 * @throws HibernateException Indicates an issue locating a suitable current session.
	 */
	public org.hibernate.classic.Session getCurrentSession() throws HibernateException;



private CurrentSessionContext buildCurrentSessionContext() {
		String impl = properties.getProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS );
		// for backward-compatability
		if ( impl == null && transactionManager != null ) {
			impl = "jta";
		}

		if ( impl == null ) {
			return null;
		}
		else if ( "jta".equals( impl ) ) {
			if ( settings.getTransactionFactory().areCallbacksLocalToHibernateTransactions() ) {
				log.warn( "JTASessionContext being used with JDBCTransactionFactory; auto-flush will not operate correctly with getCurrentSession()" );
			}
			return new JTASessionContext( this );
		}
		else if ( "thread".equals( impl ) ) {
			return new ThreadLocalSessionContext( this );
		}
		else if ( "managed".equals( impl ) ) {
			return new ManagedSessionContext( this );
		}
		else {
			try {
				Class implClass = ReflectHelper.classForName( impl );
				return ( CurrentSessionContext ) implClass
						.getConstructor( new Class[] { SessionFactoryImplementor.class } )
						.newInstance( new Object[] { this } );
			}
			catch( Throwable t ) {
				log.error( "Unable to construct current session context [" + impl + "]", t );
				return null;
			}
		}
	}

从上面获取CurrentSessionContext的方法中看出,current session是由配置文件制定,默认是jta。如果使用spring管理,切勿配置该项,默认将为springContextProvider
current_session_context_class thread 


使用spring管理
spring中的HibernateTemplate有对hibernate的封装,有很多便捷的方法,在DAO实现中
        @Override
	public Magic read(int id) {
		return super.getHibernateTemplate().get(Magic.class, id);
	}

但是如果需要自己使用复杂的组合查找,可以使用excute(new HiberanteCallback())
public <T> T get(final Class<T> entityClass, final Serializable id, final LockMode lockMode)
			throws DataAccessException {

		return executeWithNativeSession(new HibernateCallback<T>() {
			@SuppressWarnings("unchecked")
			public T doInHibernate(Session session) throws HibernateException {
				if (lockMode != null) {
					return (T) session.get(entityClass, id, lockMode);
				}
				else {
					return (T) session.get(entityClass, id);
				}
			}
		});
	}


这样调用获取的session是通过下面这个方法
/**
	 * Return a Session for use by this template.
	 * <p>Returns a new Session in case of "alwaysUseNewSession" (using the same
	 * JDBC Connection as a transactional Session, if applicable), a pre-bound
	 * Session in case of "allowCreate" turned off, and a pre-bound or new Session
	 * otherwise (new only if no transactional or otherwise pre-bound Session exists).
	 * @return the Session to use (never <code>null</code>)
	 * @see SessionFactoryUtils#getSession
	 * @see SessionFactoryUtils#getNewSession
	 * @see #setAlwaysUseNewSession
	 * @see #setAllowCreate
	 */
	protected Session getSession() {
		if (isAlwaysUseNewSession()) {
			return SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor());
		}
		else if (isAllowCreate()) {
			return SessionFactoryUtils.getSession(
					getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
		}
		else if (SessionFactoryUtils.hasTransactionalSession(getSessionFactory())) {
			return SessionFactoryUtils.getSession(getSessionFactory(), false);
		}
		else {
			try {
				return getSessionFactory().getCurrentSession();
			}
			catch (HibernateException ex) {
				throw new DataAccessResourceFailureException("Could not obtain current Hibernate Session", ex);
			}
		}
	}


SessionFactoryUtil中的逻辑如下

	/**
	 * Get a Hibernate Session for the given SessionFactory. Is aware of and will
	 * return any existing corresponding Session bound to the current thread, for
	 * example when using {@link HibernateTransactionManager}. Will create a new
	 * Session otherwise, if "allowCreate" is <code>true</code>.
	 * <p>Same as {@link #getSession}, but throwing the original HibernateException.
	 * @param sessionFactory Hibernate SessionFactory to create the session with
	 * @param entityInterceptor Hibernate entity interceptor, or <code>null</code> if none
	 * @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
	 * Session on transaction synchronization (may be <code>null</code>)
	 * @param allowCreate whether a non-transactional Session should be created
	 * when no transactional Session can be found for the current thread
	 * @return the Hibernate Session
	 * @throws HibernateException if the Session couldn't be created
	 * @throws IllegalStateException if no thread-bound Session found and
	 * "allowCreate" is <code>false</code>
	 */
	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.MANUAL, 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.MANUAL);
			}
			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;
	}


可以看出,总体的获取session的顺序是先查看spring的transaction manager, 其次JTA, 再次调用getCurrentSession,在getCurrentSession也会有JTA的回退,可能有重复的地方。
0
0
分享到:
评论

相关推荐

    DAO层中对Hiberante

    在进行任何数据库操作之前,都需要先获取一个`Session`。 2. `getTransaction()`:返回当前的`Transaction`实例,可以用来检查事务的状态或者提交或回滚事务。 3. `beginTransaction()`:启动一个新的数据库事务。在...

    hiberante 源码 配置资料

    例如,ConnectionProvider负责数据库连接的获取和释放,而StatementExecutor处理SQL执行。 4. 查询机制:Hibernate Query Language (HQL) 和 Criteria API 是两种主要的查询方式。`org.hibernate.query`包下的Query...

    Hiberante中的五大核心接口.txt

    - **读取配置**:`Configuration` 类可以加载并解析配置文件,从而获取数据库连接的信息、缓存策略以及其他配置参数。 - **构建SessionFactory**:通过调用 `Configuration` 的 `buildSessionFactory()` 方法来创建 ...

    hiberante查询方式使用详解

    例如,获取所有用户的ID: ```java String sql = "SELECT id FROM User"; SQLQuery query = session.createSQLQuery(sql); List&lt;Integer&gt; ids = query.list(); ``` 接下来是QBC,即Query By Example,是一种基于...

    hiberante有关配置说明

    例如,使用HQL获取所有用户: ```java String hql = "from User"; Query&lt;User&gt; query = session.createQuery(hql, User.class); List&lt;User&gt; users = query.getResultList(); ``` Criteria API查询: ```java ...

    Hiberante HTML 帮助文档

    本帮助文档首先会介绍Hibernate的基本概念和工作原理,包括实体类、配置文件、Session工厂和Session接口等核心元素。通过学习,读者将理解如何创建Hibernate项目,定义实体类,以及设置相应的数据库连接信息。 接着...

    Hiberante读取BLOB数据类型.

    例如,我们可以从查询结果集中获取BLOB对象,然后通过流操作读取其内容: ```java Session session = HibernateUtil.getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); ...

    hiberante中文帮助文档

    而立即加载则是在获取主对象时,同时加载其关联的对象。 这份文档深入浅出地讲解了这些核心概念,并且包含了大量的示例代码,无论是初学者还是经验丰富的开发者,都能从中受益。在实际开发中,配合阅读此文档,可以...

    疯狂Ajax讲义3+Spring+hiberante

    1. Hibernate配置与实体类:创建实体类,映射到数据库表,以及配置Hibernate的session工厂和事务管理。 2. Ajax与Hibernate的结合:通过Ajax请求更新数据库,Hibernate负责将Java对象转换为SQL语句执行。 3. ...

    struts2_hiberante_spring

    同时,Struts2的Action可以通过Spring的依赖注入获取到业务服务,降低了Action与业务层之间的耦合。 具体到这个"SSH整合架包jar",它可能包含了这三个框架的库文件,以及一些整合所需的配置文件,比如struts.xml、...

    黑马程序员 hibernate 2017版讲义资料-day2

    通过Session的get()或load()方法,可以获取数据库中的数据;更新实体后,使用Session的update()方法,将改动保存回去;删除实体时,调用Session的delete()方法。 此外,还要了解一对多、一对一、多对一和多对多等...

    hiberante - one to many - update

    例如,如果新增了一个订单并添加到User的orders列表中,然后调用`session.saveOrUpdate(user)`,Hibernate会将新订单保存到数据库,并通过外键关联到用户。 但是,需要注意的是,级联操作可能导致数据一致性问题,...

    hibernate存取oracle的clob

    Session session = factory.openSession(); Transaction tx = session.beginTransaction(); User user = new User(); user.setName("Jacky"); user.setAge(20); user.setContent(Hibernate.createClob("This is my...

    hiberante ref document

    4. 加载(Load)/获取(Get):根据ID获取持久化对象,Load会立即执行SQL查询,而Get在需要时才加载。 5. 查询(Query):通过HQL或Criteria API进行复杂查询,支持分页、排序、关联查询等。 六、关联映射 ...

    spring,Struts,Hiberante整合的小例子

    3. 配置Struts2:修改Struts2的配置文件(如`struts-default.xml`或自定义的`struts.xml`),定义Action类和结果类型,并配置Spring插件,以便Action类可以从Spring容器中获取依赖。 4. 创建Action类:Action类通常...

    hiberante 学习PDF

    Hibernate 通过 DataSource 对象自动管理数据库连接,开发者无需手动获取和释放连接。 #### 查询与检索 - **HQL(Hibernate Query Language)**:一种面向对象的查询语言,类似于 SQL,但更加面向对象。 - **...

    Hibernate双向一对一关联映射(XML版)

    - 这样,当我们通过Hibernate操作`Person`时,可以直接获取或设置其`Address`,反之亦然。 4. **示例代码**: - 创建和保存实体: ```java Session session = HibernateUtil.getSessionFactory().openSession()...

    springboot集成hibernate

    `getSession()`方法获取当前Session,`beginTransaction()`和`commit()`分别用于开始和提交事务,而`save()`方法用于保存实体到数据库。 最后,我们可以在Service或Controller中注入UserDAO,调用其方法来实现业务...

    hibernate小程序

    在这个测试程序中,我们可能会看到`SessionFactory`的获取和`Session`的打开、关闭过程。 5. **数据插入**:插入数据通常涉及以下步骤: - 开启`Session` - 创建实体对象,设置属性值 - 调用`Session`的`save()`...

Global site tag (gtag.js) - Google Analytics