Использование несериализуемых объектов в Activiti BPMN

Я хочу использовать процесс Activiti BPMN для некоторой задачи обновления базы данных. Мой процесс выглядит следующим образом.

Начальное событие-> Сервисная задача 1 -> Сервисная задача 2 -> Сервисная задача 3 -> Конечное событие

В классе реализации службы задачи обслуживания 1: я создал java.sql.Connection для базы данных MySQL. Мне нужно передать один и тот же объект подключения в служебную задачу 2 и служебную задачу 3. Обычно эти два класса будут выполнять некоторые вставки для базы данных, используя один и тот же объект подключения.

Я пробовал следующее (dbConn - это класс, который содержит java.sql.Connection type dbConnection)

execution.setVariable("DBConn",dbConn); 

Но это дает исключение, поскольку объект подключения не сериализуем.

"org.activiti.engine.ActivitiException: Couldn't serialize value" 

Итак, как лучше всего передавать такие несериализуемые переменные между служебными задачами процесса? Или есть ли способ определить такие общие объекты для нескольких задач службы в одном месте и использовать их в задачах службы (что-то вроде глобальных переменных для процесса)


person Anupama Pathirage    schedule 31.01.2016    source источник
comment
Есть ли какая-то конкретная причина, по которой вы хотите передать один и тот же объект подключения?   -  person Younes Regaieg    schedule 31.01.2016
comment
Я хочу использовать это же соединение для задач вставки в служебной задаче 2 и служебной задаче 3. Соединение с БД создается с помощью setAutoCommit (false). Итак, после выполнения служебной задачи 3 я хочу зафиксировать транзакцию   -  person Anupama Pathirage    schedule 31.01.2016
comment
Что произойдет, если по какой-то неожиданной причине сервер откажется и вам придется его перезапустить?   -  person Younes Regaieg    schedule 31.01.2016
comment
Что ж, это будет проблемой. Не могли бы вы сообщить мне о любом другом способе обработки транзакций БД с помощью activiti. В основном я хочу создать серию обновлений БД и зафиксировать транзакцию в конце, если все транзакции успешны, или откатить все транзакции.   -  person Anupama Pathirage    schedule 31.01.2016


Ответы (2)


Вы можете использовать Thradlocal в Java для передачи объекта соединения различным служебным задачам.

Например, используйте базовый класс, как показано ниже, и расширьте каждую служебную задачу из него. Затем вы можете установить dbConnection и использовать всякий раз, когда это необходимо, с помощью метода get.

public class BaseServiceTask
{
    public static final ThreadLocal<Connection> localConnectionContext = new ThreadLocal<Connection>();

    public static void initDBConnector(Connection dbConn)
    {
        localConnectionContext.set(dbConn);
    }

    public static Connection getDBConnector()
    {
        return localConnectionContext.get();
    }
}

Примечание.
Этот подход предполагает, что все служебные задачи выполняются в одном потоке, что и имеет место в этом конкретном вопросе, но как только вы включаете некоторую пользовательскую задачу / таймер (или любую асинхронную логику), это больше не является жизнеспособным решением!

person Anupama    schedule 28.03.2016

Во-первых, вы должны знать, что нет абсолютно никакого способа сериализовать экземпляр соединения после его создания в соответствии с это.

Причина в том, что соединение использует сетевой ресурс (например, сокет TCP / IP), который использует сетевой стек на машине и, в конечном итоге, оборудование машины.

Что оставляет вам только эту альтернативу:

  • Настройте bean-компонент, который будет хранить для вас экземпляры соединения, назовем его myConnectionRegistry, этот bean-компонент должен иметь область видимости синглтона и внедряться во все ваши делегаты Java (реализации задач службы)
  • В первой задаче вы создаете соединение, а затем регистрируете его в myConnectionRegistry с помощью чего-то вроде этого connectionRegistry.register(conn, wfId), которое добавит экземпляр соединения к частной карте ....
  • В последующих задачах вы извлекаете свою задачу из того же bean-компонента, используя метод, который извлекает объект подключения из частной карты и генерирует исключение, если на карте не был зарегистрирован объект подключения.
  • Иметь граничное событие, которое запускается для этого исключения, и делать все необходимое для обеспечения целостности данных (например, вариант использования, который я описал в моем комментарии)
  • В последней служебной задаче отмените регистрацию вашего соединения (вы также должны его закрыть), чтобы предотвратить утечку памяти.
  • Обязательно учитывайте пул баз данных ... и т. д. при разработке решения!

Ваше здоровье!

person Younes Regaieg    schedule 31.01.2016
comment
Большое спасибо за четкое и информативное объяснение, которое дает мне хорошее руководство. Поскольку я новичок в activiti, это очень поможет. Я изучу соответствующие разделы в руководстве пользователя activiti, чтобы реализовать это. Если возможно, дайте мне знать любую хорошую справочную статью, блог об использовании beans с activiti. - person Anupama Pathirage; 31.01.2016