JavaRush /جاوا بلاگ /Random-UR /JDBC یا جہاں سے یہ سب شروع ہوتا ہے۔
Viacheslav
سطح

JDBC یا جہاں سے یہ سب شروع ہوتا ہے۔

گروپ میں شائع ہوا۔
جدید دنیا میں ڈیٹا اسٹوریج کے بغیر کوئی راستہ نہیں ہے۔ اور ڈیٹا بیس کے ساتھ کام کرنے کی تاریخ بہت طویل عرصہ پہلے JDBC کی آمد کے ساتھ شروع ہوئی۔ میں کچھ یاد رکھنے کی تجویز پیش کرتا ہوں جس کے بغیر JDBC کے اوپر بنایا گیا کوئی جدید فریم ورک نہیں کر سکتا۔ اس کے علاوہ، ان کے ساتھ کام کرتے ہوئے بھی، بعض اوقات آپ کو "اپنی جڑوں میں واپس آنے" کا موقع درکار ہو سکتا ہے۔ مجھے امید ہے کہ یہ جائزہ بطور تعارف یا آپ کی یادداشت کو تازہ کرنے میں مدد کرے گا۔
JDBC یا جہاں سے یہ سب شروع ہوتا ہے - 1

تعارف

پروگرامنگ لینگویج کے بنیادی مقاصد میں سے ایک معلومات کو محفوظ کرنا اور اس پر کارروائی کرنا ہے۔ ڈیٹا سٹوریج کے کام کرنے کے طریقے کو بہتر طور پر سمجھنے کے لیے، ایپلی کیشنز کے تھیوری اور فن تعمیر پر تھوڑا وقت گزارنا قابل قدر ہے۔ مثال کے طور پر، آپ لٹریچر پڑھ سکتے ہیں، یعنی جوزف انجینو کی کتاب " سافٹ ویئر آرکیٹیکٹ کی ہینڈ بک: موثر آرکیٹیکٹ کو نافذ کر کے ایک کامیاب سافٹ ویئر آرکیٹیکٹ بنیں... "۔ جیسا کہ کہا گیا ہے، ایک مخصوص ڈیٹا ٹائر یا "ڈیٹا لیئر" ہے۔ اس میں ڈیٹا کو ذخیرہ کرنے کی جگہ (مثال کے طور پر ایس کیو ایل ڈیٹا بیس) اور ڈیٹا اسٹور کے ساتھ کام کرنے کے اوزار (مثال کے طور پر، JDBC، جس پر بات کی جائے گی) شامل ہے۔ مائیکروسافٹ ویب سائٹ پر ایک مضمون بھی ہے: " انفراسٹرکچر پرسسٹینس لیئر کو ڈیزائن کرنا ،" جو ڈیٹا ٹائر - پرسسٹینس لیئر سے ایک اضافی پرت کو الگ کرنے کے آرکیٹیکچرل حل کی وضاحت کرتا ہے۔ اس معاملے میں، ڈیٹا ٹائر خود ڈیٹا کے ذخیرہ کرنے کی سطح ہے، جبکہ پرسسٹینس لیئر ڈیٹا ٹائر کی سطح سے اسٹوریج سے ڈیٹا کے ساتھ کام کرنے کے لیے تجرید کی کچھ سطح ہے۔ پرسسٹینس لیئر میں "DAO" ٹیمپلیٹ یا مختلف ORMs شامل ہو سکتے ہیں۔ لیکن ORM ایک اور بحث کا موضوع ہے۔ جیسا کہ آپ پہلے ہی سمجھ چکے ہوں گے، ڈیٹا ٹائر پہلے ظاہر ہوا۔ JDK 1.1 کے وقت سے، JDBC (جاوا ڈیٹا بیس کنیکٹیویٹی - جاوا میں ڈیٹا بیس سے کنکشن) جاوا کی دنیا میں نمودار ہوا ہے۔ یہ Java SE میں شامل java.sql اور javax.sql پیکیجز کی شکل میں لاگو کردہ مختلف DBMSs کے ساتھ جاوا ایپلیکیشنز کے تعامل کا ایک معیار ہے:
JDBC یا جہاں سے یہ سب شروع ہوتا ہے - 2
اس معیار کی وضاحت " JSR 221 JDBC 4.1 API " کے ذریعہ کی گئی ہے۔ یہ تصریح ہمیں بتاتی ہے کہ JDBC API جاوا میں لکھے گئے پروگراموں سے متعلقہ ڈیٹا بیس تک پروگرامی رسائی فراہم کرتا ہے۔ یہ یہ بھی بتاتا ہے کہ JDBC API جاوا پلیٹ فارم کا حصہ ہے اور اس لیے Java SE اور Java EE میں شامل ہے۔ JDBC API دو پیکجوں میں فراہم کی گئی ہے: java.sql اور javax.sql۔ آئیے پھر ان سے واقف ہوں۔
JDBC یا جہاں سے یہ سب شروع ہوتا ہے - 3

کام کا آغاز

