hibernate使用防雷指南(持续更新)

hibernate使用防雷指南

hibernate使用过程中遇见的问题

  • 线上莫名其妙有些持久态对象需要update的数据没有update了。
  • 有些代码仅仅修改了属性,并没有显示的调用update,却更新了。
  • 持续更新ing

hibernate存储机制

hibernate持久化对象

首先先了解hibernate管理对象的两种状态

  1. 游离态,实例化的对象,并未在hibernate的管控之中比如:Person person = new Person();
  2. 托管态/持久态:在hibernate管理中的实例化对象,比如session.get( Person.class, personId );session.save( person );

hibernate持久化对象机制:查出来的持久态对象,只有修改过其中的属性,那么在hibernate的session触发任何更新操作时,都会自动更新,更新操作有:AUTO(自动刷新,在事务提交时)COMMIT MANUAL


官方文档说明:

注意hibernate官方文档中的这样一段话

Entities in managed/persistent state may be manipulated by the application and any changes will be automatically detected and persisted when the persistence context is flushed. There is no need to call a particular method to make your modifications persistent.

最后一句,无需调用特意的方法去将数据持久化。说明hibernate管理的持久态对象会在某些时候自动提交更新。这里尤为重要。

如果持久态变成游离态则不会自动持久化

5.10. Working with detached data

Detachment is the process of working with data outside the scope of any persistence context. Data becomes detached in a number of ways. Once the persistence context is closed, all data that was associated with it becomes detached. Clearing the persistence context has the same effect. Evicting a particular entity from the persistence context makes it detached. And finally, serialization will make the deserialized form be detached (the original instance is still managed).

Detached data can still be manipulated, however the persistence context will no longer automatically know about these modification and the application will need to intervene to make the changes persistent again.

我们常用的merge的官方定义

Merging is the process of taking an incoming entity instance that is in detached state and copying its data over onto a new managed instance.

将游离态对象数据copy到一个新的持久态中

详见官方文档

hibernate与事务

hibernate的一级缓存和事务是相关联的,如果在不同事务中,一级缓存是无法共享的,比如说使用hibernate持久态对象进行更新数据后,又在新的事务获取该对象,新事物会重新从数据库读取,而不是之前事务session的一级缓存。


官方说明:

关于hibernate的一级缓存和事务的官方文档

Session (org.hibernate.Session)

A single-threaded, short-lived object conceptually modeling a “Unit of Work” PoEAA. In JPA nomenclature, the Session is represented by an EntityManager.

Behind the scenes, the Hibernate Session wraps a JDBC java.sql.Connection and acts as a factory for org.hibernate.Transaction instances. It maintains a generally “repeatable read” persistence context (first level cache) of the application domain model.

Transaction (org.hibernate.Transaction)

A single-threaded, short-lived object used by the application to demarcate individual physical transaction boundaries. EntityTransaction is the JPA equivalent and both act as an abstraction API to isolate the application from the underlying transaction system in use (JDBC or JTA).

关键语句:the Hibernate Session wraps a JDBC java.sql.Connection and acts as a factory for org.hibernate.Transaction instances. session作为一级缓存,代表了数据库的连接和hibernate的事务实例。

具体实现:org.hibernate.SessionFactory#getCurrentSession获取当前session的方法。如果用此方法获取session,那么必须要开启事务获取session。

	/**
	 * Retrieve the Spring-managed Session for the current thread, if any.
	 */
	@Override
	@SuppressWarnings("deprecation")
	public Session currentSession() throws HibernateException {
		Object value = TransactionSynchronizationManager.getResource(this.sessionFactory);
		if (value instanceof Session) {
			return (Session) value;
		}
		else if (value instanceof SessionHolder) {
			SessionHolder sessionHolder = (SessionHolder) value;
			Session session = sessionHolder.getSession();
			if (!sessionHolder.isSynchronizedWithTransaction() &&
					TransactionSynchronizationManager.isSynchronizationActive()) {
				TransactionSynchronizationManager.registerSynchronization(
						new SpringSessionSynchronization(sessionHolder, this.sessionFactory, 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 = SessionFactoryUtils.getFlushMode(session);
				if (flushMode.equals(FlushMode.MANUAL) &&
						!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
					session.setFlushMode(FlushMode.AUTO);
					sessionHolder.setPreviousFlushMode(flushMode);
				}
			}
			return session;
		}

		if (this.transactionManager != null) {
			try {
				if (this.transactionManager.getStatus() == Status.STATUS_ACTIVE) {
					Session session = this.jtaSessionContext.currentSession();
					if (TransactionSynchronizationManager.isSynchronizationActive()) {
						TransactionSynchronizationManager.registerSynchronization(new SpringFlushSynchronization(session));
					}
					return session;
				}
			}
			catch (SystemException ex) {
				throw new HibernateException("JTA TransactionManager found but status check failed", ex);
			}
		}

		if (TransactionSynchronizationManager.isSynchronizationActive()) {
			Session session = this.sessionFactory.openSession();
			if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
				session.setFlushMode(FlushMode.MANUAL);
			}
			SessionHolder sessionHolder = new SessionHolder(session);
			TransactionSynchronizationManager.registerSynchronization(
					new SpringSessionSynchronization(sessionHolder, this.sessionFactory, true));
			TransactionSynchronizationManager.bindResource(this.sessionFactory, sessionHolder);
			sessionHolder.setSynchronizedWithTransaction(true);
			return session;
		}
		else {
			throw new HibernateException("Could not obtain transaction-synchronized Session for current thread");
		}
	}

你可能感兴趣的:(疑难BUG,技术笔记)