Önceki yazılarımda veri tabanında değişiklik yapmak ya da sorgu çekmek için, Java’nın Statement Interface’ini kullanarak SQL sorgularımızı teker teker göndermiştik. Bu SQL sorguları da veri tabanına her gidişinde orada tekrar derlenir, veri tabanının yönetim sistemi tarafından ideal bir yürütme politikası belirlenir ve sorgular çalıştırılır. Genelde, veri tabanıyla iletişimin çok büyük verileri kullanarak yapıldığını göz önünde bulundurursak bahsettiğim işlemi tekrar tekrar yapmak yürütme hızını ve verimi oldukça düşürecektir. Bu sebeple, bir uygulamanın database ile girdiği veri alış-verişinde Java’nın PreparedStatement (Interface) yapısı tercih edilmelidir. PreparedStatement önceden derlenmiş SQL cümlelerini saklamaya yarayan yapılara verilen isimdir. PreparedStatement özellikle;
- Bir SQL sorgusunu tekrar tekrar (mesela bir for döngüsü içersinde) çalıştırmak gerektiğinde,
- İçiçe geçmiş tabloları barındıran bir SQL sorgusunu çalıştırırken,
- SQL sorgularındaki değişken sayısı fazla olduğu gibi durumlarda tercih sebebidir ve veri tabanının performansını farkedelir derecede artırır.

PreparedStatement syntax’ı ise oldukça basittir:
SQL sorgularındaki parametrik alanlara soru işareti (?) yerleştirilir ve bu alanlar SQL sorgusu veri tabanına gönderilmeden önce gerçek değerleriyle doldurulur. Başta soru işareti ile doldurduğumuz alanlara daha sonra setter methodlar (setString(), setDate() vs.) yardımıyla gerçek değerleri atarız. Mesela, pStmt.setString(2, “Selam”) kullanımında preparedStatement’ın ikinci parametresine “Selam” değerini atamış oluruz. Dilerseniz PreparedStatement yapısının kullanımını iki farklı örnekte detaylıca inceleyelim. İlk örnekte önceden oluşturulmuş ‘Calisan’ tablomuzdaki bir kayıdın değeri değiştirilirken, ikinci örnekte de PreparedStatement yapısının bir döngü içersinde ne kadar performanslı çalıştığını gözlemleyelim.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class PreparedStatementOrnegi {
	//static olan main method içersinden erişebilmek adına bütün değişkenler static olarak tanımlanmalıdır.
	private static String url = "jdbc:oracle:thin:@localhost:1521:XE"; //Bu örnek için lokaldeki database'e bağlanacağız.
	private static Connection conn;
	private static PreparedStatement prepSta;

	public static void main(String[] args) throws SQLException {
		try
		{
			//Sınıfımızı DriverManager'a tanıtmakla başlayalım
			DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
			//Database ile bağlantıyı oluşturalım: Bunun için TestUser kullanıcı adını ve password parolasını kullanacağız.
			conn = DriverManager.getConnection(url, "TestUser", "password");

			//Parametrik olarak hazırladğımız pre-compiled update sorgusu
			prepSta = conn.prepareStatement("Update Calisan set DEPARTMAN = ?, MAAS = ? Where CALISAN_ID = ?");

			prepSta.setString(1, "Management"); //Birinci parametreyi "Management" değeri ile doldur
			//İkinci parametreyi (maaş sütununu) 2000 ile calisan_id bölümünü ise 7 ile dolduralım
			prepSta.setInt(2, 2000);
			prepSta.setInt(3, 7);

			//Artık sorguyu çalıştırabiliriz. i local değişkeni etkilenen satır sayısını belirtir.
			int i = prepSta.executeUpdate();
			System.out.println(i + " Row(s) Affected...");

		}

		catch(SQLException e)
		{
			System.out.println("Hata: " + e.getErrorCode() + " " + e.getMessage());
			throw new SQLException(e);
		}

		finally
		{
			//Hafızayı şişirmemesi açısından bağlantıları kapayabiliriz.
			prepSta.close();
			conn.close();
		}
	}

}
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

public class PStatementPerformans {
	private static Connection conn;
	private static Statement stmt;
	private static PreparedStatement prepStmt;
	private static String url = "jdbc:oracle:thin:@localhost:1521:XE";
	private static long baslangicZamani, bitisZamani;

	public static void main(String[] args) throws SQLException
	{
		try{

			DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
			conn = DriverManager.getConnection(url, "TestUser", "password");
			stmt = conn.createStatement();
			baslangicZamani = System.currentTimeMillis();
			for(int i = 0; i<10000; i++){
				stmt.executeUpdate("Insert into TESTTABLOSU values ('test', " + i + ")");

			}
			bitisZamani = System.currentTimeMillis();
			System.out.println("Statement ile çalışma zamanı " + (bitisZamani - baslangicZamani) + " ms. \n");

			stmt.execute("Truncate table TESTTABLOSU");

			baslangicZamani = System.currentTimeMillis();
			prepStmt = conn.prepareStatement("Insert into TESTTABLOSU values (? , ?)");
			for(int j = 0; j<10000; j++){
				prepStmt.setString(1,"test");
				prepStmt.setInt(2, j);
				prepStmt.executeUpdate();
			}
			bitisZamani = System.currentTimeMillis();
			System.out.println("PreparedStatement ile çalışma zamanı " + (bitisZamani - baslangicZamani) + " ms. \n");

		}
		catch(Exception e){
			throw new RuntimeException(e);
		}
		finally{
			conn.close();
			stmt.close();
			prepStmt.close();

		}
	}

}

