Hibernate saveOrUpdate源码解析

  1. HibernateTemplate的saveOrUpdate等方法的执行过程
  2. Hibernate怎么管理Session
  3. 事务读写与FlushMode关系
  4. Session与事务的关系
  5. Session与事务传播级别的关系
  6. HttpSession与Hibernate Session区别
  7. 一条hql语句的执行过程

HibernateTemplate的saveOrUpdate等方法的执行过程

SessionImpl 实现了EventSource(封转保存等事件时,记录事件的原Session)接口,继承了AbstractSessionImpl

HibernateTemplate saveOrUpdate方法的剖析

		public void saveOrUpdate(final Object entity) throws DataAccessException {
		executeWithNativeSession(new HibernateCallback<Object>() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException {
				checkWriteOperationAllowed(session);
				session.saveOrUpdate(entity);
				return null;
			}
		});
	}

一。获取session
HibernateTemplate里面的数据库操作的方法大部分是通过调用executeWithNativeSession,通过实现HibernateCallbackdoInHibernate方法,再通过调用session的具体数据库操作方法,例如:saveOrUpdate

executeWithNativeSession方法非常简单,只有一行代码return doExecute(action, true); 主要用来创建决定使用哪一个Session作为参数用来执行具体的数据库操作。

	protected <T> T doExecute(HibernateCallback<T> action, boolean enforceNativeSession) throws DataAccessException {
		Session session = null;
		boolean isNew = false;
		try {
			session = getSessionFactory().getCurrentSession();
		}
		catch (HibernateException ex) {
			logger.debug("Could not retrieve pre-bound Hibernate session", ex);
		}
		if (session == null) {
			session = getSessionFactory().openSession();
			session.setFlushMode(FlushMode.MANUAL);
			isNew = true;
		}

		try {
			enableFilters(session);
			Session sessionToExpose =
					(enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session));
			return action.doInHibernate(sessionToExpose);
		}
		//此处省去了异常的catch
		finally {
			if (isNew) {
				SessionFactoryUtils.closeSession(session);
			}
			else {
				disableFilters(session);
			}
		}
	}

doExecute方法主要用来决定使用现有session还是新开一个session,需不需要使用session的代理。

  1. session = getSessionFactory().getCurrentSession(); Session的绑定关系可以通过hibernate.current_session_context_class指定。获取当前存在的session。

例如thread和jta。当你使用Spring 声明式事务的时候 (@Transactional, tx标签 …), @Transactional声明式事务管理 会创建一个 绑定了事务的session并把 该session放到SpringSessionContext 这个上下文中, 所以在使用声明式事务并且使用 getCurrentSession()这个方法的时候,只有从 SpringSessionContext 上下文中才能取到当前的session, 这就要求将 hibernate.current_session_context_class 这个值设置为org.springframework.orm.hibernate4.SpringSessionContext, 在spring 配置文件中, 在使用LocalSessionFactoryBean时会自动的设置这个值, 不需要你去设置, 所以在spring 配置中 hibernate.current_session_context_class 默认就是SpringSessionContext;
引自 https://blog.youkuaiyun.com/gladmustang/article/details/40025879

2.session = getSessionFactory().openSession();当前情况下如果不存在Session则新建一个session,并与依赖的thread等绑定。
具体getCurrentSessionopenSession 要看具体的session工厂的具体实现方式。// 后续会继续分析thread、jta和spring的LocalSessionFactoryBean的实现方式和区别。

二 通过session执行具体的操作
拿到session后,return action.doInHibernate(sessionToExpose);通过回调函数doInHibernate执行具体的数据库操作。以saveOrUpdate为例,最终通过调用session.saveOrUpdate(entity);实现。

	@Override
	public void saveOrUpdate(String entityName, Object obj) throws HibernateException {
		fireSaveOrUpdate( new SaveOrUpdateEvent( entityName, obj, this ) );
	}

代码很简单,重点是是封装了SaveOrUpdateEvent的第三个构造函数,将Session赋值给事件中的EventSource对象,后续会用到这个对象,事件执行后的一系列与Session有关的操作都是通过该对象完成的。

public class SaveOrUpdateEvent extends AbstractEvent {
    private final EventSource session; //AbstractEvent的属性 记录事件的原Session
	private Object object; // 要保存的实体
	private Serializable requestedId;
	private String entityName; // 实体的名字
	private Object entity; // 持久化上下文解析后的实体,真正入库的实体
	private EntityEntry entry;
	private Serializable resultId;
}

SaveOrUpdateEvent包含了实体的内容,当前关联的Session,实体的名字等信息

	private void fireSaveOrUpdate(SaveOrUpdateEvent event) {
		errorIfClosed();
		checkTransactionSynchStatus();
		checkNoUnresolvedActionsBeforeOperation();
		for ( SaveOrUpdateEventListener listener : listeners( EventType.SAVE_UPDATE ) ) {
			listener.onSaveOrUpdate( event );
		}
		checkNoUnresolvedActionsAfterOperation();
	}
	public void onSaveOrUpdate(SaveOrUpdateEvent event) {
		final SessionImplementor source = event.getSession();
		final Object object = event.getObject();
		final Serializable requestedId = event.getRequestedId();

		if ( requestedId != null ) { 
			//assign the requested id to the proxy, *before*
			//reassociating the proxy
			if ( object instanceof HibernateProxy ) {
				( (HibernateProxy) object ).getHibernateLazyInitializer().setIdentifier( requestedId );
			}
		}

		// For an uninitialized proxy, noop, don't even need to return an id, since it is never a save()
		if ( reassociateIfUninitializedProxy( object, source ) ) {
			LOG.trace( "Reassociated uninitialized proxy" );
		}
		else {
			//initialize properties of the event:
			final Object entity = source.getPersistenceContext().unproxyAndReassociate( object );
			event.setEntity( entity );
			event.setEntry( source.getPersistenceContext().getEntry( entity ) );
			//return the id in the event object
			event.setResultId( performSaveOrUpdate( event ) );
		}

	}
	protected Serializable performSaveOrUpdate(SaveOrUpdateEvent event) {
		EntityState entityState = getEntityState(
				event.getEntity(),
				event.getEntityName(),
				event.getEntry(),
				event.getSession()
		);

		switch ( entityState ) {
			case DETACHED:
				entityIsDetached( event );
				return null;
			case PERSISTENT:
				return entityIsPersistent( event );
			default: //TRANSIENT or DELETED
				return entityIsTransient( event );
		}
	}

performSaveOrUpdate通过当前要保存的实例的不同状态,执行不同的持久化的策略。DETACHED 游离态 PERSISTENT 持久态 以及默认状态。
(// todo 实体状态的转移)重点看一下游离态下的保存。游离态的保存只要通过以下方法实现。

	protected void performUpdate(
			SaveOrUpdateEvent event,
			Object entity,
			EntityPersister persister) throws HibernateException {
		final EventSource source = event.getSession();
		final EntityKey key = source.generateEntityKey( event.getRequestedId(), persister );
		source.getPersistenceContext().checkUniqueness( key, entity );
		if ( invokeUpdateLifecycle( entity, persister, source ) ) {
			reassociate( event, event.getObject(), event.getRequestedId(), persister );
			return;
		}
		new OnUpdateVisitor( source, event.getRequestedId(), entity ).process( entity, persister );
		source.getPersistenceContext().addEntity(
				entity,
				( persister.isMutable() ? Status.MANAGED : Status.READ_ONLY ),
				null, // cachedState,
				key,
				persister.getVersion( entity ),
				LockMode.NONE,
				true,
				persister,
				false,
				true // assume true, since we don't really know, and it doesn't matter
		);
		persister.afterReassociate( entity, source );
		cascadeOnUpdate( event, persister, entity );
	}

从上面方法到数据库保存整个hibernate的调用量还很长,重点关注一下,在游离态保存时,会校验当前Session中有无统一id的key,存在会报错source.getPersistenceContext().checkUniqueness( key, entity );, 抛出NonUniqueObjectException异常。

从实体到sql的装换离不开Map<String,EntityPersister> entityPersisters 此对象是SessionFactoryImpl的一个属性,其随着SessionFactory的初始化完成所有对象与数据库的映射关系。其包含了项目中所有实体的EntityPersister对象。EntityPersister有很多实现类,常见的有SingleTableEntityPersister,其包含了实体与表的对应关系,例如该类中的sqlInsertStrings保存了实体类的insert sql 语句,sqlUpdateStrings更新语sql句,通过SingleTableEntityPersister确定占位符的位置,替换后执行插入语句。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值