从Hibernate迁移到Spring Data JPA - 会话和事务管理

时间:2017-07-30 12:26:29

标签: spring hibernate transactions spring-data-jpa spring-transactions

我们正在从程序化的Hibernate会话和事务管理迁移到基于Spring Data JPA的声明式事务。 但是当我使用日志级别调试记录Spring和Hibernate事务时,我看到了不同的行为 - *当我使用程序化的hibernate会话和事务管理时,我的finder和save方法调用在同一会话和事务下执行。

但是当我使用spring @transactional注释(默认传播是必需的)时,我看到在每个步骤中打开和关闭了entityManager和事务(即,即使它们在一个应用程序下,也分别用于查找和保存方法)等级交易)。我不明白的是,在一个应用程序级别的事务中调用查找和保存(调用方法有@Transactional - 参见下面的代码),它们应该在相同的位置执行,而不是打开和关闭它们自己(不是它)默认传播级别的行为REQUIRED意味着?)

以下是程序化会话管理的日志 -

    ******************transformAndSaveAdjustments
    2017-07-29 09:02:15,724 [transaction.spi.AbstractTransactionImpl 160 begin DEBUG]: begin
    2017-07-29 09:02:15,725 [jdbc.internal.LogicalConnectionImpl 226 obtainConnection DEBUG]: Obtaining JDBC connection
    2017-07-29 09:02:15,728 [jdbc.internal.LogicalConnectionImpl 232 obtainConnection DEBUG]: Obtained JDBC connection
    2017-07-29 09:02:15,728 [internal.jdbc.JdbcTransaction 69 doBegin DEBUG]: initial autocommit status: true
    2017-07-29 09:02:15,729 [internal.jdbc.JdbcTransaction 71 doBegin DEBUG]: disabling autocommit
    2017-07-29 09:02:15,731 [org.hibernate.SQL 109 logStatement DEBUG]: select orderadjus0_.id as id1_31_, orderadjus0_.adjustment_reason as adjustme2_31_, orderadjus0_.adjustment_type as adjustme3_31_, orderadjus0_.approved_by as approved4_31_, orderadjus0_.created_by as created_5_31_, orderadjus0_.date_created as date_cre6_31_, orderadjus0_.last_updated as last_upd7_31_, orderadjus0_.note as note8_31_, orderadjus0_.order_id as order_id9_31_, orderadjus0_.source_of_error as source_10_31_, orderadjus0_.updated_by as updated11_31_, orderadjus0_.work_request as work_re12_31_ from order_adjustment orderadjus0_ where order_id=?
    2017-07-29 09:02:15,735 [hibernate.loader.Loader 1486 getRow DEBUG]: Result row: EntityKey[commerce.order.OrderAdjustment#5855]
    2017-07-29 09:02:15,744 [engine.internal.TwoPhaseLoad 160 doInitializeEntity DEBUG]: Resolving associations for [order.OrderAdjustment#5855]
    2017-07-29 09:02:15,833 [engine.spi.ActionQueue 196 addResolvedEntityInsertAction DEBUG]: Executing identity-insert immediately
    2017-07-29 09:02:15,833 [org.hibernate.SQL 109 logStatement DEBUG]: insert into order_adjustment (adjustment_reason, adjustment_type, approved_by, created_by, date_created, last_updated, note, order_id, source_of_error, updated_by, work_request) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    Hibernate: insert into order_adjustment (adjustment_reason, adjustment_type, approved_by, created_by, date_created, last_updated, note, order_id, source_of_error, updated_by, work_request) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    2017-07-29 09:02:15,835 [hibernate.id.IdentifierGeneratorHelper 94 getGeneratedIdentity DEBUG]: Natively generated identity: 5867
    2017-07-29 09:02:15,836 [transaction.spi.AbstractTransactionImpl 175 commit DEBUG]: committing
    2017-07-29 09:02:15,836 [event.internal.AbstractFlushingEventListener 149 prepareEntityFlushes DEBUG]: Processing flush-time cascades
    2017-07-29 09:02:15,836 [event.internal.AbstractFlushingEventListener 189 prepareCollectionFlushes DEBUG]: Dirty checking collections
    2017-07-29 09:02:15,840 [event.internal.AbstractFlushingEventListener 123 logFlushResults DEBUG]: Flushed: 0 insertions, 1 updates, 0 deletions to 2 objects
    2017-07-29 09:02:15,840 [event.internal.AbstractFlushingEventListener 130 logFlushResults DEBUG]: Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
    2017-07-29 09:02:15,841 [internal.util.EntityPrinter 114 toString DEBUG]: Listing entities:
    2017-07-29 09:02:15,841 [internal.util.EntityPrinter 121 toString DEBUG]: commerce.order.OrderAdjustment{sourceOfError=test, lastUpdated=2017-07-29 13:02:15, note=test, adjustmentReason=test, dateCreated=2017-07-29 13:02:15, updatedBy=test, createdBy=test, orderId=12345, adjustmentType=ADJUSTMENT, approvedBy=test, id=5867, workRequest=test}
    2017-07-29 09:02:15,848 [org.hibernate.SQL 109 logStatement DEBUG]: update order_adjustment set adjustment_reason=?, adjustment_type=?, approved_by=?, created_by=?, date_created=?, last_updated=?, note=?, order_id=?, source_of_error=?, updated_by=?, work_request=? where id=?
    Hibernate: update order_adjustment set adjustment_reason=?, adjustment_type=?, approved_by=?, created_by=?, date_created=?, last_updated=?, note=?, order_id=?, source_of_error=?, updated_by=?, work_request=? where id=?
    2017-07-29 09:02:15,875 [internal.jdbc.JdbcTransaction 113 doCommit DEBUG]: committed JDBC Connection
    2017-07-29 09:02:15,876 [internal.jdbc.JdbcTransaction 126 releaseManagedConnection DEBUG]: re-enabling autocommit
    2017-07-29 09:02:15,876 [jdbc.internal.JdbcCoordinatorImpl 201 close DEBUG]: HHH000420: Closing un-released batch
    2017-07-29 09:02:15,877 [jdbc.internal.LogicalConnectionImpl 246 releaseConnection DEBUG]: Releasing JDBC connection
    2017-07-29 09:02:15,878 [jdbc.internal.LogicalConnectionImpl 264 releaseConnection DEBUG]: Released JDBC connection

以下是使用Spring Data JPA @Transactional

的日志
    +++++++++++++++++saving using adjustmentPersister
    2017-07-29 10:09:54,629 [orm.jpa.JpaTransactionManager 128 debug DEBUG]: Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findByOrderId]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; 'commerceDataApiTM'
    2017-07-29 10:09:54,630 [orm.jpa.JpaTransactionManager 128 debug DEBUG]: Opened new EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@23e135ac] for JPA transaction
    2017-07-29 10:09:54,630 [transaction.spi.AbstractTransactionImpl 160 begin DEBUG]: begin
    2017-07-29 10:09:54,630 [jdbc.internal.LogicalConnectionImpl 226 obtainConnection DEBUG]: Obtaining JDBC connection
    2017-07-29 10:09:54,631 [jdbc.internal.LogicalConnectionImpl 232 obtainConnection DEBUG]: Obtained JDBC connection
    2017-07-29 10:09:54,631 [internal.jdbc.JdbcTransaction 69 doBegin DEBUG]: initial autocommit status: true
    2017-07-29 10:09:54,631 [internal.jdbc.JdbcTransaction 71 doBegin DEBUG]: disabling autocommit
    2017-07-29 10:09:54,632 [orm.jpa.JpaTransactionManager 128 debug DEBUG]: Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@4c01db8d]
    2017-07-29 10:09:54,633 [jpa.criteria.CriteriaQueryImpl 327 interpret DEBUG]: Rendered criteria query -> select generatedAlias0 from Adjustment as generatedAlias0 where generatedAlias0.orderId=:param0
    2017-07-29 10:09:54,633 [org.hibernate.SQL 109 logStatement DEBUG]: select adjustment0_.id as id1_3_, adjustment0_.adjustment_reason as adjustme2_3_, adjustment0_.adjustment_type as adjustme3_3_, adjustment0_.approved_by as approved4_3_, adjustment0_.created_by as created_5_3_, adjustment0_.date_created as date_cre6_3_, adjustment0_.last_updated as last_upd7_3_, adjustment0_.note as note8_3_, adjustment0_.order_id as order_id9_3_, adjustment0_.source_of_error as source_10_3_, adjustment0_.updated_by as updated11_3_, adjustment0_.work_request as work_re12_3_ from dbo.order_adjustment adjustment0_ where adjustment0_.order_id=?
    2017-07-29 10:09:54,636 [orm.jpa.JpaTransactionManager 128 debug DEBUG]: Initiating transaction commit
    2017-07-29 10:09:54,636 [orm.jpa.JpaTransactionManager 128 debug DEBUG]: Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@23e135ac]
    2017-07-29 10:09:54,636 [transaction.spi.AbstractTransactionImpl 175 commit DEBUG]: committing
    2017-07-29 10:09:54,637 [internal.jdbc.JdbcTransaction 113 doCommit DEBUG]: committed JDBC Connection
    2017-07-29 10:09:54,637 [internal.jdbc.JdbcTransaction 126 releaseManagedConnection DEBUG]: re-enabling autocommit
    2017-07-29 10:09:54,638 [orm.jpa.JpaTransactionManager 128 debug DEBUG]: Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@23e135ac] after transaction
    2017-07-29 10:09:54,638 [orm.jpa.EntityManagerFactoryUtils 128 debug DEBUG]: Closing JPA EntityManager
    2017-07-29 10:09:54,638 [jdbc.internal.LogicalConnectionImpl 246 releaseConnection DEBUG]: Releasing JDBC connection
    2017-07-29 10:09:54,639 [jdbc.internal.LogicalConnectionImpl 264 releaseConnection DEBUG]: Released JDBC connection
    2017-07-29 10:09:54,732 [core.support.TransactionalRepositoryProxyPostProcessor$CustomAnnotationTransactionAttributeSource 351 getTransactionAttribute DEBUG]: Adding transactional method 'save' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
    2017-07-29 10:09:54,733 [orm.jpa.JpaTransactionManager 128 debug DEBUG]: Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
    2017-07-29 10:09:54,733 [orm.jpa.JpaTransactionManager 128 debug DEBUG]: Opened new EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@98f9e0b] for JPA transaction
    2017-07-29 10:09:54,734 [transaction.spi.AbstractTransactionImpl 160 begin DEBUG]: begin
    2017-07-29 10:09:54,734 [jdbc.internal.LogicalConnectionImpl 226 obtainConnection DEBUG]: Obtaining JDBC connection
    2017-07-29 10:09:54,734 [jdbc.internal.LogicalConnectionImpl 232 obtainConnection DEBUG]: Obtained JDBC connection
    2017-07-29 10:09:54,735 [internal.jdbc.JdbcTransaction 69 doBegin DEBUG]: initial autocommit status: true
    2017-07-29 10:09:54,735 [internal.jdbc.JdbcTransaction 71 doBegin DEBUG]: disabling autocommit
    2017-07-29 10:09:54,736 [orm.jpa.JpaTransactionManager 128 debug DEBUG]: Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@462d18ae]
    2017-07-29 10:09:54,740 [engine.spi.ActionQueue 196 addResolvedEntityInsertAction DEBUG]: Executing identity-insert immediately
    2017-07-29 10:09:54,741 [org.hibernate.SQL 109 logStatement DEBUG]: insert into dbo.order_adjustment (adjustment_reason, adjustment_type, approved_by, created_by, date_created, last_updated, note, order_id, source_of_error, updated_by, work_request) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) select scope_identity()
    2017-07-29 10:09:54,744 [hibernate.id.IdentifierGeneratorHelper 94 getGeneratedIdentity DEBUG]: Natively generated identity: 5869
    2017-07-29 10:09:54,744 [orm.jpa.JpaTransactionManager 128 debug DEBUG]: Initiating transaction commit
    2017-07-29 10:09:54,745 [orm.jpa.JpaTransactionManager 128 debug DEBUG]: Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@98f9e0b]
    2017-07-29 10:09:54,745 [transaction.spi.AbstractTransactionImpl 175 commit DEBUG]: committing
    2017-07-29 10:09:54,745 [event.internal.AbstractFlushingEventListener 149 prepareEntityFlushes DEBUG]: Processing flush-time cascades
    2017-07-29 10:09:54,745 [event.internal.AbstractFlushingEventListener 189 prepareCollectionFlushes DEBUG]: Dirty checking collections
    2017-07-29 10:09:54,746 [event.internal.AbstractFlushingEventListener 123 logFlushResults DEBUG]: Flushed: 0 insertions, 0 updates, 0 deletions to 1 objects
    2017-07-29 10:09:54,746 [event.internal.AbstractFlushingEventListener 130 logFlushResults DEBUG]: Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
    2017-07-29 10:09:54,746 [internal.util.EntityPrinter 114 toString DEBUG]: Listing entities:
    2017-07-29 10:09:54,747 [internal.util.EntityPrinter 121 toString DEBUG]: commerce.data.model.Adjustment{sourceOfError=SYSTEM, lastUpdated=2017-07-29 14:09:54, note=test, adjustmentReason=TAX_IN_ERROR, dateCreated=2017-07-29 14:09:54, updatedBy=soubhrad, createdBy=soubhrad, orderId=10679446, adjustmentType=ADJUSTMENT, approvedBy=test, id=5869, workRequest=test}
    2017-07-29 10:09:54,751 [internal.jdbc.JdbcTransaction 113 doCommit DEBUG]: committed JDBC Connection
    2017-07-29 10:09:54,752 [internal.jdbc.JdbcTransaction 126 releaseManagedConnection DEBUG]: re-enabling autocommit
    2017-07-29 10:09:54,753 [orm.jpa.JpaTransactionManager 128 debug DEBUG]: Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@98f9e0b] after transaction
    2017-07-29 10:09:54,753 [orm.jpa.EntityManagerFactoryUtils 128 debug DEBUG]: Closing JPA EntityManager
    2017-07-29 10:09:54,754 [jdbc.internal.LogicalConnectionImpl 246 releaseConnection DEBUG]: Releasing JDBC connection
    2017-07-29 10:09:54,754 [jdbc.internal.LogicalConnectionImpl 264 releaseConnection DEBUG]: Released JDBC connection