Yukarıdaki programı çalıştırdğımızda PreparedStatement yapısının Statement yapısına oranla %50'ye varan bir performans kazancı sağladığını göreceksiniz.

Merhaba Arkadaşlar,
Bir önceki yazımda JDBC yardımıyla Oracle Veri Tabanına bağlanmayı ve SQL sorgularımızı Java programımızdan çalıştırmayı anlatmıştım. Örneğimde ise yazdığım SQL cümlelerini hemen ardından Statement Interface’inden executeUpdate() methodunu çağırarak çalıştırmıştım. Fakat SQL sorgularımızı çalıştırmanın tek yolu bu değil. Batch adı verilen, JDBC 2.0 API’si ile birlikte desteklenmeye başlanan ve Statement, PreparedStatement ve CallableStatement objelerinin liste halinde tuttuğu sorguları topluca çalıştırmaya yarayan bu yapı veri tabanıyla iletişimin bir başka yoludur. Özellikle çok sayıda satırı etkileyen SQL sorgularında executeUpdate() methoduna oranla daha iyi bir performans gösteren Batch, aynı zamanda kodun satır sayısı da göz önünde bulundurulduğunda daha etkili bir yöntemdir. Aşağıda, bir önceki örnekte oluşturduğum ‘Calisan’ tablosuna Batch yapısını kullanarak yeni kayıtlar ekleyen örnek bir program ekledim. Umarım işinize yarar.

import java.sql.*;
public class BatchUpdateOrnegi {

	private static String url = "jdbc:oracle:thin:@localhost:1521:XE";
	private static Connection conn;

	public static void main(String[] args) throws SQLException
	{

		try
		{

			//Öncelikle kullanacağımız Oracle jdbc driver'ımızı tanımlayalım.
			DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
			//Driver'ımızı tanımladığımıza göre artık bir bağlantı objesi oluşturabiliriz
			conn = DriverManager.getConnection(url, "TestUser", "password");

			//SQL statementlarımızı yazmadan önce veri tabanımızın batchUpdate'i destekleyip desteklemediğini öğrenebiliriz

			//Bunun için veri tabanımız hakkında her türlü bilgiye ulaşabilceğimiz bir databaseMetaData objesi oluşturmamız gerekmekte.
			DatabaseMetaData dbMData = conn.getMetaData(); 

			//DatabaseMetaData interface'inin supportsBatchUpdates() methodunu kullanacağız test için.
			if(dbMData.supportsBatchUpdates())
			{
				System.out.println(dbMData.getDatabaseProductVersion() + " batchUpdate'i desteklemektedir... ");
				//Bir sonraki işlemimiz pek çok database'de öntanımlı olarak belirlenen autocommit özelliğini kapatmak olacak.
				conn.setAutoCommit(false);

				//Şimdi SQL cümlelerimizi ekleyeceğimiz Statement objemizi tanımlayıp mevcut bağlantımızla ilişkilendirebiliriz.
				Statement stmt = conn.createStatement();

				stmt.addBatch("Insert Into Calisan Values (4, 'Fehmi Sözer', 'Testing', '01.07.1983', 1950)");

				stmt.addBatch("Insert Into Calisan Values (5, 'Leyla Uzungül', 'Testing', '15.12.1985', 1950)");

				stmt.addBatch("Update Calisan set Maas = 2000 Where ISIM = 'Zeki Duman' ");

				//Yığına (batch) eklediğimiz cümleleri artık toplu halde çalıştırabiliriz. Bunun için executeBatch() methodunu kullanacağız.
				stmt.executeBatch();
                                //Yaptığımız değişikliklerin veri tabanına kaydolması için commit()'leyebiliriz artık.
				conn.commit();

				//Şimdi de girdiğimiz değerleri tablodan çekip ekrana düzenli bir şekilde bastıralım
				 ResultSet resSet = stmt.executeQuery("Select * From Calisan"); //Sonuç setindeki her bir obje sorgudan gelen bir satırı temsil etmektedir.

				 ResultSetMetaData rsmetadata = resSet.getMetaData(); //Sonuç setimizin sütun bilgisini almak adına meta data bilgisini alalım.

				 int sütunSayisi = rsmetadata.getColumnCount();

				 //Sütun başlıklarını bastıralım.
				 for (int a = 0; a < sütunSayisi; a++)
				 {
				 	 System.out.print(rsmetadata.getColumnName(a + 1) + "\t");
				 }
				 System.out.println("\n=============================================================================================================");

				 //Sonuç setimizdeki her satır için bilgileri ekrana bastıralım
				while (resSet.next())
				{
					for (int j = 0; j < sütunSayisi; j++)
					{
						System.out.print(resSet.getString(j + 1) + "\t");
					}
					System.out.println();
				}

			}
			else
			{
				System.out.println(dbMData.getDatabaseProductVersion() + " batchUpdate'i desteklememektedir!...");
				System.exit(0);
			}

		}

		catch( SQLException e)
		{
			System.out.println("error: " + e.toString());
		}
		finally
		{
			conn.close();
		}

	}
}

Yukardaki kodu çalıştırdıktan sonraki veri tabanındaki “Calisan” tablosunun son görüntüsü aşağıdaki gibi olacaktır:
BatchUpdate

© 2011 Korhan Ozturk - Kişisel Yazılım Günlüğü Suffusion theme by Sayontan Sinha