Dün karşılaştığım bir bilgiyi paylaşmak istedim bugün. Spring MVC 3.0 üzerisinde çalışıyordum. Hibernate kullanıyorum ve veritabanına bir insert yapmam gerekiyordu. Tabii ki Entity Manager'ın bir örneğini aldıktan sonra ona veritabanındaki tablonun pojosu türünden bir nesne göndermem gerekiyordu. Buraya kadar herşey gayet güzel, gayet hoş. İşler tıkırında herşey çalışıyor. Kodum da aşağıda.
@Transactional
public void insertName(TmFrstDnm name) throws DataAccessException {
try {
entityManager.persist(name);
entityManager.flush();
}
catch (Exception e) {
e.printStackTrace();
}
}
Eski zamanlardan kalma alışkanlık, ucu veritabanına dokunan her işlemi try catch bloguna aldım. Ve editor debug aşamasında bas bas bağırdı.
"org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly"
"Transaction marked as rollbackOnly" mi :S ?? Nasıl olur, ben commit edemeyeceğim datayla niçin oynayayım. Tablom CRUD işlemlerini yoğun olarak barındıran bir tablo. Eğer rollback yapacaktıysam Temprorary Table kullanırdım, hem de Oracle'ın üzerisindeki yükü hafifletirdim.(Bknz Redo Log Oluşumu)
Biraz araştırınca sebebi ortaya çıktı. Entity Manager'ın yapacağı işlemleri try catch blogu içerisine aldığımızda kodun çalışması garanti olamıyor. Yani şöyle örnekleyelim, yukarıdaki flush işleminin altında da kod parçaları olduğunu düşünün. O kod parçasında bir exception olduğu zaman try işleminin içerisinde yapılan işlemin tamamının iptal edilmesi, doğrudan catch blogunun içerisinin işletilmesi gerekir. Ancak bu exception'dan önce flush işlemi yapıldığından veritabanı commit'lenmiş olacak, işlemin geriye alınması mümkün olmayacaktır. İşte bunu önleyebilmek için try-catch blogu içerisindeki veritabanı işlemleri otomatik olarak rollback only yapılıyor. Bu sebeple try içerisindeki flush'ım çalışmıyor.
Peki neler yapılabilir? Flush try'ın dışarısına çıkarılabilir. Ortaya çıkan exception'lar fırlatılarak DAO katmanında yakalanmaktansa service veya controller katmanında yakalanabilir. Veya try-catch bloguna bir de finally eklenerek burada commit yapılmak istenebilir ama ne kadar tercih edilesi bir durumdur tartışılır.
İşte böyle, ilginç ama güzel bir senaryo. Tekrar görüşmek üzere
e.printStackTrace();
}
}
Eski zamanlardan kalma alışkanlık, ucu veritabanına dokunan her işlemi try catch bloguna aldım. Ve editor debug aşamasında bas bas bağırdı.
"org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly"
"Transaction marked as rollbackOnly" mi :S ?? Nasıl olur, ben commit edemeyeceğim datayla niçin oynayayım. Tablom CRUD işlemlerini yoğun olarak barındıran bir tablo. Eğer rollback yapacaktıysam Temprorary Table kullanırdım, hem de Oracle'ın üzerisindeki yükü hafifletirdim.(Bknz Redo Log Oluşumu)
Biraz araştırınca sebebi ortaya çıktı. Entity Manager'ın yapacağı işlemleri try catch blogu içerisine aldığımızda kodun çalışması garanti olamıyor. Yani şöyle örnekleyelim, yukarıdaki flush işleminin altında da kod parçaları olduğunu düşünün. O kod parçasında bir exception olduğu zaman try işleminin içerisinde yapılan işlemin tamamının iptal edilmesi, doğrudan catch blogunun içerisinin işletilmesi gerekir. Ancak bu exception'dan önce flush işlemi yapıldığından veritabanı commit'lenmiş olacak, işlemin geriye alınması mümkün olmayacaktır. İşte bunu önleyebilmek için try-catch blogu içerisindeki veritabanı işlemleri otomatik olarak rollback only yapılıyor. Bu sebeple try içerisindeki flush'ım çalışmıyor.
Peki neler yapılabilir? Flush try'ın dışarısına çıkarılabilir. Ortaya çıkan exception'lar fırlatılarak DAO katmanında yakalanmaktansa service veya controller katmanında yakalanabilir. Veya try-catch bloguna bir de finally eklenerek burada commit yapılmak istenebilir ama ne kadar tercih edilesi bir durumdur tartışılır.
İşte böyle, ilginç ama güzel bir senaryo. Tekrar görüşmek üzere
0 yorum:
Yorum Gönder