2015-12-18 3 views
1

Я хочу сделать многопоточную обработку с помощью JTA.JTA Транзакция и нить

Окружающая среда:

  • JBOSS AS 6,3
  • Java 7
  • Oracle 11.2g
  • КДИ

Лечение: Я хочу, чтобы произвести молнию со всеми DATAS из базы данных. Этот zip-файл может быть большим, поэтому я хочу начать поток для создания потока в то же время, когда jboss отправит его клиенту.

Мои ОСТАЛЬНЫЕ запись:

@Stateless 
@Path("/exportProcess") 
public class ExportProcessusResource { 

    @Inject 
    private IExport export; 

    @GET 
    @Path("/{processCode: [^/]+}") 
    @Produces(MediaType.APPLICATION_OCTET_STREAM) 
    public Response export(@PathParam("processCode") final String pProcessCode) { 
     return Response.ok(export.export(pProcessCode)) 
           .header("Content-Disposition", "attachment; filename=" + pCodeProcessus + ".zip") 
           .build(); 
    } 
} 

Мой МОДЕЛЬ:

@Entity 
@Table(name = "T_PROCESS") 
@NamedQueries({ 
    @NamedQuery(name = "Process.GetByCode", query = "SELECT p FROM Process p WHERE p.code=:code") 
}) 
public class Process { 

    @Column(name = "CODE", length = 50, nullable = false) 
    private String code; 

    @OneToMany(mappedBy = "process", targetEntity = Step.class) 
    private Collection<Step> steps; 

    //Getters/Setters 
} 

@Entity 
@Table(name = "T_STEP") 
public class STEP { 
    @Id 
    @Column(name = "ID_STEP") 
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_ID_STEP") 
    @SequenceGenerator(name = "SEQ_ID_STEP", sequenceName = "SEQ_ID_STEP") 
    private int id; 

    @ManyToOne(targetEntity = Process.class) 
    @JoinColumn(name = "CODE_PROCESS", referencedColumnName = "CODE", nullable = false) 
    private Process process; 

    //Getters/Setters 
} 

Мой DAO:

public interface IProcessDao { 

    Processus getByCode(final String pCode); 
} 

public class ProcessDao implements IProcessDao { 

    @Override 
    public Processus getByCode(final String pCode) { 
     Processus lResult = null; 
     try { 
      final TypedQuery<Processus> lRequest = pEm.createNamedQuery("Process.GetByCode", Process.class); 
      lRequest.setParameter("code", pCode); 
      lResult = lRequest.getSingleResult(); 
     } catch (final NoResultException e) { 
      // Return null 
      lResult = null; 
     } 
     return lResult; 
    } 
} 

Мой контроллер:

public interface IExport { 

    /** 
    * Generate export 
    * 
    * @param pProcessCode Process code 
    * @return Datas 
    */ 
    InputStream export(final String pProcessCode); 
} 


public class Export implements IExport { 

    @PersistenceContext(unitName="authorizations") 
    private EntityManager entityManagerAuthorizations; 

    @Inject 
    private ExportThreadHelper exportThreadHelper; 

    @Override 
    public InputStream export(final String pProcessCode) { 
     //Check if user has the profile. Use database "AUTHORIZATIONS" 
     checkProfil(entityManagerAuthorizations, Profiles.ADMIN); 

     final PipedInputStream lInputStream = new PipedInputStream(); 
     OutputStream lOutputStream = null; 
     try { 
      lOutputStream = new FileOutputStream("d:/test.zip");// new 
                   // PipedOutputStream(lInputStream); 
     } catch (final IOException e) { 
      throw new RuntimeException("Cannot start zip generation", e); 
     } 

     final ZipOutputStream lZipOutputStream = new ZipOutputStream(lOutputStream); 

     final Runnable lRunnable = new Runnable() { 
      @Override 
      public void run() { 
       try { 
        exportThreadHelper.export(pProcessCode, lZipOutputStream); 
       } catch (final Exception e) { 
        logger.error(e); 
       } finally { 
        IOUtils.closeQuietly(lZipOutputStream); 
       } 
      } 
     }; 
     //To execute in same thread : 
     //lRunnable.run(); 

     //To execute in another thread 
     final Thread lThread = new Thread(lRunnable); 
     lThread.start(); 
     try { 
      lThread.join(); 
     } catch (final InterruptedException e1) { 
      throw new RuntimeException(e1); 
     } 


     try { 
      return new FileInputStream("d:/test.zip"); 
     } catch (final FileNotFoundException e) { 
      logger.error(e); 
     } 
     return lInputStream; 
    } 
} 


public class ExportThreadHelper { 

    private class ProcessToExport { 
     //... 
    } 

    @PersistenceContext 
    @Named("Application") 
    private EntityManager entityManagerThreadable; 

    @Inject 
    private IProcessDao processDao; 

    public void export(final String pProcesssCode, final ZipOutputStream pZipOutputStream) 
        throws MyWayBusinessException { 
     try { 

      final ProcessToExport lProcessToExport = new ProcessToExport(); 

      transaction(entityManagerThreadable, new Callable<Void>() { 
       @Override 
       public Void execute() { 
        final Process lProcess = processDao.getByCode(pProcesssCode); 
        for (final Step lStep : lProcess.getSteps()) { 
         //Many things 
        } 
        return null; 
       } 
      }); 

      //MANY OTHER TREATMENTS 

     } catch (final Exception e) { 
      logger.error(e); 
      throw new RuntimeException("Cannot generate export", e); 
     } 
    } 