这是现有的代码 - 基于Hibernate的Dao -

public class AdjustmentDao extends BaseHibernateDao {
  public List<Adjustment> findByOrderId(Integer orderId) {
  try {
    String queryString = "from OrderAdjustment o where order_id = :orderId ";
    Query query = getSession().createQuery(queryString);
    query.setParameter("orderId", orderId);
    @SuppressWarnings("unchecked")
    List<Adjustment> adjustments = query.list();
    return adjustments;
  } catch (HibernateException ex) {
    String msg = "Exception finding Adjustment for order id:" + orderId;
    LOG.error(msg, ex);
    throw new CommerceRuntimeException(msg, ex);
  }
}

public void saveAdjustments(Collection<Adjustment> adjustments) {
  try {
    save(adjustments);
  } catch (HibernateException ex) {
    Integer orderId = findOrderId(adjustments);
    String msg = "Exception saving Adjustments for order id:" + orderId;
    LOG.error(msg, ex);
    throw new CommerceRuntimeException(msg, ex);
  }
}
}

BaseHibernateDao -

public class BaseHibernateDao {

  private Transaction transaction;

  public void closeSession() {
    HibernateSessionFactory.closeSession();
  }

  public void beginTransaction() {
      if(this.transaction != null && this.transaction.isActive()) {
      return;
    }
    if(getSession().getTransaction() != null && 
getSession().getTransaction().isActive()) {
      setTransaction(getSession().getTransaction());
    } else {      
      setTransaction(getSession().beginTransaction());     
    }    
  }

