不,不幸的是,spring@Transactional
注释特定于单个事务管理器,并且不符合您描述的愿望。
在我看来,您可能想要的是一个用于 2PC 提交的 JTA 事务,您基本上启动一个主 JTA 事务,然后对于每个SessionFactory
,您为您的分片调用每个特定的事务管理器并执行您的操作。
@Service
public class StudentBatchServiceImpl implements StudentBatchService {
@Autowired List<StudentService> studentServices;
@Transactional(value = "jtaTransactionManager")
public void storeStudents(List<Student> students) {
for(StudentService service : studentServices)
service.storeStudents(students);
}
}
public interface StudentService {
void storeStudents(List<Student> students);
}
public abstract AbstractStudentServiceImpl implements StudentService {
protected void storeStudents(EntityManager em, List<Student> students) {
for(Student student : students) {
em.persist(student);
}
}
}
@Service
public class Shard1StudentServiceImpl extends AbstractStudentServiceImpl {
@PersistenceContext(name = "shard1")
private EntityManager entityManager;
@Override
@Transactional(value = "shard1TransactionManager")
public void storeStudents(List<Student> students) {
storeStudents(entityManager, students);
}
}
可能有一些其他方法可以在没有 JTA 的 2PC 提交设置的情况下处理此问题,但通常在容器管理的事务中(如 JBoss、WebLogic 等);这就是方法。
作为一个侧栏,如果你已经走上了春天的道路,我可能会建议你去看看spring-batch
。它为大量用例的批处理操作提供了一个不错的基线。我上面描述的是对一个 case inside 的穷人实现spring-batch
。
更新
如果您想避免使用注释详细信息创建多个分片类实现,您可以求助于 XML 配置并拥有一个类实现:
<bean id="shard1" class="default.ShardStudentServiceImpl">
<property name="entityManager" ref="shard1EntityManager" />
<property name="transactionManager" ref="shard1TransactionManager" />
</bean>
这里唯一的区别是您必须在 XML 中定义 25 个分片,然后您必须编写自己的代码来启动、提交和管理ShardStudentServiceImpl
类中的事务。
将抽象基类与上面显示的最终实现中的注释结合使用,我的更新到达了相同的目的地。实际上,如果您查看spring-batch
,您会注意到它们的批处理配置遵循类似的前提,将实体管理器和事务管理器指定为单个类的输入属性。