    @Override 
    @TransactionAttribute(TransactionAttributeType.REQUIRED) 
    protected <T> T transaction(final EntityManager pEntityManager, final Callable<T> pCallable) { 
     //I've tried with and without the annotation and with and without the "UserTransaction" 
     try { 
      final UserTransaction tx = com.arjuna.ats.jta.UserTransaction.userTransaction(); 
      try { 
       tx.begin(); 
       final T lResultat = pCallable.execute(); 
       tx.commit(); 
       return lResultat; 
      } catch (final Throwable e) { 
       tx.rollback(); 
       throw e; 
      } 
     } catch (final Throwable e) { 
      throw new RuntimeException(e); 
     } 
    } 
} 

Мои persistence.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<persistence version="2.0" 
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd "> 
    <persistence-unit name="APPLICATION" transaction-type="JTA"> 
     <jta-data-source>java:/jdbc/app</jta-data-source> 
     <class>Processus</class> 
     <class>Step</class> 
     <properties> 
      <!-- Scan for annotated classes and Hibernate mapping XML files --> 
      <property name="hibernate.archive.autodetection" value="class, hbm" /> 
     </properties> 
    </persistence-unit> 
    <persistence-unit name="AUTHORIZATION" transaction-type="JTA"> 
     <jta-data-source>java:/jdbc/AUTHORIZATION</jta-data-source> 
     <!-- many things... --> 
    </persistence-unit> 
</persistence> 

(я почистил код, чтобы сохранить только важные вещи).

И, если я использую версию monothread (lRunnable.run()), у меня есть zip-файл, но если я запустил многопоточную версию (thread.start()) (которую я заблокировал здесь, чтобы обеспечить мои тесты, подключение не близко родительская нить, но после того, как я удалю Thread.join()) Я это исключение:

ERROR [... ExportThreadHelper] (Thread-115) не лениво инициализировать набор ролей: .steps, не удалось инициализировать прокси - нет Сессия: org.hibernate.LazyInitializationException: не удалось лениво инициализировать коллекцию роли: .steps, не удалось инициализировать прокси - нет сеанса на org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException (AbstractPersistentCollection.java:569) [hibernate-core-4.2.14.SP1-redhat-1.jar: 4.2.14.SP1-redhat-1] на org .hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded (AbstractPersistentCollection.java:188) [hibernate-core-4.2.14.SP1-redhat-1.jar: 4.2.14.SP1-redhat-1] в org.hibernate .collection.internal.AbstractPersistentCollection.initialize (AbstractPersistentCollection.java:548) [hibernate-core-4.2.14.SP1-redhat-1.jar: 4.2.14.SP1-redhat-1] в org.hibernate.collection .internal.AbstractPersistentCollection.read (AbstractPersistentCollection.java:126) [hibernate-core-4.2.14.SP1-redhat-1.jar: 4.2.14.SP1-redhat-1] в org.hibernate.collection.internal.PersistentBag.iterator (PersistentBag.java:266) [hibernate-core-4.2.14.SP1-redhat-1.jar: 4.2.14.SP1-redhat-1] в ExportThreadHelper $ 1.execute (ExportThreadHelper.java:101) [metier-2.3.0-SNAPSHOT.jar:] at ExportThreadHelper $ 1.execute (ExportThreadHelper.java:1) [metier-2.3.0-SNAPSHOT.банку:] в ExportThreadHelper.transaction (ExportThreadHelper.java:148) [2.3.0-ремесло-SNAPSHOT.jar:] в ExportThreadHelper.export (ExportThreadHelper.java:97) [métier-2.3.0-SNAPSHOT. jar:] at ExportMetier $ 1.run (ExportMetier.java:62) [metier-2.3.0-SNAPSHOT.jar:] at java.lang.Thread.run (Thread.java:722) [rt.jar: 1.7 .0_04]

Вы видели проблему в моем коде?

+0

ли вы имея файл с именем 'ExportThreadHelper.java' в проекте, вы можете разместить этот файл. Специально линии около 90-150? – Amogh

+0

С первого взгляда на исключение кажется, что вы пытаетесь получить доступ к 'Collection ' из объекта 'Process' из сеанса спящего режима. Либо не закрывайте спящий режим сеанса или набор 'выборки = FetchType.EAGER' в' частной коллекции шагов; ' – Amogh

+0

Спасибо за внимание - ExportThreadHelper находится в«контроллер»часть - Я хочу, чтобы сохранить ленивая загрузка, потому что слишком много, и я не использую ее во всех случаях. – Chklang

ответ

0

Вам необходимо изменить запрос, как это:

@NamedQueries({ 
    @NamedQuery(name = "Process.GetByCode", query = "SELECT p FROM Process p LEFT JOIN FETCH p.steps WHERE p.code=:code") 
}) 
+0

Я также могу добавить «fetch = EAGER» в поле, но я не хочу этого, потому что иначе мы все время получаем все данные по каждому случаю. Я хочу поддерживать ленивую загрузку и правильно использовать транзакции. – Chklang

+0

Почему бы не задать два запроса? –

+0

Я не хочу быть зависимым от контекста. Это большое приложение, которое работает в REST. И этот новый ресурс REST должен создать «экспорт» в zip-файле ответов. Поэтому, если вы вызываете «/ rest/myResource», вы получаете JSON, и если вы вызываете «/ rest/export», у вас будет «zip-файл» с «/rest/myResource.json», который содержит ответ первого запроса , Это простой пример, но проблема здесь: я хочу вызвать все другие бизнес-методы в потоке для создания zip-файла. – Chklang