    protected void save(Collection<? extends Object> transientInstances) throws HibernateException {
    if (getTransaction() == null) {
      throw new IllegalArgumentException("Transaction is null");
    }
    try {
      for (Object transientInstance : transientInstances) {
        getSession().save(transientInstance);
      }
      getTransaction().commit();
    } catch (HibernateException ex) {
      rollbackTransaction();
      throw ex;
    }
  }
}

HIbernateSessionFactory -

    public class HibernateSessionFactory {

      /**
       * Location of hibernate.cfg.xml file. Location should be on the classpath as Hibernate uses #resourceAsStream style 
       * lookup for its configuration file. The default classpath location of the hibernate config file is in the default 
       * package. Use #setConfigFile() to update the location of the configuration file for the current session.
       */
      private static String CONFIG_FILE_LOCATION = "/config/hibernate.cfg.xml";
      private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
      private static Configuration configuration = new Configuration();
      private static SessionFactory sessionFactory;
      private static String configFile = CONFIG_FILE_LOCATION;
      private static final Logger LOG = LoggerFactory.getLogger(HibernateSessionFactory.class);

      static {
        try {
          configuration.configure(configFile);
          sessionFactory = configuration.buildSessionFactory();
        } catch (Exception e) {
          LOG.error("%%%% Error Creating SessionFactory %%%%", e);
        }
      }

      private HibernateSessionFactory() {
      }

      /**
       * Returns the ThreadLocal Session instance. Lazy initialize the <code>SessionFactory</code> if needed.
       * @return Session
       * @throws HibernateException
       */
      public static Session getSession() throws HibernateException {
        Session session = threadLocal.get();
        if (session == null || !session.isOpen()) {
          if (sessionFactory == null) {
            rebuildSessionFactory();
          }
          session = (sessionFactory != null) ? sessionFactory.openSession() : null;
          threadLocal.set(session);
        }
        return session;
      }

      /**
       * Close the single hibernate session instance.
       * @throws HibernateException
       */
      public static void closeSession() throws HibernateException {
        Session session = threadLocal.get();
        threadLocal.set(null);
        if (session != null) {
          session.close();
        }
      }
    }

