如何从其他服务的其他@Transactional方法中的一个服务调用@Transactional方法

时间:2014-05-13 21:23:05

标签: spring transactions spring-transactions

我有:

1)服务:

@Service("scanner")
@Transactional
public class Scanner
{
    @Inject
    AnalyzerService analyzerService;

    @Transactional
    private void scan() {
        analyzerService.analyze();
    }
}

2)服务:

@Service
public class AnalyzerService
{
    @Inject
    AnalyzerDao analyzerDao;

    @Transactional
    public void analyze() {
        List<AnalyzerResult> items;
        // code filling items list removed;
        save(items); 
    }

    @Transactional
    private void save(List<SomeType> items) {
        analyzerDao.save(items); // <--- Why after call save items are not saved in DB?
    }
}

3)道:

@Repository
public class AnalyzerDao extends GenericDaoImpl<AnalyzerResult>
{
    //all needed methods for find, edit, delete and save which works fine in other cases.
}

问题:

为什么在调用analzyerDao.save(items) DB后仍然为空?交易有问题怎么样? 当我在行flush()之后调用getSession().getTransaction().commit()方法和analyzerDao.save(items)时,会出现在数据库中的记录但是会抛出异常:

Caused by: org.springframework.transaction.TransactionSystemException: Could not commit Hibernate transaction; nested exception is org.hibernate.TransactionException: Transaction not successfully started
    at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:660)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at com.sun.proxy.$Proxy44.execute(Unknown Source)
    at org.quartz.core.JobRunShell.run(JobRunShell.java:223)
    ... 1 more
Caused by: org.hibernate.TransactionException: Transaction not successfully started
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:127)
    at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
    ... 9 more

如何实施工作&#39;保存&#39;方法好吗? 我应该怎么做才能在第一次交易完成后不仅仅在第一次交易完成后保存项目?(

2 个答案:

答案 0 :(得分:1)

在提交事务之前,数据不会出现在数据库中。对于@Transactional方法,事务由Spring 方法返回后提交。

顺便说一下,@Transactional对私有方法没有影响,因此Scanner.scan()根本不是事务性的。

答案 1 :(得分:1)

您需要的是一个新的交易,只是为了节省您需要保存的内容。您可以通过将propagation @Transactional注释配置为REQUIRES_NEW来实现此目的。

不幸的是你的情况有点棘手,因为当你执行this时你在save(items);上下文中调用一个方法,这意味着事务拦截器不会拦截这样的调用,因此你有可能将服务注入到一个字段保持自己并在注入的服务上调用它而不是强制调用该方法被事务拦截器拦截,请尝试以下实现:

@Service
public class DefaultAnalyzerService implements AnalyzerService {
    @Inject
    AnalyzerDao analyzerDao;
    @Inject
    AnalyzerService analyserService;

    @Transactional
    @Override
    public void analyze() {
        List<AnalyzerResult> items;
        // code filling items list removed;
        analyserService.save(items); 
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void save(List<SomeType> items) {
        analyzerDao.save(items); // <--- Why after call save items are not saved in DB?
    }

}

另一个改变的是save(List<SomeType> items)的可见性,现在是公开的,以便被事务拦截器拦截并提取接口。由于弹簧的限制,这是必需的,但您可以使用AspectJ来处理这种拦截器,因此请查看here