Несколько разделенных баз данных Hibernate Transactions

У меня есть служба tomcat на основе весны. Я использую сопоставление спящего режима на основе аннотаций, и у меня есть несколько сегментированных баз данных. Все сегментированные базы данных имеют одинаковые таблицы, скажем, Student. Я хочу реализовать на них транзакцию, используя аннотацию @Transactional.

@Autowired
List<SessionFactory> sessionFactoryList;

@Transactional
public insertStudentBatch(List<Student> students) {

}

Теперь я хочу вставить всю партию. Если произойдет какая-либо ошибка, я хочу, чтобы все они откатились. Как лучше всего это сделать? Могу ли я написать несколько квалификаторов TransactionManager, например @Transactional("txManager1", "txManager2")?


person Amit    schedule 11.12.2015    source источник
comment
Почему бы вам не попробовать вместо того, чтобы спросить, можете ли вы попробовать?   -  person innoSPG    schedule 11.12.2015
comment
Это не работает. Я спрашиваю, могу ли я настроить его так или иначе, чтобы он работал. Когда я пытаюсь вставить в 2 БД с помощью @Transactional, он вставляется только в один из них.   -  person Amit    schedule 11.12.2015


Ответы (1)


Нет, к сожалению, аннотация spring @Transactional относится к одному диспетчеру транзакций и не ведет себя так, как вы описали.

Мне кажется, что вам, скорее всего, нужна транзакция JTA для фиксации 2PC, где вы в основном запускаете главную транзакцию 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);
   }
 }

Могут быть некоторые другие способы справиться с этим без настройки фиксации 2PC с JTA, но обычно в транзакциях, управляемых контейнером (например, JBoss, WebLogic и т. д.); это будет подход.

В качестве дополнительной панели, если вы уже на весеннем пути, я могу предложить вам проверить spring-batch. Он обеспечивает достойную основу для пакетных операций для множества вариантов использования. То, что я описал выше, представляет собой грубую реализацию одного случая внутри spring-batch.

ОБНОВЛЕНИЕ

Если вы хотите избежать необходимости создавать несколько реализаций классов сегментов с подробностями аннотаций, вы можете прибегнуть к конфигурации XML и иметь реализацию одного класса:

 <bean id="shard1" class="default.ShardStudentServiceImpl">
   <property name="entityManager" ref="shard1EntityManager" />
   <property name="transactionManager" ref="shard1TransactionManager" />
 </bean>

Единственная разница здесь в том, что вы должны определить свои 25 осколков в XML, а затем вам нужно написать свой собственный код для запуска, фиксации и управления транзакцией внутри вашего класса ShardStudentServiceImpl.

Используя абстрактный базовый класс в сочетании с аннотациями в окончательных реализациях, показанных выше, мое обновление достигает того же места назначения. На самом деле, если вы посмотрите на spring-batch, вы заметите, что их пакетная конфигурация следует аналогичной предпосылке с указанием менеджера сущностей и менеджеров транзакций в качестве входных свойств для одного класса.

person Naros    schedule 11.12.2015
comment
Что означает - // Each instance here has their own EntityManager/SessionFactory/PersistenceContext ? Если у меня 25 баз данных, нужно ли мне реализовывать их 25 раз? Не могли бы вы сделать это немного яснее? - person Amit; 11.12.2015
comment
Да, у вас будет несколько реализаций AbstractStudentServiceImpl, поскольку каждая реализованная служба описывает контракт между экземпляром контекста сохраняемости и конкретным экземпляром диспетчера транзакций. Смотрите мое обновление. - person Naros; 11.12.2015