最后在应用程序中使用DAO(它是一个grails应用程序) -     class OrderUpdateService {

  static scope = "request"
  AdjustmentDao adjustmentDao = new AdjustmentDao()

  void transformAndSaveAdjustments(Integer orderId, def orderParams, User user) {
  System.out.println("******************transformAndSaveAdjustments")
  def adjustParams = orderParams.adjustments
  if (adjustParams && !adjustParams.isEmpty()) {
    adjustmentDao.getSession()
    adjustmentDao.beginTransaction()
    Collection<Adjustment> adjusts = adjustmentDao.findByOrderId(orderId)
    ParametersToAdjustmentTransformer xform = new ParametersToAdjustmentTransformer()
    Collection<Adjustment> adjustToSave = xform.transformAdjustmentData(adjusts, adjustParams, user, orderId)
    adjustmentDao.saveAdjustments(adjustToSave)
    adjustmentDao.closeSession()
} 

}

观察会话和事务的打开方式,并在同一个打开的会话和事务中查找和保存对DAO的调用。这就是现在(也可能不是最好的方法)。

现在新代码Spring Data JPA @Transactional -

@Transactional(value="commerceDataApiTM", propagation=Propagation.REQUIRED)
public interface AdjustmentRepository extends JpaRepository<Adjustment, Integer> {

  List<Adjustment> findByOrderId(Integer orderId);

}

    @Component
    @Transactional(value="commerceDataApiTM", propagation=Propagation.REQUIRED)
    public class AdjustmentPersister {

      private static final Logger LOG = LoggerFactory.getLogger(AdjustmentPersister.class);

      @Autowired
      private AdjustmentRepository adjustmentRepository;

      public List<Adjustment> findByOrderId(Integer orderId) {
        return adjustmentRepository.findByOrderId(orderId);
      }

      public void save(Adjustment adjustment) {
        adjustmentRepository.save(adjustment);
      }

      public void save(List<Adjustment> adjustments) {
        LOG.info("saving through new AdjustmentPersister.save()");
        adjustmentRepository.save(adjustments);
      }
    }

调用应用程序代码 -

      @Transactional("commerceDataApiTM")
      void transformAndSaveAdjustments(Integer orderId, def orderParams, User user) {
        System.out.println("+++++++++++++++++saving using adjustmentPersister")
        def adjustParams = orderParams.adjustments
        if (adjustParams && !adjustParams.isEmpty()) {
          List<Adjustment> adjusts = adjustmentPersister.findByOrderId(orderId)
          ParametersToAdjustmentTransformer xform = new ParametersToAdjustmentTransformer()
          List<Adjustment> adjustToSave = xform.transformAdjustmentData(adjusts, adjustParams, user, orderId)
          adjustmentPersister.save(adjustToSave)
        } 
      }

0 个答案:

没有答案