Doğrudan JDBC Kullanırken
JDBC spesifikasyonuna göre veritabanı bağlantılarının default autocommit değeri true
’dur. Bu nedenle doğrudan JDBC ile
işlem yaptığınızda, veri üzerinde değişiklik yapan operasyonların her birisi kendi başına ayrı bir transaction’da ele
alınacaktır. Transactional çalışabilmek için öncelikle bağlantının autocommit
özelliğini false
yapmanız gerekmektedir.
Eğer veritabanı bağlantısı yaratılırken autocommit
değerinin false
olmasını istiyorsanız, bunu DataSource
’un
defaultAutoCommit
property’si üzerinden yapabilirsiniz. Ya da doğrudan veritabanı üzerinde autocommit
’i false
olarak
set edebilirsiniz. Örneğin, HSQLDB’de “SET AUTOCOMMIT FALSE
” komutunu çalıştırmanız yeterlidir.
Eğer Spring kullanıyorsanız, DriverManagerDataSource
bean’ının connectionProperties
property’si ile defaultAutoCommit
’i
false
olarak set edebilirsiniz. Test ortamları için yazılmış olan SingleConnectionDataSource
bean’ını kullanıyorsanız,
ya connectionProperties
ile ya da doğrudan autoCommit
property’si üzerinden false
yapabilirsiniz.
Doğrudan Hibernate Kullanırken
Hibernate tarafında autocommit davranışı hibernate.connection.autocommit
property’si ile düzenlenmektedir. Default
olarak Hibernate, autocommit’i false
olarak set etmektedir ve bu property ile oynanmaması önerilmektedir. Detaylar için
Hibernate’in sitesindeki ilgili yazıyı okuyabilirsiniz.
Peki autocommit false
olunca ne oluyor? Autocommit false
olduğunda veri erişim işlemleri yine eskiden olduğu gibi
problemsiz gerçekleşiyor. Ancak insert
, update
, delete
gibi veri üzerinde değişikliklere neden olan işlemler için
Hibernate Session
üzerinde mutlaka transaction başlatılması gerekiyor. Yapılan işlemler sonrasında ise iş akışına göre
transaction commit
veya rollback
edilmeli ki yapılan değişiklikler veritabanına yansısın. Transaction başlatılmadan
yapılan insert
, delete
, update
işlemleri ile ilgili hiçbir hata olmamaktadır; Hibernate bu işlemleri sessizce göz
ardı etmektedir.
<hibernate-configuration>
<session-factory>
<property name="connection.autocommit">true</property>
<property name="dialect">org.hibernate.dialect.HSQLDialect</property>
<property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>
<mapping class="examples.Foo"/>
</session-factory>
</hibernate-configuration>
Foo foo = new Foo();
Configuration configuration = new AnnotationConfiguration().configure();
SessionFactory factory = configuration.buildSessionFactory();
Session session = factory.openSession();
session.save(foo);
session.close();
Eğer Hibernate ile çalışırken autocommit davranışını doğrudan JDBC kullanımı gibi yapmak istiyorsanız, yapmanız gereken
yukarıdaki örnekte gördüğünüz connection.commit
property değerini true
olarak set etmekten ibarettir. Bu durumda
Hibernate Session
üzerinde hiç transaction oluşturmadan veri manipülasyonu gerçekleştirebilirsiniz.
Spring ile Hibernate Kullanırken
Eğer Spring üzerinden Hibernate’i kullanıyorsanız işler biraz farklılaşmaktadır. Muhtemelen Hibernate SessionFactory
nesnesini Spring’in LocalSessionFactoryBean
factory bean’ı ile oluşturuyorsunuzdur. Hibernate SessionFactory
bu
durumda “user supplied connection” kullandığını düşünerek JDBC bağlantısını kendisi oluşturmak yerine doğrudan Spring’in
inject ettiği DataSource
bean’ından beklemektedir. Bu durumda da Hibernate’in hibernate.cfg.xml
dosyası içerisinde
belirteceğiniz connection.autocommit
değişkeninin bir etkisi olmamaktadır.
Veritabanı bağlantısının autocommit özelliği, DataSource
bean’ı nasıl konfigüre edilmişse ona göre değişmektedir.
DriverManagerDataSource
bean’ı, defaultAutoCommit
değerine bir değişiklik yapmadığı için de bu değer true
olarak
kalmakta ve Hibernate üzerinden gerçekleşen veri manipülasyonları da ortada bir transaction olmasa bile veritabanına
yansıtılmaktadır.
Doğrudan Hibernate kullanırken ki default Hibernate davranışını sağlamak için Spring ile konfigüre ettiğiniz DataSource
bean’ına, veritabanı bağlantısı oluştururken autocommit
’i false
yapmasını söylemeniz gerekmektedir.
Foo foo = new Foo();
hibernateTemplate.persist(foo);
JPA ile Hibernate Kullanırken
Hibernate’i JPA ile kullanırken durum biraz daha değişmektedir. JPA, veri üzerinde manipülasyon yapan işlemler için mutlaka
bir transaction beklemektedir. Sizin DataSource
bean’ı üzerinde veya hibernate.cfg.xml
içerisinde autocommit davranışını
true
yapmanızın bir etkisi olmamaktadır. Her iki durumda da transaction olmadan yapılan bir veri manipülasyonu
javax.persistence.TransactionRequiredException
ile sonuçlanmaktadır.
Eğer yukarıdaki işlemin başarılı biçimde sonuçlanmasını istiyorsanız, bu işlemi mutlaka bir transaction içerisinde çalıştırmanız gerekmektedir.
Foo foo = new Foo();
jpaTemplate.persist(foo);
jpaTemplate.flush();
Kısacası autocommit özelliği, Hibernate’in doğrudan kullanımı veya SessionFactory
’nin Spring tarafından yönetilmesi,
JPA üzerinden Hibernate kullanılması durumlarının her birinde farklı biçimlerde ele alınmaktadır. Bu nedenle yazdığınız
servislerin veri erişim mekanizmaları farklılaştığında davranışlarında da değişiklikler söz konusu oluyorsa şaşırmayın.