2013-07-23 3 views
0

Я пытаюсь вставить много строк в циклы while. Я понимаю, что я должен создать отдельный новый переходный экземпляр в теле цикла в транзакции.Строки не сохраняются при использовании объемных вставок в спящем режиме

Из моего опыта, не создающего отдельный экземпляр переходного процесса (переходный экземпляр внешнего тела цикла), вставляет, по крайней мере, одну строку, являющуюся последней строкой. Нужно ли использовать save только один раз здесь, прежде чем совершать транзакции?

Возможно использование flush() и clear() в этом случае?

Я относительно новичок в hibernate.I был бы благодарен за любую помощь или указал бы мне в правильном направлении.

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

public boolean addVariableHonorariumDetails(Monthly_variable_honorarium_processing mvhp 
              , Monthly_variable_group_honorarium_processing mvghp 
              , Monthlyvariablecompid compositeID) 
{ 
    Session session = HibernateUtil.getSessionFactory().openSession(); 
    Transaction tx = null; 
    String ccyymm = mvhp.getMvhp().getVariable_monthly_ccyy()+mvhp.getMvhp().getVariable_monthly_month(); 

    try 
    { 
     tx = session.beginTransaction(); 

     // ctrl query 

     M_control_table mct = (M_control_table) session.createQuery("from M_control_table").uniqueResult(); //single result 

     Query query = session.createSQLQuery(
"Select c.Booklet_type, SUM(c.End_Leaf - c.Start_Leaf +1) as No_of_Coupons from m_coupon_sale c where date_format(c.Booklet_Sale_Date, '%Y%m') = :string and c.Booklet_type in ('GR','PI') group by c.Booklet_Type") 
          .addScalar("c.Booklet_type", Hibernate.STRING) 
          .addScalar("No_of_Coupons", Hibernate.STRING) 
          .setString("string", ccyymm); 

     ScrollableResults results = query.scroll(); 

     Integer sumTotalOfPayment = 0; 
     while (results.next()) 
     { 
      Object[] row = results.get(); 

      mvghp.setMvhpgroup(new Monthlyvariablecompid(mvhp.getMvhp().getVariable_monthly_month() 
           , mvhp.getMvhp().getVariable_monthly_ccyy() 
           , row[0].toString()) 
          ); 

      mvghp.setNo_of_items(row[1].toString()); 

      Integer no_of_items = Integer.parseInt(mvghp.getNo_of_items(), 10); 

      mvghp.setGroup_rate((row[0].toString().equals("GR")) ? mct.getRate_for_green_coupons() 
                    : mct.getRate_for_pink_coupons() ); 

      Integer variable_payment = no_of_items * Integer.parseInt(mvghp.getGroup_rate(), 10); 
      sumTotalOfPayment = sumTotalOfPayment + variable_payment; 

      mvghp.setVariable_payment(variable_payment.toString()); 

      session.save(mvghp); 
      session.flush(); 
      session.clear(); 
     } 

     Query query2 = session.createSQLQuery(
"select m.pooja_name, count(*) as no_of_items from t_pooja_booking t inner join m_pooja_detail m on t.pooja_id=m.pooja_id where date_format(t.pooja_date, '%Y%m')= :string and m.pooja_name in ('A','B') group by m.pooja_name") 
              .addScalar("m.pooja_name", Hibernate.STRING) 
              .addScalar("no_of_items", Hibernate.STRING) 
              .setString("string", ccyymm); 

     ScrollableResults results1 = query2.scroll(); 

     while (results1.next()) 
     { 
      Object[] row = results1.get(); 

      mvghp.setMvhpgroup(new Monthlyvariablecompid(mvhp.getMvhp().getVariable_monthly_month() 
           , mvhp.getMvhp().getVariable_monthly_ccyy() 
           , row[0].toString()) 
          ); 

      mvghp.setNo_of_items(row[1].toString()); 
      Integer no_of_items = Integer.parseInt(mvghp.getNo_of_items(), 10); 

      mvghp.setGroup_rate((row[0].toString().equals("A"))?mct.getRate_for_108_vadamalas_cook() 
                      :mct.getRate_for_51_vadamalas_cook()); 

      Integer variable_payment = no_of_items * Integer.parseInt(mvghp.getGroup_rate() , 10) ; 
      sumTotalOfPayment = sumTotalOfPayment + variable_payment; 

      mvghp.setVariable_payment(variable_payment.toString()); 

      session.save(mvghp); 
      session.flush(); 
      session.clear(); 
     } 


     mvhp.setTotal_variable_payment(sumTotalOfPayment.toString()); 
     session.save(mvhp); 

     tx.commit(); 

    } 
    catch(Exception e) 
    { 
     if(tx!=null) 
     { 
      tx.rollback(); 
     } 
     e.printStackTrace(); 
     return false; 
    } 
    finally 
    { 
     session.close(); 
    } 

    return true; 
} 

ответ

1

