【问题标题】:Hibernate Transaction Manager - Java configurationHibernate 事务管理器 - Java 配置
【发布时间】:2013-02-15 19:15:21
【问题描述】:

一段时间以来,我一直在努力解决这个问题。我创建了以下数据访问对象:

public interface GenericDAO<T, ID extends Serializable> {
  T findById(ID id);
  List<T> findAll();
  T save(T entity);
  void update(T entity);
  void delete(T entity);
}

public class GenericHibernateDAO<T, ID extends Serializable> implements GenericDAO<T, ID> {

  private final Class<T> persistentClass;
  private final SessionFactory sessionFactory;

  public GenericHibernateDAO(final SessionFactory sessionFactory) {
    this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    this.sessionFactory = sessionFactory;
  }

  protected Session getSession() {
    return sessionFactory.getCurrentSession();
  }

  public Class<T> getPersistentClass() {
    return persistentClass;
  }

  @Override
  public T findById(final ID id) {
    return (T) getSession().load(getPersistentClass(), id);
  }

  @Override @SuppressWarnings("unchecked")
  public List<T> findAll() {
    return findByCriteria();
  }

  protected List<T> findByCriteria(final Criterion... criterion) {
    final Criteria crit = getSession().createCriteria(getPersistentClass());
    for (final Criterion c : criterion) {
      crit.add(c);
    }
    return crit.list();
  }

  @Override
  public T save(final T entity) {
    getSession().saveOrUpdate(entity);
    return entity;
  }

  @Override
  public void delete(final T entity) {
    getSession().delete(entity);
  }

  @Override
  public void update(final T entity) {
    getSession().saveOrUpdate(entity);
  }
}

@Repository
public class StockHibernateDAO extends GenericHibernateDAO<Stock, String> implements StockDAO {

  @Inject
  public StockHibernateDAO(final SessionFactory sessionFactory) {
    super(sessionFactory);
  }
}

我正在尝试使用 Java 配置进行设置,所以这是我设置服务层的配置:

@Configuration @Profile("hibernate")
@EnableCaching @EnableTransactionManagement
@ComponentScan("reference.dao.hibernate")
public class HibernateServiceConfig implements TransactionManagementConfigurer {

  @Inject private StockDAO stockDao; //No extra methods, just the base stuff for now

  @Bean(destroyMethod = "shutdown")
  public DataSource dataSource() {
    return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL).addScript("classpath:schema.sql").build();
  }

  @Bean
  public SessionFactory sessionFactory() {
    return new LocalSessionFactoryBuilder(dataSource()).addAnnotatedClasses(Stock.class)
    .setProperty("hibernate.show_sql", "true")
    .setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory")
    .setProperty("hibernate.cache.use_query_cache", "true")
    .setProperty("hibernate.cache.use_second_level_cache", "true")
    .setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect").buildSessionFactory();
  }

  @Override @Bean
  public PlatformTransactionManager annotationDrivenTransactionManager() {
    return new HibernateTransactionManager(sessionFactory());
  }

}

这里是交易服务:

@Service
public class TradingServiceImpl implements TradingService {    
  @Inject private StockDAO stockDAO;

  @Override @Transactional
  @CachePut(value = "stockCache", key = "#stock.name")
  public Stock addNewStock(final Stock stock) {
    stockDAO.save(stock);
    return stock;
  }

  @Override @Cacheable(value = "stockCache")
  public Stock getStock(final String stockName) {
    return stockDAO.findById(stockName);
  }

  @Override @CacheEvict(value = "stockCache", key = "#stock.name")
  public void removeStock(final Stock stock) {
    stockDAO.delete(stock);
  }

  @Override @CacheEvict(value = "stockCache", key = "#stock.name")
  public void updateStock(final Stock stock) {
    stockDAO.update(stock);
  }

  @Override
  public List<Stock> getAll() {
    return stockDAO.findAll();
  }
}

只有在我将 session.flush() 添加到 save 方法时,股票的保存似乎才完成。我理解事物的方式,在服务层方法周围使用 TransactionManager 和 @Transactional 实际上应该会导致为我进行调用。这个配置缺少什么?

【问题讨论】:

  • 删除 @Inject StockDao 并使用 @Repository 注释该类或其实现。

标签: java spring hibernate spring-transactions


【解决方案1】:

因为你正在注入一个Session

  @Bean
  public Session session() {
    return sessionFactory().openSession();
  }

Spring 不能围绕它添加它的事务行为。让 Spring 打开会话并完成它的业务。

不是注入Session,而是注入SessionFactory。在您的 DAO 中,保留 SessionFactory 的属性并使用 sessionFactory.getCurrentSession() 获取会话。

当 Spring 看到 @Transactional 时,它会得到 SessionFactory,调用 openSession(),开始一个事务,然后调用你的方法。当您的方法成功返回时,它将关闭该事务。

您还应该@Autowired 服务类中的 dao。

【讨论】:

  • 只有当我的 DAO 被划分为 @Transactional 时才有效(即 getCurrentSession() 仅在事务中才有意义)?就目前而言,我想用事务标记我的服务层,而不是我的 DAO 层。
  • 无论谁拥有@Transactional,默认情况下,方法调用中的任何内容都将使用相同的会话和事务。
  • 那么有些事情还是不太对劲,因为我收到了以下堆栈: org.hibernate.HibernateException: No Session found for current thread at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext .java:97) 在 org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:978) 在 reference.dao.hibernate.GenericHibernateDAO.getSession(GenericHibernateDAO.java:25)
  • 而不是将它们放在 Configuration 类中,只需将您的 Dao 和 Service 实现分别注释为 @Repository@Service
猜你喜欢
  • 2017-07-30
  • 2011-07-05
  • 1970-01-01
  • 1970-01-01
  • 2010-11-13
  • 2017-02-05
  • 1970-01-01
  • 1970-01-01
  • 2010-10-18
相关资源
最近更新 更多