package org.easyframe.enterprise.spring;
import java.sql.SQLException;
import java.sql.Savepoint;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import jef.database.jpa.JefEntityManager;
import jef.database.support.SavepointNotSupportedException;
import org.springframework.jdbc.datasource.ConnectionHolder;
import org.springframework.orm.jpa.DefaultJpaDialect;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.NestedTransactionNotSupportedException;
import org.springframework.transaction.SavepointManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
/**
* 标准的JPA API中因为没有关于savepoint的特性,因此Spring是不支持使用nested这个事务传播级别的,
* 这个dialect可以使Spring的7个传播级别全部得到支持
* 在Spring中配置如下
* <pre>
* <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" lazy-init="true">
* <property name="entityManagerFactory" ref="entityManagerFactory" />
* <property name="jpaDialect">
* <bean class="org.jef.enterprise.spring.JefJpaDialect"/>
* </property>
* </bean>
* </pre>
*
* @author jiyi
*
*/
public class JefJpaDialect extends DefaultJpaDialect {
private static final long serialVersionUID = 1L;
public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition) throws PersistenceException, SQLException, TransactionException {
JefEntityManager em = getJefEntityManager(entityManager);
return new JefJpaTransactionData(em,definition);
}
private JefEntityManager getJefEntityManager(EntityManager entityManager) {
if (entityManager instanceof JefEntityManager)
return (JefEntityManager) entityManager;
throw new IllegalStateException("You should use jef.database.DbClientFacotry for EntityManagerFactory!");
}
/**
* Transaction data Object exposed from <code>beginTransaction</code>,
* implementing the SavepointManager interface.
*/
private static class JefJpaTransactionData implements SavepointManager {
private final JefEntityManager entityManager;
private int savepointCounter = 0;
public JefJpaTransactionData(JefEntityManager entityManager,TransactionDefinition def) {
this.entityManager = entityManager;
entityManager.getTransaction().begin(def.getTimeout(),def.getIsolationLevel(),def.isReadOnly());
}
public Object createSavepoint() throws TransactionException {
this.savepointCounter++;
String savepointName = ConnectionHolder.SAVEPOINT_NAME_PREFIX + this.savepointCounter;
try {
Savepoint sp=this.entityManager.setSavepoint(savepointName);
return sp;
} catch (SavepointNotSupportedException e) {
throw new NestedTransactionNotSupportedException("Cannot create a nested transaction because savepoints are not supported.");
} catch (Throwable ex) {
throw new CannotCreateTransactionException("Could not create JDBC savepoint", ex);
}
}
public void rollbackToSavepoint(Object savepoint) throws TransactionException {
if(savepoint!=null){
this.entityManager.rollbackToSavepoint((Savepoint) savepoint);
}
}
public void releaseSavepoint(Object savepoint) throws TransactionException {
if(savepoint!=null){
this.entityManager.releaseSavepoint((Savepoint) savepoint);
}
}
}
}