让JPA支持Hibernate事务隔离级别配置

原创
2013/01/10 13:37
阅读数 4.5K

JPA本身不提供事务的隔离级别这个概念,所以如果直接配置如 isolation="READ_COMMITTED" 时,后台会报异常 

Standard JPA does not support custom isolation levels - use a special JpaDialect

如果想使用配置隔离级别需要自己写代码让jpa支持,代码里面用的是hibernate4。

public class HibernateJpaIsolationSupportDialect extends HibernateJpaDialect {
	private static final long serialVersionUID = 1L;
	
	private Logger logger = LoggerFactory
			.getLogger(HibernateJpaIsolationSupportDialect.class);

	@Override
	public Object beginTransaction(final EntityManager entityManager,
			final TransactionDefinition definition)
			throws PersistenceException, SQLException, TransactionException {
		if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {
			getSession(entityManager).getTransaction().setTimeout(
					definition.getTimeout());
		}
		if (logger.isDebugEnabled()) {
			logger.debug(
					"Transaction Info: IsolationLevel={} , PropagationBehavior={} , Timeout={} , Name={}",
					new Object[] { definition.getIsolationLevel(),
							definition.getPropagationBehavior(),
							definition.getTimeout(), definition.getName()});
		}
		logger.debug("The isolation level set on the transaction is {}",
				definition.getIsolationLevel());
		ConnectionHandle connHandle = getJdbcConnection(entityManager, definition.isReadOnly());
		Connection conn = connHandle.getConnection();
		Integer previousIsolationLevel = DataSourceUtils
				.prepareConnectionForTransaction(conn, definition);
		logger.debug("The previousIsolationLevel {}", previousIsolationLevel);
		
		entityManager.getTransaction().begin();
		Object transactionData = prepareTransaction(entityManager,
				definition.isReadOnly(), definition.getName());

		return new IsolationSupportSessionTransactionData(transactionData,
				previousIsolationLevel, conn);
	}

	@Override
	public void cleanupTransaction(Object transactionData) {
		IsolationSupportSessionTransactionData isstd = (IsolationSupportSessionTransactionData) transactionData;
		super.cleanupTransaction(isstd.getSessionTransactionData());
		isstd.resetIsolationLevel();
	}

	private static class IsolationSupportSessionTransactionData {

		private final Object sessionTransactionData;
		private final Integer previousIsolationLevel;
		private final Connection connection;

		public IsolationSupportSessionTransactionData(
				Object sessionTransactionData,
				Integer previousIsolationLevel, Connection connection) {
			this.sessionTransactionData = sessionTransactionData;
			this.previousIsolationLevel = previousIsolationLevel;
			this.connection = connection;
		}

		public void resetIsolationLevel() {
			if (this.previousIsolationLevel != null) {
				DataSourceUtils.resetConnectionAfterTransaction(connection,
						previousIsolationLevel);
			}
		}

		public Object getSessionTransactionData() {
			return this.sessionTransactionData;
		}

	}

}

然后事务配置里面使用我们自己写的HibernateJpaIsolationSupportDialect。

<!-- transactionManager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="jpaDialect">
<bean class="framework.support.hibernate.HibernateJpaIsolationSupportDialect" />
</property>
</bean>

,另外entityManagerFactory里面的jpaVendorAdapter,不要使用否则HibernateJpaIsolationSupportDialect不起作用。

<!-- <property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false"/>
<property name="database" value="MYSQL"/>
</bean>
</property> -->

关于这个问题的讨论帖: http://stackoverflow.com/questions/5234240/hibernatespringjpaisolation-does-not-work
展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
2 收藏
0
分享
返回顶部
顶部