Вызов session.save (mvghp), session.flush() и session.clear() для каждой итерации цикла, в лучшем случае неэффективно, и кажется, что это может быть частью того, где ваша путаница возникает из.

Вернемся к основам. В Hibernate каждый объект свободно представляет строку в таблице верхнего уровня, а также строки дочерних таблиц, которые присоединяются к этой строке верхнего уровня. (Да, есть исключения, и да, это упрощение, но для кого-то нового для Hibernate, это хорошая рабочая модель, которая поможет вам поднять ноги под собой.) Это означает, что если вы собираетесь в конечном итоге с несколькими строки в таблице в конце (например, один раз за итерацию цикла), вы должны быть в конечном итоге с несколькими объектами, по одному на строку. То, что вы делаете (повторное использование одного объекта Hibernate), идет вразрез с этим; если я правильно понял ваш случай использования, вы должны создать новый Hibernate POJO (сокращение от обычного объекта Java) для каждой итерации через цикл.

Во-вторых, POJO может быть либо постоянным (сеанс Hibernate знает об этом объекте и сохраняет изменения в базе данных, когда ваша транзакция становится красной или закрытой), либо переходная (Hibernate ничего не знает об этом объекте и не будет сохранять изменения в базе данных). Вызов save() делает переходный объект постоянным (и не влияет на POJO, который уже является постоянным!); это, вероятно, наихудший метод в Hibernate API, и его следует называть makePersistent() вместо save(), поскольку он фактически не сохраняет объект в базе данных. Скорее, он делает его постоянным, так что он будет в конечном итоге получить сохраненный в базе данных. Вызов clear() делает обратное: он принимает все постоянные объекты в сеансе и делает их непостоянными, отбрасывая все изменения в этом процессе и не влияет на POJO, которые уже являются переходными.

И flush() просто заставляет Hibernate записывать все изменения в постоянные объекты в базу данных; Hibernate может делать это в любое другое время, если он захочет, и гарантированно это сделает, когда транзакция сессии совершит, но вызов flush() заставляет его делать это прямо сейчас. Но он не совершает транзакцию, поэтому: а) вы все равно потеряете эти изменения, если транзакция откатится, и б) вы не увидите изменений в базе данных до тех пор, пока транзакция не совершит, если вы просматриваете что-то вроде SQLPlus. Обычно это полезно только тогда, когда вы хотите переместить свои изменения из своих POJO в базу данных, прежде чем запускать SQL-запрос, в котором вы хотите, чтобы он учитывал сделанные вами изменения или где у вас очень большие транзакции, которые вы хотите сбросить ваши изменения для одной партии, а затем мусор - собирайте эти POJO, чтобы у вас не хватило памяти до завершения транзакции, и, конечно же, это не обязательно, если вы говорите, что находитесь с Hibernate.

Поэтому, когда вы вызываете save(), затем flush(), а затем очищаете() для каждого POJO, то, что вы делаете, делает этот объект постоянным, а затем заставляет базу данных записывать свои данные в БД, и затем делает его временным. Затем вы вносите изменения в свои данные во время следующей итерации цикла, и когда вы делаете это снова постоянным, Hibernate считает, что это новый объект (как вы хотите) и сохраняет новую строку в базе данных. Это работает, но всякий промывка неэффективна (и запутывает людей, знакомых с Hibernate), и вы получите такое же поведение, просто создав N экземпляров вашего типа POJO и вызвав save() на каждом из них (без flush(), нет clear()), с лучшей производительностью и меньшей путаницей.

Кроме того, clear() - это кувалда; он удаляет все POJO из сеанса Hibernate, что может вызвать очень неожиданное поведение для любого кода, который ожидал, что сможет изменить эти объекты и сохранить эти изменения. (Ваш вызов flush() перед этим будет гарантировать, что любые изменения, которые уже были сделаны, будут сохраняться, но ничего не сделают, чтобы гарантировать, что будущие изменения сделают.) Это также означает, что в любое время Hibernate необходимо получить любой из этих объектов, чтобы вернуться к базе данных, а не вытаскивать их из кеша сеанса, что неэффективно. Если вы действительно хотели использовать подход, который у вас есть здесь (и я делал это иногда, например, в ситуациях, когда мне хотелось, чтобы многие объекты сохранялись, но не могли разумно построить новый объект для каждого, поэтому я повторно использовал один и тот же объект, изменяя его свойства, пока он преходящ, и не отслеживает эти изменения, а затем ненадолго делает его постоянным, поэтому он будет записывать «новый» объект в базу данных), метод, который вы, вероятно, захотите использовать, - это выдворение (), который позволяет удалить из кэша только один объект Hibernate. Но я хочу подчеркнуть, что даже evict() является скорее функцией только для экспертов, и вам не нужно (и не следует использовать его) в большинстве сценариев, в том числе и в вашем примере.

Надеюсь, это поможет вам получить дальнейшее понимание вашего спящего режима ...

Смежные вопросы