یہ سمجھنے کے لیے کہ JDBC API عمومی طور پر کیا ہے، ہمیں جاوا ایپلیکیشن کی ضرورت ہے۔ پروجیکٹ اسمبلی کے نظام میں سے کسی ایک کو استعمال کرنا سب سے آسان ہے۔ مثال کے طور پر، آئیے استعمال کریں Gradle ۔ آپ ایک مختصر جائزہ میں گریڈل کے بارے میں مزید پڑھ سکتے ہیں: " گریڈل کا مختصر تعارف "۔ پہلے، آئیے ایک نیا گریڈل پروجیکٹ شروع کریں۔ چونکہ گریڈل کی فعالیت کو پلگ ان کے ذریعے لاگو کیا جاتا ہے، ہمیں ابتدا کے لیے " گریڈل بلڈ انیٹ پلگ ان " استعمال کرنے کی ضرورت ہے:
gradle init --type java-application
اس کے بعد، آئیے بلڈ اسکرپٹ کو کھولتے ہیں - build.gradle فائل ، جو ہمارے پروجیکٹ اور اس کے ساتھ کام کرنے کا طریقہ بتاتی ہے۔ ہم " انحصار " بلاک میں دلچسپی رکھتے ہیں، جہاں انحصار بیان کیا جاتا ہے - یعنی وہ لائبریریاں/فریم ورک/api، جن کے بغیر ہم کام نہیں کر سکتے اور جن پر ہم انحصار کرتے ہیں۔ بطور ڈیفالٹ ہم کچھ اس طرح دیکھیں گے:
dependencies {
    // This dependency is found on compile classpath of this component and consumers.
    implementation 'com.google.guava:guava:26.0-jre'
    // Use JUnit test framework
    testImplementation 'junit:junit:4.12'
}
ہم یہاں یہ کیوں دیکھ رہے ہیں؟ یہ ہمارے پروجیکٹ کے انحصار ہیں، جو کہ گریڈل کے ذریعہ خود بخود پیدا ہوئے جب ہم نے پروجیکٹ بنایا۔ اور یہ بھی کہ امرود ایک علیحدہ لائبریری ہے جو جاوا SE کے ساتھ شامل نہیں ہے۔ JUnit بھی Java SE کے ساتھ شامل نہیں ہے۔ لیکن ہمارے پاس JDBC آؤٹ آف دی باکس ہے، یعنی یہ Java SE کا حصہ ہے۔ یہ پتہ چلتا ہے کہ ہمارے پاس JDBC ہے۔ زبردست. ہمیں اور کیا چاہیے؟ اس طرح کا ایک شاندار خاکہ ہے:
JDBC یا جہاں سے یہ سب شروع ہوتا ہے - 4
جیسا کہ ہم دیکھ سکتے ہیں، اور یہ منطقی ہے، ڈیٹا بیس ایک بیرونی جزو ہے جو جاوا SE کا مقامی نہیں ہے۔ اس کی وضاحت آسان ہے - ڈیٹا بیس کی ایک بڑی تعداد ہے اور آپ کسی کے ساتھ بھی کام کر سکتے ہیں۔ مثال کے طور پر، PostgreSQL، Oracle، MySQL، H2 ہے۔ ان میں سے ہر ایک ڈیٹا بیس ایک علیحدہ کمپنی کے ذریعہ فراہم کیا جاتا ہے جسے ڈیٹا بیس وینڈر کہتے ہیں۔ ہر ڈیٹا بیس کو اس کی اپنی پروگرامنگ زبان میں لکھا جاتا ہے (ضروری نہیں کہ جاوا)۔ جاوا ایپلیکیشن سے ڈیٹا بیس کے ساتھ کام کرنے کے قابل ہونے کے لیے، ڈیٹا بیس فراہم کرنے والا ایک خصوصی ڈرائیور لکھتا ہے، جو اس کا اپنا امیج اڈاپٹر ہے۔ اس طرح کے JDBC مطابقت رکھنے والے (یعنی جن کے پاس JDBC ڈرائیور ہے) کو "JDBC- Compliant Database" بھی کہا جاتا ہے۔ یہاں ہم کمپیوٹر آلات کے ساتھ مشابہت کھینچ سکتے ہیں۔ مثال کے طور پر، ایک نوٹ پیڈ میں ایک "پرنٹ" بٹن ہوتا ہے۔ جب بھی آپ اسے دباتے ہیں، پروگرام آپریٹنگ سسٹم کو بتاتا ہے کہ نوٹ پیڈ ایپلیکیشن پرنٹ کرنا چاہتی ہے۔ اور آپ کے پاس ایک پرنٹر ہے۔ اپنے آپریٹنگ سسٹم کو Canon یا HP پرنٹر کے ساتھ یکساں طور پر بات چیت کرنا سکھانے کے لیے، آپ کو مختلف ڈرائیورز کی ضرورت ہوگی۔ لیکن آپ کے لیے، بطور صارف، کچھ نہیں بدلے گا۔ آپ اب بھی وہی بٹن دبائیں گے۔ JDBC کے ساتھ بھی۔ آپ ایک ہی کوڈ چلا رہے ہیں، یہ صرف اتنا ہے کہ مختلف ڈیٹا بیس ہوڈ کے نیچے چل رہے ہیں۔ میرے خیال میں یہ ایک بہت واضح نقطہ نظر ہے۔ اس طرح کا ہر JDBC ڈرائیور کسی نہ کسی قسم کا نمونہ، لائبریری، جار فائل ہے۔ یہ ہمارے منصوبے کا انحصار ہے۔ مثال کے طور پر، ہم ڈیٹا بیس " H2 ڈیٹا بیس " کو منتخب کر سکتے ہیں اور پھر ہمیں اس طرح کا انحصار شامل کرنے کی ضرورت ہے:
dependencies {
    implementation 'com.h2database:h2:1.4.197'
انحصار کیسے تلاش کیا جائے اور اسے کیسے بیان کیا جائے ڈیٹا بیس فراہم کنندہ کی سرکاری ویب سائٹس یا " Maven Central " پر اشارہ کیا گیا ہے۔ JDBC ڈرائیور ڈیٹا بیس نہیں ہے، جیسا کہ آپ سمجھتے ہیں۔ لیکن وہ اس کے لیے صرف رہنما ہے۔ لیکن " میموری ڈیٹا بیس میں " جیسی چیز موجود ہے ۔ یہ وہ ڈیٹا بیس ہیں جو آپ کی درخواست کی زندگی بھر کے لیے میموری میں موجود ہیں۔ عام طور پر، یہ اکثر جانچ یا تربیت کے مقاصد کے لیے استعمال ہوتا ہے۔ یہ آپ کو مشین پر علیحدہ ڈیٹا بیس سرور انسٹال کرنے سے بچنے کی اجازت دیتا ہے۔ جو ہمارے لیے جے ڈی بی سی سے واقفیت کے لیے بہت موزوں ہے۔ تو ہمارا سینڈ باکس تیار ہے اور ہم شروع کرتے ہیں۔
JDBC یا جہاں سے یہ سب شروع ہوتا ہے - 5

کنکشن

لہذا، ہمارے پاس JDBC ڈرائیور ہے، ہمارے پاس JDBC API ہے۔ جیسا کہ ہمیں یاد ہے، JDBC کا مطلب Java DataBase Connectivity ہے۔ لہذا، یہ سب کنیکٹیویٹی سے شروع ہوتا ہے - کنکشن قائم کرنے کی صلاحیت۔ اور کنکشن کنکشن ہے۔ آئیے JDBC تفصیلات کے متن کی طرف دوبارہ رجوع کریں اور مندرجات کے جدول کو دیکھیں۔ باب " باب 4 جائزہ " (جائزہ) میں ہم سیکشن " 4.1 کنکشن قائم کرنا " (کنکشن قائم کرنا) کی طرف رجوع کرتے ہیں یہ کہا جاتا ہے کہ ڈیٹا بیس سے جڑنے کے دو طریقے ہیں:
  • ڈرائیور مینیجر کے ذریعے
  • ڈیٹا سورس کے ذریعے
آئیے ڈرائیور مینیجر سے نمٹتے ہیں۔ جیسا کہ کہا گیا ہے، ڈرائیور مینجر آپ کو مخصوص یو آر ایل پر ڈیٹا بیس سے منسلک ہونے کی اجازت دیتا ہے، اور JDBC ڈرائیورز کو بھی لوڈ کرتا ہے جو اسے CLASSPATH میں ملا تھا (اور اس سے پہلے، JDBC 4.0 سے پہلے، آپ کو ڈرائیور کی کلاس خود لوڈ کرنا پڑتی تھی)۔ ڈیٹا بیس سے جڑنے کے بارے میں ایک الگ باب "باب 9 کنکشنز" ہے۔ ہم اس میں دلچسپی رکھتے ہیں کہ ڈرائیور مینجر کے ذریعے کنکشن کیسے حاصل کیا جائے، لہذا ہم سیکشن "9.3 The DriverManager Class" میں دلچسپی رکھتے ہیں۔ یہ بتاتا ہے کہ ہم ڈیٹا بیس تک کیسے رسائی حاصل کر سکتے ہیں:
Connection con = DriverManager.getConnection(url, user, passwd);
پیرامیٹرز ہمارے منتخب کردہ ڈیٹا بیس کی ویب سائٹ سے لیے جا سکتے ہیں۔ ہمارے معاملے میں، یہ H2 - " H2 چیٹ شیٹ " ہے۔ آئیے Gradle کی تیار کردہ AppTest کلاس کی طرف چلتے ہیں۔ اس میں JUnit ٹیسٹ ہوتے ہیں۔ JUnit ٹیسٹ ایک ایسا طریقہ ہے جو تشریح کے ساتھ نشان زد ہوتا ہے @Test۔ یونٹ ٹیسٹ اس جائزے کا موضوع نہیں ہیں، اس لیے ہم صرف اپنے آپ کو اس سمجھ تک محدود رکھیں گے کہ یہ ایک خاص طریقے سے بیان کیے گئے طریقے ہیں، جن کا مقصد کسی چیز کی جانچ کرنا ہے۔ JDBC تفصیلات اور H2 ویب سائٹ کے مطابق، ہم چیک کریں گے کہ ہمیں ڈیٹا بیس سے کنکشن ملا ہے۔ آئیے کنکشن حاصل کرنے کا طریقہ لکھتے ہیں:
private Connection getNewConnection() throws SQLException {
	String url = "jdbc:h2:mem:test";
	String user = "sa";
	String passwd = "sa";
	return DriverManager.getConnection(url, user, passwd);
}
اب آئیے اس طریقہ کے لیے ایک ٹیسٹ لکھتے ہیں جو یہ چیک کرے گا کہ کنکشن واقعتاً قائم ہے:
@Test
public void shouldGetJdbcConnection() throws SQLException {
	try(Connection connection = getNewConnection()) {
		assertTrue(connection.isValid(1));
		assertFalse(connection.isClosed());
	}
}
یہ ٹیسٹ، جب عمل میں لایا جائے گا، اس بات کی تصدیق کرے گا کہ نتیجہ کنکشن درست ہے (درست طریقے سے بنایا گیا ہے) اور یہ بند نہیں ہے۔ وسائل کے ساتھ کوشش کر کے ہم وسائل جاری کریں گے جب ہمیں ان کی مزید ضرورت نہیں ہوگی۔ یہ ہمیں ٹوٹتے ہوئے کنکشن اور میموری لیک ہونے سے بچائے گا۔ چونکہ ڈیٹا بیس کے ساتھ کسی بھی عمل کے لیے کنکشن کی ضرورت ہوتی ہے، آئیے ٹیسٹ کے شروع میں @Test کے ساتھ کنکشن کے نشان والے باقی ٹیسٹ طریقے فراہم کرتے ہیں، جسے ہم ٹیسٹ کے بعد جاری کریں گے۔ ایسا کرنے کے لیے، ہمیں دو تشریحات کی ضرورت ہے: @Before اور @After آئیے AppTest کلاس میں ایک نیا فیلڈ شامل کریں جو JDBC کنکشن کو ٹیسٹ کے لیے محفوظ کرے گا:
private static Connection connection;
اور آئیے نئے طریقے شامل کریں:
@Before
public void init() throws SQLException {
	connection = getNewConnection();
}
@After
public void close() throws SQLException {
	connection.close();
}
اب، کسی بھی جانچ کے طریقہ کار کے پاس JDBC کنکشن ہونے کی ضمانت ہے اور اسے ہر بار خود بنانا نہیں پڑتا ہے۔
JDBC یا جہاں سے یہ سب شروع ہوتا ہے - 6

بیانات

اگلا ہم بیانات یا تاثرات میں دلچسپی رکھتے ہیں۔ وہ باب " باب 13 بیانات " میں دستاویزات میں بیان کیے گئے ہیں ۔ سب سے پہلے، یہ کہتا ہے کہ بیانات کی کئی اقسام یا اقسام ہیں:
  • بیان: SQL اظہار جس میں کوئی پیرامیٹرز نہیں ہیں۔
  • PreparedStatement : ان پٹ پیرامیٹرز پر مشتمل ایس کیو ایل کا تیار کردہ بیان
  • کال ایبل اسٹیٹمنٹ: ایس کیو ایل ایکسپریشن جس میں ایس کیو ایل اسٹورڈ پروسیجرز سے ریٹرن ویلیو حاصل کرنے کی صلاحیت ہے۔
لہذا، ایک کنکشن ہونے کے بعد، ہم اس کنکشن کے فریم ورک کے اندر کچھ درخواستوں کو انجام دے سکتے ہیں۔ لہذا، یہ منطقی ہے کہ ہم ابتدائی طور پر کنکشن سے SQL اظہار کی مثال حاصل کریں۔ آپ کو ایک ٹیبل بنا کر شروع کرنے کی ضرورت ہے۔ آئیے ٹیبل بنانے کی درخواست کو String متغیر کے طور پر بیان کرتے ہیں۔ یہ کیسے کرنا ہے؟ آئیے کچھ ٹیوٹوریل جیسے " sqltutorial.org "، " sqlbolt.com "، " postgresqltutorial.com "، " codecademy.com " استعمال کریں۔ آئیے، مثال کے طور پر، khanacademy.org پر SQL کورس کی ایک مثال استعمال کریں ۔ آئیے ڈیٹا بیس میں اظہار کو انجام دینے کے لئے ایک طریقہ شامل کریں:
private int executeUpdate(String query) throws SQLException {
	Statement statement = connection.createStatement();
	// Для Insert, Update, Delete
	int result = statement.executeUpdate(query);
	return result;
}
آئیے پچھلے طریقہ کو استعمال کرتے ہوئے ٹیسٹ ٹیبل بنانے کے لیے ایک طریقہ شامل کریں:
private void createCustomerTable() throws SQLException {
	String customerTableQuery = "CREATE TABLE customers " +
                "(id INTEGER PRIMARY KEY, name TEXT, age INTEGER)";
	String customerEntryQuery = "INSERT INTO customers " +
                "VALUES (73, 'Brian', 33)";
	executeUpdate(customerTableQuery);
	executeUpdate(customerEntryQuery);
}
اب آئیے اس کی جانچ کریں:
@Test
public void shouldCreateCustomerTable() throws SQLException {
	createCustomerTable();
	connection.createStatement().execute("SELECT * FROM customers");
}
اب آئیے درخواست پر عمل کریں، اور یہاں تک کہ پیرامیٹر کے ساتھ:
@Test
public void shouldSelectData() throws SQLException {
 	createCustomerTable();
 	String query = "SELECT * FROM customers WHERE name = ?";
	PreparedStatement statement = connection.prepareStatement(query);
	statement.setString(1, "Brian");
	boolean hasResult = statement.execute();
	assertTrue(hasResult);
}
JDBC PreparedStatement کے لیے نامزد کردہ پیرامیٹرز کو سپورٹ نہیں کرتا ہے، اس لیے پیرامیٹرز خود سوالات کے ذریعے بتائے جاتے ہیں، اور قدر کی وضاحت کر کے ہم سوالیہ اشاریہ کی نشاندہی کرتے ہیں (1 سے شروع ہوتا ہے، صفر سے نہیں)۔ آخری ٹیسٹ میں ہمیں اس بات کے اشارے کے طور پر صحیح موصول ہوا کہ آیا نتیجہ آیا ہے۔ لیکن JDBC API میں استفسار کے نتیجے کی نمائندگی کیسے کی جاتی ہے؟ اور اسے رزلٹ سیٹ کے طور پر پیش کیا جاتا ہے۔
JDBC یا جہاں سے یہ سب شروع ہوتا ہے - 7

نتیجہ سیٹ

رزلٹ سیٹ کا تصور JDBC API تفصیلات میں باب "CHAPTER 15 Result Sets" میں بیان کیا گیا ہے۔ سب سے پہلے، یہ کہتا ہے کہ ResultSet پھانسی کی گئی سوالات کے نتائج کو بازیافت کرنے اور ان میں ہیرا پھیری کے طریقے فراہم کرتا ہے۔ یعنی، اگر عمل کرنے کا طریقہ ہمارے پاس درست ہو گیا، تو ہم رزلٹ سیٹ حاصل کر سکتے ہیں۔ آئیے کال کو createCustomerTable() میتھڈ میں init میتھڈ میں منتقل کرتے ہیں، جسے @Before کے بطور نشان زد کیا گیا ہے۔ اب ہم اپنے shouldSelectData ٹیسٹ کو حتمی شکل دیتے ہیں:
@Test
public void shouldSelectData() throws SQLException {
	String query = "SELECT * FROM customers WHERE name = ?";
	PreparedStatement statement = connection.prepareStatement(query);
	statement.setString(1, "Brian");
	boolean hasResult = statement.execute();
	assertTrue(hasResult);
	// Обработаем результат
	ResultSet resultSet = statement.getResultSet();
	resultSet.next();
	int age = resultSet.getInt("age");
	assertEquals(33, age);
}
یہاں یہ بات قابل غور ہے کہ اگلا ایک طریقہ ہے جو نام نہاد "کرسر" کو منتقل کرتا ہے۔ رزلٹ سیٹ میں کرسر کسی قطار کی طرف اشارہ کرتا ہے۔ اس طرح، کسی لائن کو پڑھنے کے لیے، آپ کو اس پر یہی کرسر رکھنا ہوگا۔ جب کرسر کو منتقل کیا جاتا ہے، کرسر منتقل کرنے کا طریقہ درست ہو جاتا ہے اگر کرسر درست ہے (درست، درست)، یعنی یہ ڈیٹا کی طرف اشارہ کرتا ہے۔ اگر یہ غلط لوٹتا ہے، تو کوئی ڈیٹا نہیں ہے، یعنی کرسر ڈیٹا کی طرف اشارہ نہیں کر رہا ہے۔ اگر ہم غلط کرسر کے ساتھ ڈیٹا حاصل کرنے کی کوشش کرتے ہیں، تو ہمیں خرابی ملے گی: کوئی ڈیٹا دستیاب نہیں ہے یہ بھی دلچسپ ہے کہ ResultSet کے ذریعے آپ اپ ڈیٹ کر سکتے ہیں یا قطاریں بھی داخل کر سکتے ہیں:
@Test
public void shouldInsertInResultSet() throws SQLException {
	Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
	ResultSet resultSet = statement.executeQuery("SELECT * FROM customers");
	resultSet.moveToInsertRow();
	resultSet.updateLong("id", 3L);
	resultSet.updateString("name", "John");
	resultSet.updateInt("age", 18);
	resultSet.insertRow();
	resultSet.moveToCurrentRow();
}

رو سیٹ

ResultSet کے علاوہ، JDBC نے RowSet کا تصور متعارف کرایا ہے۔ آپ یہاں مزید پڑھ سکتے ہیں: " JDBC بنیادی باتیں: RowSet آبجیکٹ کا استعمال "۔ استعمال کے مختلف تغیرات ہیں۔ مثال کے طور پر، سب سے آسان کیس اس طرح نظر آسکتا ہے:
@Test
public void shouldUseRowSet() throws SQLException {
 	JdbcRowSet jdbcRs = new JdbcRowSetImpl(connection);
 	jdbcRs.setCommand("SELECT * FROM customers");
	jdbcRs.execute();
	jdbcRs.next();
	String name = jdbcRs.getString("name");
	assertEquals("Brian", name);
}
جیسا کہ آپ دیکھ سکتے ہیں، RowSet بیان کی ایک علامت (ہم نے اس کے ذریعے کمانڈ کی وضاحت کی ہے) اور executed کمانڈ کی طرح ہے۔ اس کے ذریعے ہم کرسر کو کنٹرول کرتے ہیں (اگلے طریقے سے کال کرکے) اور اس سے ڈیٹا حاصل کرتے ہیں۔ نہ صرف یہ نقطہ نظر دلچسپ ہے، بلکہ ممکنہ نفاذ بھی۔ مثال کے طور پر، CachedRowSet. یہ "منقطع" ہے (یعنی یہ ڈیٹا بیس سے مستقل کنکشن استعمال نہیں کرتا ہے) اور ڈیٹا بیس کے ساتھ واضح ہم آہنگی کی ضرورت ہے:
CachedRowSet jdbcRsCached = new CachedRowSetImpl();
jdbcRsCached.acceptChanges(connection);
آپ اوریکل ویب سائٹ پر ٹیوٹوریل میں مزید پڑھ سکتے ہیں: " CachedRowSetObjects کا استعمال کرنا
JDBC یا جہاں سے یہ سب شروع ہوتا ہے - 8

میٹا ڈیٹا

استفسارات کے علاوہ، ڈیٹا بیس سے کنکشن (یعنی کنکشن کلاس کی ایک مثال) میٹا ڈیٹا تک رسائی فراہم کرتا ہے - ڈیٹا اس بارے میں کہ ہمارے ڈیٹا بیس کو کس طرح ترتیب اور منظم کیا جاتا ہے۔ لیکن پہلے، آئیے چند اہم نکات کا ذکر کرتے ہیں: ہمارے ڈیٹا بیس سے منسلک ہونے کا URL: "jdbc:h2:mem:test"۔ test ہمارے ڈیٹا بیس کا نام ہے۔ JDBC API کے لیے، یہ ایک ڈائریکٹری ہے۔ اور نام بڑے حروف میں ہوگا یعنی TEST۔ H2 کے لیے ڈیفالٹ سکیما عوامی ہے۔ اب، آئیے ایک ٹیسٹ لکھتے ہیں جو تمام صارف کی میزیں دکھاتا ہے۔ رواج کیوں؟ کیونکہ ڈیٹا بیس میں نہ صرف صارف کی میزیں ہوتی ہیں (جنہیں ہم نے خود تخلیق ٹیبل ایکسپریشنز کا استعمال کرتے ہوئے بنایا ہے) بلکہ سسٹم ٹیبلز بھی ہوتے ہیں۔ وہ ڈیٹا بیس کی ساخت کے بارے میں سسٹم کی معلومات کو ذخیرہ کرنے کے لیے ضروری ہیں۔ ہر ڈیٹا بیس اس طرح کے سسٹم ٹیبل کو مختلف طریقے سے محفوظ کر سکتا ہے۔ مثال کے طور پر، H2 میں وہ " INFORMATION_SCHEMA " اسکیما میں محفوظ ہیں۔ دلچسپ بات یہ ہے کہ انفارمیشن اسکیما ایک عام طریقہ ہے، لیکن اوریکل نے ایک مختلف راستہ اختیار کیا۔ آپ یہاں مزید پڑھ سکتے ہیں: " INFORMATION_SCHEMA اور Oracle "۔ آئیے ایک ٹیسٹ لکھتے ہیں جو صارف کی میزوں پر میٹا ڈیٹا وصول کرتا ہے:
@Test
public void shoudGetMetadata() throws SQLException {
	// У нас URL = "jdbc:h2:mem:test", где test - название БД
	// Название БД = catalog
	DatabaseMetaData metaData = connection.getMetaData();
	ResultSet result = metaData.getTables("TEST", "PUBLIC", "%", null);
	List<String> tables = new ArrayList<>();
	while(result.next()) {
		tables.add(result.getString(2) + "." + result.getString(3));
	}
	assertTrue(tables.contains("PUBLIC.CUSTOMERS"));
}
JDBC یا جہاں سے یہ سب شروع ہوتا ہے - 9

کنکشن پول

JDBC تفصیلات میں کنکشن پول میں "باب 11 کنکشن پولنگ" نامی ایک سیکشن ہے۔ یہ کنکشن پول کی ضرورت کا بنیادی جواز بھی فراہم کرتا ہے۔ ہر Coonection ڈیٹا بیس سے ایک جسمانی تعلق ہے۔ اس کی تخلیق اور بندش کافی "مہنگا" کام ہے۔ JDBC صرف کنکشن پولنگ API فراہم کرتا ہے۔ لہذا، عمل درآمد کا انتخاب ہمارے پاس رہتا ہے. مثال کے طور پر، اس طرح کے نفاذ میں HikariCP شامل ہیں ۔ اس کے مطابق، ہمیں اپنے پراجیکٹ انحصار میں ایک پول شامل کرنے کی ضرورت ہوگی:
dependencies {
    implementation 'com.h2database:h2:1.4.197'
    implementation 'com.zaxxer:HikariCP:3.3.1'
    testImplementation 'junit:junit:4.12'
}
اب ہمیں کسی نہ کسی طرح اس پول کو استعمال کرنے کی ضرورت ہے۔ ایسا کرنے کے لیے، آپ کو ڈیٹا سورس کو شروع کرنے کی ضرورت ہے، جسے ڈیٹا سورس بھی کہا جاتا ہے:
private DataSource getDatasource() {
	HikariConfig config = new HikariConfig();
	config.setUsername("sa");
	config.setPassword("sa");
	config.setJdbcUrl("jdbc:h2:mem:test");
	DataSource ds = new HikariDataSource(config);
	return ds;
}
اور آئیے پول سے کنکشن حاصل کرنے کے لیے ایک ٹیسٹ لکھیں:
@Test
public void shouldGetConnectionFromDataSource() throws SQLException {
	DataSource datasource = getDatasource();
	try (Connection con = datasource.getConnection()) {
		assertTrue(con.isValid(1));
	}
}
JDBC یا جہاں سے یہ سب شروع ہوتا ہے - 10

لین دین

JDBC کے بارے میں سب سے دلچسپ چیزوں میں سے ایک لین دین ہے۔ JDBC تفصیلات میں، انہیں باب "باب 10 ٹرانزیکشنز" تفویض کیا گیا ہے۔ سب سے پہلے، یہ سمجھنے کے قابل ہے کہ لین دین کیا ہے۔ ایک ٹرانزیکشن ڈیٹا پر منطقی طور پر مشترکہ ترتیب وار کارروائیوں کا ایک گروپ ہے، جس پر مجموعی طور پر عملدرآمد یا منسوخ کیا گیا ہے۔ JDBC استعمال کرتے وقت لین دین کب شروع ہوتا ہے؟ جیسا کہ تصریح میں کہا گیا ہے، یہ براہ راست JDBC ڈرائیور کے ذریعے ہینڈل کیا جاتا ہے۔ لیکن عام طور پر، ایک نیا ٹرانزیکشن اس وقت شروع ہوتا ہے جب موجودہ SQL سٹیٹمنٹ کو ٹرانزیکشن کی ضرورت ہوتی ہے اور ٹرانزیکشن ابھی تک نہیں بنی ہے۔ لین دین کب ختم ہوتا ہے؟ یہ آٹو کمٹ وصف کے ذریعہ کنٹرول کیا جاتا ہے۔ اگر آٹوکمیٹ فعال ہے تو، ایس کیو ایل اسٹیٹمنٹ کے "مکمل" ہونے کے بعد لین دین مکمل ہو جائے گا۔ کیا "ہو گیا" کا مطلب SQL اظہار کی قسم پر منحصر ہے:
  • ڈیٹا مینیپولیشن لینگویج، جسے DML بھی کہا جاتا ہے (انسرٹ، اپ ڈیٹ، ڈیلیٹ)
    کارروائی مکمل ہوتے ہی لین دین مکمل ہو جاتا ہے۔
  • بیانات منتخب کریں
    جب رزلٹ سیٹ بند ہو جائے تو ٹرانزیکشن مکمل ہو جاتی ہے ( ResultSet#close )
  • CallableStatement اور اظہارات جو ایک سے زیادہ نتائج دیتے ہیں
    جب تمام متعلقہ ResultSets بند کر دیے جاتے ہیں اور تمام آؤٹ پٹ موصول ہو جاتے ہیں (بشمول اپ ڈیٹس کی تعداد)
بالکل اسی طرح JDBC API برتاؤ کرتا ہے۔ ہمیشہ کی طرح، آئیے اس کے لیے ایک ٹیسٹ لکھتے ہیں:
@Test
public void shouldCommitTransaction() throws SQLException {
	connection.setAutoCommit(false);
	String query = "INSERT INTO customers VALUES (1, 'Max', 20)";
	connection.createStatement().executeUpdate(query);
	connection.commit();
	Statement statement = connection.createStatement();
 	statement.execute("SELECT * FROM customers");
	ResultSet resultSet = statement.getResultSet();
	int count = 0;
	while(resultSet.next()) {
		count++;
	}
	assertEquals(2, count);
}
یہ آسان ہے. لیکن یہ سچ ہے جب تک کہ ہمارے پاس صرف ایک لین دین ہے۔ جب ان میں سے متعدد ہوں تو کیا کریں؟ انہیں ایک دوسرے سے الگ تھلگ رہنے کی ضرورت ہے۔ لہذا، آئیے لین دین کی تنہائی کی سطحوں کے بارے میں بات کرتے ہیں اور JDBC ان سے کیسے نمٹتا ہے۔
JDBC یا جہاں سے یہ سب شروع ہوتا ہے - 11

موصلیت کی سطح

آئیے JDBC تفصیلات کے ذیلی حصے "10.2 ٹرانزیکشن آئسولیشن لیولز" کو کھولتے ہیں۔ یہاں، آگے بڑھنے سے پہلے، میں ACID جیسی چیز کے بارے میں یاد رکھنا چاہوں گا۔ ACID لین دین کے نظام کی ضروریات کو بیان کرتا ہے۔
  • جوہری:
    کوئی بھی لین دین جزوی طور پر سسٹم کے ساتھ وابستہ نہیں ہوگا۔ یا تو اس کے تمام ذیلی کام انجام دیئے جائیں گے، یا کوئی بھی انجام نہیں دیا جائے گا۔
  • مستقل مزاجی:
    ہر کامیاب لین دین، تعریف کے مطابق، صرف درست نتائج ریکارڈ کرتا ہے۔
  • الگ تھلگ:
    جب کوئی لین دین چل رہا ہو، ہم وقتی لین دین سے اس کے نتائج کو متاثر نہیں کرنا چاہیے۔
  • پائیداری:
    اگر کوئی لین دین کامیابی کے ساتھ مکمل ہو جاتا ہے، تو اس میں کی گئی تبدیلیاں کسی ناکامی کی وجہ سے کالعدم نہیں ہوں گی۔
لین دین کی تنہائی کی سطح کے بارے میں بات کرتے وقت، ہم "تنہائی" کی ضرورت کے بارے میں بات کر رہے ہیں۔ تنہائی ایک مہنگی ضرورت ہے، لہذا حقیقی ڈیٹا بیس میں ایسے طریقے ہیں جو کسی لین دین کو مکمل طور پر الگ نہیں کرتے ہیں (دوبارہ پڑھنے کے قابل تنہائی کی سطح اور کم)۔ ویکیپیڈیا میں ان مسائل کی بہترین وضاحت ہے جو لین دین کے ساتھ کام کرتے وقت پیدا ہو سکتی ہیں۔ یہ یہاں مزید پڑھنے کے قابل ہے: " لین دین کا استعمال کرتے ہوئے متوازی رسائی کے مسائل ۔" اس سے پہلے کہ ہم اپنا ٹیسٹ لکھیں، آئیے اپنی گریڈل بلڈ اسکرپٹ کو تھوڑا سا تبدیل کریں: پراپرٹیز کے ساتھ ایک بلاک شامل کریں، یعنی ہمارے پروجیکٹ کی سیٹنگز کے ساتھ:
ext {
    h2Version = '1.3.176' // 1.4.177
    hikariVersion = '3.3.1'
    junitVersion = '4.12'
}
اگلا، ہم اسے ورژن میں استعمال کرتے ہیں:
dependencies {
    implementation "com.h2database:h2:${h2Version}"
    implementation "com.zaxxer:HikariCP:${hikariVersion}"
    testImplementation "junit:junit:${junitVersion}"
}
آپ نے دیکھا ہو گا کہ h2 ورژن کم ہو گیا ہے۔ ہم بعد میں دیکھیں گے کیوں۔ تو آپ تنہائی کی سطحوں کو کیسے لاگو کرتے ہیں؟ آئیے فوراً ایک چھوٹی عملی مثال دیکھتے ہیں:
@Test
public void shouldGetReadUncommited() throws SQLException {
	Connection first = getNewConnection();
	assertTrue(first.getMetaData().supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED));
	first.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
	first.setAutoCommit(false);
	// Транзакиця на подключение. Поэтому первая транзакция с ReadUncommited вносит изменения
	String insertQuery = "INSERT INTO customers VALUES (5, 'Max', 15)";
	first.createStatement().executeUpdate(insertQuery);
	// Вторая транзакция пытается их увидеть
	int rowCount = 0;
	JdbcRowSet jdbcRs = new JdbcRowSetImpl(getNewConnection());
	jdbcRs.setCommand("SELECT * FROM customers");
	jdbcRs.execute();
	while (jdbcRs.next()) {
		rowCount++;
	}
	assertEquals(2, rowCount);
}
دلچسپ بات یہ ہے کہ یہ ٹیسٹ ایسے وینڈر پر ناکام ہو سکتا ہے جو TRANSACTION_READ_UNCOMMITTED (مثال کے طور پر، sqlite یا HSQL) کو سپورٹ نہیں کرتا ہے۔ اور لین دین کی سطح شاید کام نہ کرے۔ یاد رکھیں ہم نے H2 ڈیٹا بیس ڈرائیور کے ورژن کا اشارہ کیا تھا؟ اگر ہم اسے h2Version = '1.4.177' اور اس سے اوپر کرتے ہیں، تو READ UNCOMMITTED کام کرنا بند کر دے گا، حالانکہ ہم نے کوڈ کو تبدیل نہیں کیا ہے۔ اس سے ایک بار پھر ثابت ہوتا ہے کہ وینڈر اور ڈرائیور ورژن کا انتخاب صرف خطوط نہیں ہے، یہ دراصل اس بات کا تعین کرے گا کہ آپ کی درخواستوں پر عمل کیسے کیا جائے گا۔ آپ ورژن 1.4.177 میں اس رویے کو ٹھیک کرنے کے طریقہ کے بارے میں پڑھ سکتے ہیں اور یہ کیسے اعلی ورژن میں کام نہیں کرتا ہے: " سپورٹ READ UNCOMMITTED Isolation level in MVStore موڈ
JDBC یا جہاں سے یہ سب شروع ہوتا ہے - 12

نیچے کی لکیر

جیسا کہ ہم دیکھ سکتے ہیں، JDBC ڈیٹا بیس کے ساتھ کام کرنے کے لیے جاوا کے ہاتھ میں ایک طاقتور ٹول ہے۔ مجھے امید ہے کہ یہ مختصر جائزہ آپ کو نقطہ آغاز دینے یا آپ کی یادداشت کو تازہ کرنے میں مدد کرے گا۔ ٹھیک ہے، ناشتے کے لیے، کچھ اضافی مواد: #ویاچسلاو
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION