- HibernateTemplate的saveOrUpdate等方法的执行过程
- Hibernate怎么管理Session
- 事务读写与FlushMode关系
- Session与事务的关系
- Session与事务传播级别的关系
- HttpSession与Hibernate Session区别
- 一条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
,通过实现HibernateCallback
的doInHibernate
方法,再通过调用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的代理。
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等绑定。
具体getCurrentSession
和openSession
要看具体的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确定占位符的位置,替换后执行插入语句。