2017-02-21 6 views
-1

私は、エンティティを更新する必要がありますが、それは本当にSpring + Hibernate - トランザクションが実際にコミットされたとき?

私の方法は

@Override 
    @Transactional(isolation = Isolation.SERIALIZABLE) 
    public void lightOn(int idInterruttore) { 

     Interruttore interruttore = dao.findById(idInterruttore); 

      String inputPin = interruttore.getInputPin(); 
      String pinName = interruttore.getRelePin(); 
      GpioController gpio = interruttore.getGpio(); 
      GpioPinDigitalOutput rele = gpio.provisionDigitalOutputPin(RaspiPin.getPinByName(pinName)); 

      try { 
       DateTime date = new DateTime(); 
       Date now = date.toDate(); 
        int i = 1; 
        while (getInput(inputPin, gpio) != 1) { 
         if(i > 1){ 
         logger.debug(String.format("Try n %s", i)); 
         } 
         pushButton(rele); 
         Thread.sleep(1000); 
         i++; 
        } 
        dao.updateInterruttore(idInterruttore, now, true); 

      } catch (GpioPinExistsException | InterruptedException gpe) { 
       logger.error("GPIO già esistente", gpe); 
      } finally { 
       gpio.unprovisionPin(rele); 
      } 

     logger.debug(String.format("After the update status should be true and it's %s", 
       interruttore.isStato())); 
    } 

updateInterruttoreがあるが更新されたとき、私は知らない...

を特異な問題に直面しています(私はこのフォームを使用して、更新後にコミットを呼び出すようにしました...このメソッドに複数の呼び出しを行うことができますが、最初のものだけを更新する必要があるため、ロックオプションがあります。

@Override 
    public void updateInterruttore(int idInterruttore, Date dateTime, boolean stato) { 

     Session session = getSession(); 
     Transaction tx = session.beginTransaction(); 
     String update = "update Interruttore i set i.dateTime = :dateTime, i.stato = :stato where idInterruttore = :idInterruttore"; 
     session.createQuery(update).setTimestamp("dateTime", dateTime).setBoolean("stato", stato) 
       .setInteger("idInterruttore", idInterruttore).setLockOptions(LockOptions.UPGRADE).executeUpdate(); 
     tx.commit(); 
      } 

} 

はまあ...私は、ログを更新したときに私を言う:

After the update status should be true and it's false 

これは私がメソッドを呼び出すだけで最初の時間に発生し、二度目interruttore.isStatoが正しく真実です。

これはどうしてですか?

答えて

0

これは、データベースを更新ステートメントで直接更新しているために発生します。この場合、Hibernateはすでにロードされているエンティティを自動的に更新しません。 dao.updateInterruttoreへの呼び出し後にエンティティをリロードすると、更新されたデータが取得されます。

0

2つのノート:

1)更新を適用するためにクエリを使用しています。その場合、Hibernateはセッションにあるエンティティを更新しません。エンティティ自体を更新してsession.save(interruttore)を呼び出さない限り、エンティティは更新されません。 (ただし、更新はDBに表示されます。)さらに、エンティティを更新してsession.save()で保存しない理由はわかりません。

2)サービスメソッドに@Transactionalと注釈を付けています。 (春のアノテーションを想定しています)JTAを使用すると、tx.commit()は効果がありません。しかし、メソッドが完了すると、トランザクションはコミットされます。 (メソッドが例外をスローした場合はロールバックされます)JTAを使用していない場合は、@Transactionalを取り除き、DAOメソッドでトランザクションを管理します。しかし、それは悪い習慣とみなされます。

+0

私の問題は、メソッドへの複数の同時呼び出しがありますが、最初の1つだけが 'pushButton(rele)'コールを呼び出してInterruttoreを更新しなければならないため、他の人は 'interruttore.isStato () 'を呼び出し、press関数を呼び出さないでください。私はいくつかの試みを行い、このようにして(多かれ少なかれ)それが働いていることがわかりました。私はSpringの '@ Transactional'indeedを使用していますが、通常はセッターのメソッドを使用してエンティティを更新します。 – besmart

+0

DB並行処理とビジネス同時性を混在させているようです。トランザクションの途中でThread.sleepを呼び出しているという事実は本当に悪い兆候です。 HibernateセッションとDBとのやりとりにほとんど時間を費やさずにコードを再設計し、アプリケーションの並行性を他の場所で管理する必要があります。 DBの並行性は、トランザクションではなくユーザに基づいています。 – raminr

関連する問題