休眠 Spring @Transaction 不起作用

Hibernate Spring @Transaction doesn't work

我有以下内容:

@Service
public class AsyncMarketService {

    @Inject
    IdentifierManager identifierManager;

    @Transactional
    public void getProducts() {
        identifierManager.getTitleForIdentifier();
      }
}

正在从 @Async 方法调用服务方法。

我在日志中看到交易正在打开:

134331 DEBUG [Company-1] org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'transactionManager'
134342 DEBUG [Company-1] org.springframework.orm.hibernate4.HibernateTransactionManager - Creating new transaction with name [com.estartup.caller.AsyncMarketService.getProducts]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
134343 DEBUG [Company-1] org.springframework.orm.hibernate4.HibernateTransactionManager - Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@b9b0793 updates=org.hibernate.engine.spi.ExecutableList@ee6c9e deletions=org.hibernate.engine.spi.ExecutableList@4230dd40 orphanRemovals=org.hibernate.engine.spi.ExecutableList@5d5e00b collectionCreations=org.hibernate.engine.spi.ExecutableList@56a1c8bd collectionRemovals=org.hibernate.engine.spi.ExecutableList@25d8d46b collectionUpdates=org.hibernate.engine.spi.ExecutableList@61c6c74d collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@4b39a6c6 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
134346 DEBUG [Company-1] org.springframework.orm.hibernate4.HibernateTransactionManager - Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@b9b0793 updates=org.hibernate.engine.spi.ExecutableList@ee6c9e deletions=org.hibernate.engine.spi.ExecutableList@4230dd40 orphanRemovals=org.hibernate.engine.spi.ExecutableList@5d5e00b collectionCreations=org.hibernate.engine.spi.ExecutableList@56a1c8bd collectionRemovals=org.hibernate.engine.spi.ExecutableList@25d8d46b collectionUpdates=org.hibernate.engine.spi.ExecutableList@61c6c74d collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@4b39a6c6 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
134346 DEBUG [Company-1] org.springframework.jdbc.datasource.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:mysql://localhost:3306/Company?zeroDateTimeBehavior=convertToNull]
134377 DEBUG [Company-1] org.springframework.orm.hibernate4.HibernateTransactionManager - Exposing Hibernate transaction as JDBC transaction [com.mysql.jdbc.JDBC4Connection@4d9068ae]

但是,我仍然得到一个错误:

Caused by: java.util.concurrent.ExecutionException: org.hibernate.HibernateException: get is not valid without active transaction
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)

当我尝试从该方法 (identifierManager.getTitleForIdentifier();) 调用 DAO 以通过 id 检索某些内容时。

怎么了?

已编辑

配置 Bean:

@Configuration
@ComponentScan({ "com.estartup" })
@PropertySource("classpath:jdbc.properties")
@EnableScheduling
@EnableTransactionManagement
public class PersistenceConfig {

    @Autowired
    Environment env;

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource(env.getProperty("connection.url"), env.getProperty("connection.username"),
                env.getProperty("connection.password"));
        driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        return driverManagerDataSource;
    }

    public PersistenceConfig() {
        super();
    }

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean factoryBean = null;
        try {
            factoryBean = createBaseSessionFactory();
            factoryBean.getHibernateProperties().setProperty("hibernate.current_session_context_class", "thread");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return factoryBean;
    }

    private LocalSessionFactoryBean createBaseSessionFactory() throws IOException {
        LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
        Properties pp = new Properties();
        pp.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
        pp.setProperty("hibernate.max_fetch_depth", "3");
        pp.setProperty("hibernate.current_session_context_class", "org.springframework.orm.hibernate4.SpringSessionContext");
        factoryBean.setDataSource(dataSource());
        factoryBean.setPackagesToScan(new String[] { "com.estartup.*" });
        factoryBean.setHibernateProperties(pp);
        return factoryBean;
    }

    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
        HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(sessionFactory);
        return txManager;
    }
}

您可以尝试的一件事是删除 @Transactional 注释并自己手动打开一个会话(不确定是否有更好的方法...)

@Service
public class AsyncMarketService {

    @Inject
    IdentifierManager identifierManager;

    @Inject
    SessionFactory sessionFactory;

    public void getProducts() {
        Session session = sessionFactory.openSession();
        Transaction tx = null;

        try {
            identifierManager.getTitleForIdentifier();
        } catch(Exception e) {
            if(tx != null) tx.rollback();
        } finally {
            session.close();
        }
    }
}

如果您发现自己不止一次这样做,也许可以编写另一个组件,其中包含一个采用闭包或其他方法的方法。

如果我在接下来的几分钟内找到更优雅的方式,我会及时通知您。

尝试将@Transactional 移动到调用异步方法。事务不会通过调用层次结构从一个 Spring 组件传播到另一个组件,因为异步方法正在由任务执行程序安排并在稍后时间执行。