Skip to content

6. مدیریت پایگاه داده با API JDBC

6.1. اطلاعات عمومی

بانک‌های اطلاعاتی زیادی در بازار موجود هستند. برای استانداردسازی دسترسی به پایگاه‌های داده در ویندوز MS، مایکروسافت رابطی به نام ODBC (Open DataBase Connectivity) توسعه داده است. این لایه ویژگی‌های خاص هر پایگاه داده را پشت یک رابط استاندارد پنهان می‌کند. زیر ویندوز MS، درایورهای ODBC متعددی وجود دارند که دسترسی به پایگاه‌های داده را تسهیل می‌کنند. در اینجا، به عنوان مثال، فهرستی از درایورهای ODBC نصب‌شده بر روی یک ماشین Win95 آورده شده است:

Image

یک برنامه کاربردی که به این درایورها متکی است می‌تواند بدون نیاز به بازنویسی، از هر یک از پایگاه‌های داده فوق استفاده کند.

Image

برای اینکه برنامه‌های جاوا نیز بتوانند از رابط ODBC بهره‌مند شوند، شرکت Sun رابط JDBC (ارتباط‌پذیری Java DataBase) را ایجاد کرده است که به‌عنوان واسطه بین برنامه جاوا و رابط ODBC عمل خواهد کرد:

Image

6.2. مراحل کلیدی در عملیات پایگاه داده

6.2.1. مقدمه

در یک برنامه JAVA که از رابط JDBC برای اتصال به یک پایگاه داده استفاده می‌کند، مراحل زیر معمولاً درگیر هستند:

  1. اتصال به پایگاه داده
  2. ارسال پرس‌وجوهای SQL به پایگاه داده
  3. دریافت و پردازش نتایج این پرس‌وجوها
  4. بستن اتصال

مراحل ۲ و ۳ به طور مکرر انجام می‌شوند و اتصال تنها زمانی قطع می‌شود که از پایگاه داده به طور کامل استفاده شده باشد. این یک الگوی نسبتاً استاندارد است که اگر به صورت تعاملی از یک پایگاه داده استفاده کرده باشید، ممکن است با آن آشنا باشید. اکنون هر یک از این مراحل را با استفاده از یک مثال به تفصیل توضیح خواهیم داد. یک پایگاه داده به نام ACCESS را در نظر بگیرید که به اختصار ARTICLES نامیده می‌شود و ساختار زیر را دارد:

name
نوع
code
کد آیتم ۴ کاراکتری
nom
نام آن (رشتهٔ کاراکتری)
prix
قیمت آن (واقعی)
stock_actu
موجودی فعلی آن (اعداد صحیح)
stock_mini
حداقل سطح موجودی (اعداد صحیح) که کالا باید پس از کاهش از آن دوباره تأمین شود

این پایگاه داده ACCESS به‌عنوان منبع داده «کاربر» در مدیر پایگاه داده ODBC تعریف شده است:

Image

Image

ویژگی‌های آن با استفاده از دکمه Configurer به شرح زیر مشخص می‌شوند:

Image

این پیکربندی اساساً شامل مرتبط کردن پایگاه داده ARTICLES با فایل Access متناظر articles.mdb است. پس از انجام این کار، پایگاه داده ARTICLES برای برنامه‌هایی که از رابط ODBC استفاده می‌کنند، قابل دسترسی است.

6.2.2. مرحله اتصال

برای دسترسی به یک پایگاه داده، یک برنامه جاوا باید ابتدا یک اتصال برقرار کند. این کار با استفاده از روش کلاس زیر انجام می‌شود:

Connection DriverManager.getConnection(String URL, String id, String mdp)

با

DriverManager: یک کلاس جاوا که حاوی لیست درایورهای در دسترس برای برنامه است

Connection: یک کلاس جاوا که ارتباطی بین برنامه و پایگاه داده برقرار می‌کند، از طریق آن برنامه پرس‌وجوها را به پایگاه داده ارسال می‌کند SQL و نتایج را دریافت می‌کند

URL: نامی که پایگاه داده را شناسایی می‌کند. این نام مشابه URL در اینترنت است. به همین دلیل بخشی از کلاس URL را تشکیل می‌دهد. با این حال، اینترنت در این مورد هیچ نقشی ندارد. URL شکل زیر را دارد:

jdbc:nom_du_pilote:nom_de_la_source;param=val1;param2=val2

در مثال‌های ما، که در آن فقط از درایورهای ODBC استفاده خواهیم کرد، نام درایور odbc است. بخش سوم URL شامل نام منبع به همراه هرگونه پارامتر است. در مثال‌های ما، این‌ها منابع داده ODBC هستند که توسط سیستم شناسایی می‌شوند. بنابراین، URL برای منبع داده Articles که قبلاً تعریف شده است، خواهد بود

jdbc:odbc:مقالات

id: شناسه کاربری (ورود)

mdp: رمز عبور کاربر

خلاصه اینکه، برنامه به یک پایگاه داده متصل می‌شود:

  • که با نامی (URL) شناسایی می‌شود
  • زیر اعتبارنامه‌های کاربر (نام کاربری، رمز عبور)

اگر این سه پارامتر صحیح باشند و اگر درایوری که قادر به ایجاد اتصال بین برنامه جاوا و پایگاه داده مشخص‌شده است وجود داشته باشد، در این صورت یک اتصال بین برنامه جاوا و پایگاه داده برقرار می‌شود. برای برنامه، این اتصال با ابجکت از نوع Connection که توسط کلاس DriverManager بازگردانده می‌شود، نشان داده می‌شود. از آنجایی که این اتصال ممکن است به دلایل مختلف با شکست مواجه شود، احتمالاً یک استثنا (exception) به وجود می‌آید. بنابراین ما می‌نویسیم:


    Connection connexion=null;
    URL base=...;
    String id=...;
    String mdp=...;
try{
        connexion=DriverManager.getConnection(base,id,mdp);
} catch (Exception e){
        // مدیریت استثنا
}

برای اتصال به یک پایگاه داده، باید درایور مناسب را داشته باشید. در مثال‌های ما، این درایور ODBC خواهد بود که قادر به مدیریت پایگاه داده مورد نیاز است. در حالی که این درایور باید در لیست درایورهای ODBC روی سیستم موجود باشد، کلاس JAVA که به عنوان رابط با آن عمل خواهد کرد نیز باید موجود باشد. برای این کار، برنامه به شرح زیر کلاس مورد نیاز را درخواست خواهد کرد:

    Class.forName(String nomClasse)

کلاس Class به هیچ وجه به رابط JDBC مرتبط نیست. این یک کلاس مدیریت عمومی کلاس‌ها است. متد استاتیک آن، forName، امکان بارگذاری پویا یک کلاس را فراهم می‌کند و از این طریق دسترسی به ویژگی‌ها و متدهای استاتیک آن را ممکن می‌سازد. کلاسی که با درایورهای ODBC برای MS ویندوز رابط‌گذاری می‌کند، «sun.jdbc.odbc.JdbcOdbcDriver» نامیده می‌شود. بنابراین، ما می‌نویسیم (ممکن است این متد یک استثنا پرتاب کند):

try{
    Class.forName(« sun.jdbc.odbc.JdbcOdbcDriver ») ;
} catch (Exception e){
    // مدیریت استثنا (کلاس وجود ندارد)
}

کلاس‌های مورد نیاز برای رابط JDBC در بسته java.sql قرار دارند. بنابراین، موارد زیر باید در ابتدای برنامه نوشته شود:

    import java.sql.*;

در اینجا برنامه‌ای است که به شما امکان می‌دهد به یک پایگاه داده متصل شوید:

import java.sql.*;
import java.io.*;

// فراخوانی: pg PILOTE URL UID MDP
// با استفاده از کلاس JDBC PILOTE به پایگاه داده URL متصل می‌شود
//کاربر UID با استفاده از رمز عبور MDP احراز هویت می‌شود

public class connexion1{
    static String syntaxe="pg PILOTE URL UID MDP";

    public static void main(String arg[]){
        //بررسی تعداد آرگومان‌ها
        if(arg.length<2 || arg.length>4)
            erreur(syntaxe,1);
        // اتصال به پایگاه داده
        Connection connect=null;
        String uid="";
        String mdp="";
        if(arg.length>=3) uid=arg[2];
        if(arg.length==4) mdp=arg[3];        
        try{
            Class.forName(arg[0]);
            connect=DriverManager.getConnection(arg[1],uid,mdp);
            System.out.println("Connexion avec la base " + arg[1] + " établie");
        } catch (Exception e){
            erreur("Erreur " + e,2);
        }
        // بستن پایگاه داده
        try{
            connect.close();
            System.out.println("Base " + arg[1] + " fermée");
        } catch (Exception e){}
    }// main

    public static void erreur(String msg, int exitCode){
        System.err.println(msg);
        System.exit(exitCode);
    }
}//کلاس    

در اینجا مثالی از اجرای برنامه آورده شده است:

E:\data\java\jdbc\0>java connexion1 sun.jdbc.odbc.JdbcOdbcDriver jdbc:odbc:articles
Connexion avec la base jdbc:odbc:articles établie
Base jdbc:odbc:articles fermée

6.2.3. ارسال پرس‌وجوها به پایگاه داده

رابط JDBC امکان ارسال پرس‌وجوهای SQL به پایگاه داده متصل به برنامه جاوا و همچنین پردازش نتایج این پرس‌وجوها را فراهم می‌کند. زبان SQL (زبان پرس‌وجوی ساخت‌یافته) یک زبان پرس‌وجوی استاندارد برای پایگاه‌های داده رابطه‌ای است. انواع مختلفی از پرس‌وجوها وجود دارد:

  • درخواست‌های پرس‌وجوی پایگاه داده (SELECT)
  • پرس‌وجوهای به‌روزرسانی پایگاه داده (INSERT, DELETE, UPDATE)
  • پرس‌وجوهای ایجاد/حذف جدول (CREATE, DELETE)

در اینجا فرض می‌شود که خواننده با مبانی زبان SQL آشنا است.

6.2.3.1. کلاس Statement

برای اجرای هر پرس‌وجوی SQL در یک پایگاه داده، برنامه جاوا باید یک شی از نوع Statement داشته باشد. این شی، در میان موارد دیگر، متن پرس‌وجو را ذخیره می‌کند. این شی لزوماً به اتصال جاری متصل است. بنابراین، این یک متد از اتصال برقرار شده است که امکان ایجاد اشیاء Statement مورد نیاز برای اجرای پرس‌وجوهای SQL را فراهم می‌کند. اگر connexion شیء نماینده اتصال به پایگاه داده باشد، یک شیء Statement به شرح زیر به دست می‌آید:

    Statement requete=connexion.CreateStatement();

پس از به‌دست‌آوردن یک شیء Statement، می‌توان پرس‌وجوهای SQL را صادر کرد. رویه انجام این کار بسته به اینکه پرس‌وجو یک پرس‌وجوی پایگاه داده باشد یا یک پرس‌وجوی به‌روزرسانی، متفاوت خواهد بود.

6.2.3.2. ارسال درخواست پرس‌وجو

یک پرس‌وجو معمولاً از نوع زیر است:

    select col1, col2,... from table1, table2,...
    where condition
    order by expression
    ...

فقط کلمات کلیدی در خط اول اجباری هستند؛ سایر کلمات اختیاری‌اند. کلمات کلیدی دیگری نیز وجود دارند که در اینجا نشان داده نشده‌اند.

  1. پیوندی روی تمام جداول انجام می‌شود که پس از کلمهٔ کلیدی «FROM» می‌آیند
  2. فقط ستون‌هایی که پس از کلمهٔ کلیدی «SELECT» می‌آیند، نگه‌داری می‌شوند
  3. فقط سطرهایی که شرط مشخص‌شده توسط کلمهٔ کلیدی «WHERE» را برآورده می‌کنند، نگه‌داری می‌شوند
  4. رده‌های حاصل، بر اساس عبارت در کلیدواژه `ORDER BY` مرتب شده و نتیجه پرس‌وجو را تشکیل می‌دهند.

نتیجه یک پرس‌وجوی select یک جدول است. اگر جدول قبلی ARTICLES را در نظر بگیریم و بخواهیم نام اقلامی را که موجودی فعلی‌شان کمتر از آستانهٔ حداقل است، بازیابی کنیم، خواهیم نوشت: SELECT name FROM items WHERE stock\_actu &lt; stock\_mini. اگر بخواهیم آن‌ها را به ترتیب الفبایی نام فهرست کنیم، خواهیم نوشت: select name from items where stock_actu<stock_mini order by name

برای اجرای این نوع پرس‌وجو، کلاس Statement متد executeQuery را فراهم می‌کند:

    ResultSet executeQuery(String requête)

که در آن requête متن پرس‌وجوی SELECT است که باید اجرا شود.

بنابراین، اگر

  • connexion ابجکتی است که نمایانگر اتصال به پایگاه داده است
  • دستور s=connexion.createStatement() شیء Statement مورد نیاز برای ارسال پرس‌وجوهای SQL را ایجاد می‌کند
  • ResultSet rs=s.executeQuery(" select name from articles where stock_actu<stock_mini") یک پرس‌وجوی select را اجرا می‌کند و سطرهای نتیجهٔ پرس‌وجو را به یک شیء از نوع ResultSet اختصاص می‌دهد.

6.2.3.3. کلاس ResultSet: نتیجه یک پرس‌وجوی SELECT

یک شیء از نوع ResultSet یک جدول را نشان می‌دهد، یعنی مجموعه‌ای از سطرها و ستون‌ها. در هر لحظه، تنها یک سطر از جدول قابل دسترسی است؛ این سطر، سطر جاری نامیده می‌شود. هنگامی که ResultSet در ابتدا ایجاد می‌شود، سطر جاری، سطر شماره ۱ است اگر ResultSet خالی نباشد. برای رفتن به سطر بعدی، کلاس ResultSet متد next را فراهم می‌کند:

    boolean next()

این متد سعی می‌کند به خط بعدی ResultSet حرکت کند و در صورت موفقیت، true را بازمی‌گرداند، و در غیر این صورت، false را. اگر موفقیت‌آمیز باشد، خط بعدی به خط جاری جدید تبدیل می‌شود. رشته قبلی از بین می‌رود و قابل بازیابی نیست. جدول ResultSet دارای ستون‌های col1، col2 و غیره است. برای دسترسی به فیلدهای مختلف در رشته جاری، روش‌های زیر در دسترس هستند:

Type getType("coli") 

برای بازیابی فیلد «coli» از سطر جاری. Type به نوع فیلد coli اشاره دارد. روش getString اغلب روی همه فیلدها استفاده می‌شود که محتوای فیلد را به صورت یک رشته کاراکتری بازمی‌گرداند. این سپس در صورت لزوم تبدیل می‌شود. اگر نام ستون نامشخص باشد، می‌توان از روش‌های زیر استفاده کرد:

Type getType(i) 

که در آن i نمایه ستون مورد نظر است (i ≥ 1).

6.2.3.4. یک مثال اول

در اینجا برنامه‌ای آمده است که محتویات پایگاه داده ARTICLES را که قبلاً ایجاد شده است، نمایش می‌دهد:

import java.sql.*;
import java.io.*;

// محتویات یک پایگاه داده سیستمی را نمایش می‌دهد ARTICLES

public class articles1{

    static final String DB="ARTICLES";        // پایگاه داده مورد استفاده

    public static void main(String arg[]){

        Connection connect=null;        //اتصال به پایگاه داده
        Statement S=null;                // شیء برای صدور پرس‌وجوها
        ResultSet RS=null;            //جدول نتایج پرس‌وجو
        try{
            //اتصال به پایگاه داده
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
            connect=DriverManager.getConnection("jdbc:odbc:"+DB,"","");
            System.out.println("Connexion avec la base " + DB + " établie");
            //ایجاد یک شیء Statement
            S=connect.createStatement();
            //اجرای یک پرس‌وجوی SELECT
            RS=S.executeQuery("select * from " + DB);
            //پردازش جدول نتایج
            while(RS.next()){                //تا زمانی که ردیفی برای پردازش وجود داشته باشد
                // روی صفحه نمایش داده می‌شود
                System.out.println(RS.getString("code")+","+
                    RS.getString("nom")+","+
                    RS.getString("prix")+","+
                    RS.getString("stock_actu")+","+
                    RS.getString("stock_mini"));
            }// ردیف بعدی
        } catch (Exception e){
            erreur("Erreur " + e,2);
        }
        // پایگاه داده را ببندید
        try{
            connect.close();
            System.out.println("Base " + DB + " fermée");
        } catch (Exception e){}
    }// اصلی

    public static void erreur(String msg, int exitCode){
        System.err.println(msg);
        System.exit(exitCode);
    }
}//کلاس    

نتایج به‌دست‌آمده به شرح زیر است:

Connexion avec la base ARTICLES établie
a300,vélo,1202,30,2
d600,arc,5000,10,2
d800,canoé,1502,12,6
x123,fusil,3000,10,2
s345,skis nautiques,1800,3,2
f450,essai3,3,3,3
f807,cachalot,200000,0,0
z400,léopard,500000,1,1
g457,panthère,800000,1,1
Base ARTICLES fermée

6.2.3.5. کلاس ResultSetMetadata

در مثال قبلی، ما نام ستون‌ها را برای ResultSet می‌دانیم. اگر آن‌ها را ندانیم، نمی‌توانیم از روش getType(nom_colonne) استفاده کنیم. در عوض، از getType(شماره ستون) استفاده می‌کنیم. با این حال، برای به‌دست آوردن همه ستون‌ها، باید بدانیم که ResultSet حاصل چند ستون دارد. کلاس ResultSet این اطلاعات را ارائه نمی‌دهد. این کلاس ResultSetMetaData است که این اطلاعات را فراهم می‌کند. به طور کلی‌تر، این کلاس اطلاعاتی در مورد ساختار جدول، یعنی ماهیت ستون‌های آن، ارائه می‌دهد.

ما می‌توانیم با ایجاد یک شیء از کلاس ResultSetMetaData، به اطلاعات مربوط به ساختار یک ResultSet دسترسی پیدا کنیم. اگر RS یک ResultSet باشد، ResultSetMetaData مربوطه از طریق زیر به دست می‌آید:

    RS.getMetaData()

دو متد مفید در کلاس ResultSetMetaData را توجه کنید:

  1. int getColumnCount() که تعداد ستون‌ها را در ResultSet برمی‌گرداند
  2. String getColumnLabel(int iکه نام ستون i را در ResultSet (i ≥ 1) بازمی‌گرداند

6.2.3.6. یک مثال دوم

برنامه قبلی محتویات پایگاه داده ARTICLES را نمایش داد. در اینجا برنامه‌ای می‌نویسیم که هر پرس‌وجوی SQL یا Select را که کاربر در صفحه‌کلید وارد می‌کند، بر روی پایگاه داده ARTICLES اجرا می‌کند.

import java.sql.*;
import java.io.*;

//محتویات یک پایگاه داده سیستمی ARTICLES را نمایش می‌دهد

public class sql1{

    static final String DB="ARTICLES";        // پایگاه داده‌ای که باید استفاده شود

    public static void main(String arg[]){

        Connection connect=null;        //اتصال به پایگاه داده
        Statement S=null;                // شیء برای صدور پرس‌وجوها
        ResultSet RS=null;            // جدول نتایج پرس‌وجو
        String select;                    // متن پرس‌وجوی SELECT SQL
        int nbColonnes;                // تعداد ستون‌ها در ResultSet

        //ایجاد جریان ورودی صفحه‌کلید
        BufferedReader in=null;
        try{
            in=new BufferedReader(new InputStreamReader(System.in));
        } catch(Exception e){
            erreur("erreur lors de l'ouverture du flux clavier ("+e+")",3);
        }
        try{
            //اتصال به پایگاه داده
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
            connect=DriverManager.getConnection("jdbc:odbc:"+DB,"","");
            System.out.println("Connexion avec la base " + DB + " établie");
            //ایجاد یک شی Statement
            S=connect.createStatement();
            //حلقه برای اجرای پرس‌وجوها SQL وارد شده از طریق صفحه‌کلید
            System.out.print("Requête : ");
            select=in.readLine();
            while(!select.equals("fin")){
                //اجرای پرس‌وجو
                RS=S.executeQuery(select);
                // تعداد ستون‌ها
                nbColonnes=RS.getMetaData().getColumnCount();
                //پردازش جدول نتایج
                System.out.println("Résultats obtenus\n\n");
                while(RS.next()){                //تا زمانی که ردیفی برای پردازش وجود داشته باشد
                    // روی صفحه نمایش داده می‌شود
                    for(int i=1;i<nbColonnes;i++)
                        System.out.print(RS.getString(i)+",");
                    System.out.println(RS.getString(nbColonnes));
                }// ردیف بعدی
                // پرس‌وجوی بعدی
                System.out.print("Requête : ");
                select=in.readLine();                
            }// در حالی که
        } catch (Exception e){
            erreur("Erreur " + e,2);
        }
        // پایگاه داده و جریان ورودی را ببندید
        try{
            connect.close();
            System.out.println("Base " + DB + " fermée");
            in.close();
        } catch (Exception e){}
    }// main

    public static void erreur(String msg, int exitCode){
        System.err.println(msg);
        System.exit(exitCode);
    }
}// کلاس    

در اینجا برخی از نتایج به‌دست‌آمده آورده شده است:

Connexion avec la base ARTICLES établie
Requête : select * from articles order by prix desc
Résultats obtenus


g457,panthère,800000,1,1
z400,léopard,500000,1,1
f807,cachalot,200000,0,0
d600,arc,5000,10,2
x123,fusil,3000,10,2
s345,skis nautiques,1800,3,2
d800,canoé,1502,12,6
a300,vélo,1202,30,2
f450,essai3,3,3,3

Requête : select nom, prix from articles where prix >10000 order by prix desc
Résultats obtenus


panthère,800000
léopard,500000
cachalot,200000

6.2.3.7. ارسال درخواست به‌روزرسانی پایگاه داده

یک شیء از نوع Statement برای ذخیره‌سازی درخواست‌های SQL استفاده می‌شود. متدی که این شیء برای ارسال درخواست‌های به‌روزرسانی SQL به کار می‌برد (INSERT, UPDATE, DELETE) دیگر روش executeQuery مورد بحث قبلی نیست، بلکه روش executeUpdate است:

    int executeUpdate(String requête)

تفاوت در نتیجه است: در حالی که executeQuery جدول نتایج (ResultSet) را بازگردانده است، executeUpdate تعداد ردیف‌های تحت تأثیر عملیات به‌روزرسانی را بازمی‌گرداند.

6.2.3.8. یک مثال سوم

ما برنامه قبلی را کمی تغییر می‌دهیم: پرس‌وجوهایی که از طریق صفحه‌کلید وارد می‌شوند، اکنون پرس‌وجوهای به‌روزرسانی برای پایگاه داده ARTICLES هستند.

import java.sql.*;
import java.io.*;

// محتویات یک پایگاه داده سیستمی ARTICLES را نمایش می‌دهد

public class sql2{

    static final String DB="ARTICLES";    // پایگاه داده مورد استفاده

    public static void main(String arg[]){

        Connection connect=null;        //اتصال به پایگاه داده
        Statement S=null;                // شیء برای صدور پرس‌وجوها
        ResultSet RS=null;            //جدول نتایج پرس‌وجو
        String sqlUpdate;                // متن پرس‌وجوی به‌روزرسانی SQL
        int nbLignes;                    // تعداد سطرهای تحت تأثیر یک به‌روزرسانی

        //ایجاد جریان ورودی صفحه‌کلید
        BufferedReader in=null;
        try{
            in=new BufferedReader(new InputStreamReader(System.in));
        } catch(Exception e){
            erreur("erreur lors de l'ouverture du flux clavier ("+e+")",3);
        }
        try{
            // اتصال به پایگاه داده
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
            connect=DriverManager.getConnection("jdbc:odbc:"+DB,"","");
            System.out.println("Connexion avec la base " + DB + " établie");
            //ایجاد یک شی Statement
            S=connect.createStatement();
            //حلقه برای اجرای پرس‌وجوها SQL وارد شده از طریق صفحه‌کلید
            System.out.print("Requête : ");
            sqlUpdate=in.readLine();
            while(!sqlUpdate.equals("fin")){
                //اجرای پرس‌وجو
                nbLignes=S.executeUpdate(sqlUpdate);
                //پیگیری
                System.out.println(nbLignes + " ligne(s) ont été mises à jour");
                // پرس‌وجوی بعدی
                System.out.print("Requête : ");
                sqlUpdate=in.readLine();                
            }// درحالی‌که
        } catch (Exception e){
            erreur("Erreur " + e,2);
        }
        //بستن پایگاه داده و جریان ورودی
        try{
            // رهاسازی منابع مرتبط با پایگاه داده
            RS.close();
            S.close();
            connect.close();
            System.out.println("Base " + DB + " fermée");
            //بسته‌شدن جریان صفحه‌کلید
            in.close();
        } catch (Exception e){}
    }// دست

    public static void erreur(String msg, int exitCode){
        System.err.println(msg);
        System.exit(exitCode);
    }
}//کلاس    

در اینجا نتایج اجرای‌های مختلف برنامه‌های sql1 و sql2 آمده است:

فهرست سطرها در پایگاه داده ARTICLES:


E:\data\java\jdbc\0>java sql1
Connexion avec la base ARTICLES établie
Requête : select nom,stock_actu from articles
Résultats obtenus


vélo,30
arc,10
canoé,12
fusil,10
skis nautiques,3
essai3,3
cachalot,0
léopard,1
panthère,1

ما خطوط خاصی را اصلاح می‌کنیم:


E:\data\java\jdbc\0>java sql2
Connexion avec la base ARTICLES établie
Requête : update articles set stock_actu=stock_actu+1 where stock_actu>10
2 ligne(s) ont été mises à jour

تأیید:


E:\data\java\jdbc\0>java sql1
Connexion avec la base ARTICLES établie
Requête : select nom,stock_actu from articles
Résultats obtenus

vélo,31
arc,10
canoé,13
fusil,10
skis nautiques,3
essai3,3
cachalot,0
léopard,1
panthère,1

یک خط اضافه کنید:


E:\data\java\jdbc\0>java sql2
Connexion avec la base ARTICLES établie
Requête : insert into articles (code,nom,prix,stock_actu,stock_mini) values ('x400','nouveau',200,20,10)
1 ligne(s) ont été mises à jour

تأیید:


E:\data\java\jdbc\0>java sql1
Connexion avec la base ARTICLES établie
Requ_te : select nom,stock_actu from articles
Résultats obtenus

vélo,31
arc,10
canoé,13
fusil,10
skis nautiques,3
essai3,3
cachalot,0
léopard,1
panthère,1
nouveau,20

حذف یک خط:


E:\data\java\jdbc\0>java sql2
Connexion avec la base ARTICLES établie
Requête : delete from articles where code='x400'
1 ligne(s) ont été mises à jour
Requête : fin

تأیید:


E:\data\java\jdbc\0>java sql1
Connexion avec la base ARTICLES établie
Requête : select nom,stock_actu from articles
Résultats obtenus


vélo,31
arc,10
cano_,13
fusil,10
skis nautiques,3
essai3,3
cachalot,0
léopard,1
panthère,1

6.2.3.9. ارسال هر درخواست SQL

شیء Statement که برای ارسال درخواست‌های SQL مورد نیاز است، دارای متدی execute است که قادر به اجرای هر نوع درخواست SQL می‌باشد:

    boolean execute(String requête)

نتیجه‌ی بازگشتی، مقدار بولی true است اگر پرس‌وجو یک ResultSet (executeQuery) را بازگردانده باشد، یا false اگر یک عدد را بازگردانده باشد (executeUpdate). مقدار بازگشتی ResultSet را می‌توان با استفاده از روش getResultSet بازیابی کرد و تعداد ردیف‌های به‌روزرسانی‌شده را می‌توان با استفاده از روش getUpdateCount بازیابی کرد. بنابراین، خواهیم نوشت:


Statement S=...;
ResultSet RS=...;
int nbLignes;
String requête=...;
// اجرای یک پرس‌وجو SQL
if (S.execute(requête)){
    // ما یک مجموعه نتایج داریم
    RS=S.getResultSet();
    //پردازش ResultSet
    ...
} else {
    //این یک پرس‌وجوی به‌روزرسانی بود
    nbLignes=S.getUpdateCount();
    ...
}

6.2.3.10. مثال چهارم

ما مفهوم پشت برنامه‌های sql1 و sql2 را در برنامه‌ای به نام sql3 ادغام کرده‌ایم که اکنون قادر است هر پرس‌وجوی SQL را که از طریق صفحه‌کلید وارد می‌شود، اجرا کند. برای عمومی‌تر کردن برنامه، ویژگی‌های پایگاه داده مورد استفاده به عنوان پارامتر به برنامه ارسال می‌شوند.

import java.sql.*;
import java.io.*;

//فراخوانی: pg PILOTE URL UID MDP
// با استفاده از کلاس JDBC به پایگاه داده URL متصل می‌شود PILOTE
//کاربر UID با استفاده از رمز عبور MDP احراز هویت می‌شود

public class sql3{

    static String syntaxe="pg PILOTE URL UID MDP";

    public static void main(String arg[]){



        //بررسی تعداد آرگومان‌ها
        if(arg.length<2 || arg.length>4)
            erreur(syntaxe,1);

        // ابتدایی‌سازی پارامترهای اتصال
        Connection connect=null;
        String uid="";
        String mdp="";
        if(arg.length>=3) uid=arg[2];
        if(arg.length==4) mdp=arg[3];        

        // سایر داده‌ها
        Statement S=null;                        // شیء برای ارسال پرس‌وجوها
        ResultSet RS=null;                    //جدول نتایج یک پرس‌وجو
        String sqlText;                            //متن پرس‌وجوی SQL برای اجرا
        int nbLignes;                                // تعداد سطرهای تحت تأثیر یک به‌روزرسانی
        int nbColonnes;                            // تعداد ستون‌ها در یک ResultSet

        //ایجاد جریان ورودی صفحه‌کلید
        BufferedReader in=null;
        try{
            in=new BufferedReader(new InputStreamReader(System.in));
        } catch(Exception e){
            erreur("erreur lors de l'ouverture du flux clavier ("+e+")",3);
        }
        try{
            // اتصال به پایگاه داده
            Class.forName(arg[0]);
            connect=DriverManager.getConnection(arg[1],uid,mdp);
            System.out.println("Connexion avec la base " + arg[1] + " établie");
            //ایجاد یک شی Statement
            S=connect.createStatement();
            //حلقه برای اجرای پرس‌وجوهای واردشده از طریق صفحه‌کلید SQL
            System.out.print("Requête : ");
            sqlText=in.readLine();
            while(!sqlText.equals("fin")){
                //اجرای پرس‌وجو
                try{
                    if(S.execute(sqlText)){
                        //نتیجه حاصل شده است: ResultSet – آن را پردازش کنید
                        RS=S.getResultSet();
                        // تعداد ستون‌ها
                        nbColonnes=RS.getMetaData().getColumnCount();
                        //پردازش جدول نتایج
                        System.out.println("\nRésultats obtenus\n-----------------\n");
                        while(RS.next()){                //تا زمانی که ردیفی برای پردازش وجود داشته باشد
                            //آن را روی صفحه نمایش نمایش دهید
                            for(int i=1;i<nbColonnes;i++)
                                System.out.print(RS.getString(i)+",");
                            System.out.println(RS.getString(nbColonnes));
                        }// ردیف بعدی ResultSet
                    } else {
                        // این یک درخواست به‌روزرسانی بود
                        nbLignes=S.getUpdateCount();
                        //پیگیری
                        System.out.println(nbLignes + " ligne(s) ont été mises à jour");
                    }//اگر
                } catch (Exception e){
                    System.out.println("Erreur " +e);
                }
                //درخواست بعدی
                System.out.print("\nNouvelle Requête : ");
                sqlText=in.readLine();                
            }//در حالی که
        } catch (Exception e){
            erreur("Erreur " + e,2);
        }
        //بستن پایگاه داده و جریان ورودی
        try{
            //آزادسازی منابع مرتبط با پایگاه داده
            RS.close();
            S.close();
            connect.close();
            System.out.println("Base " + arg[1] + " fermée");
            //بستن جریان صفحه‌کلید
            in.close();
        } catch (Exception e){}
    }// main

    public static void erreur(String msg, int exitCode){
        System.err.println(msg);
        System.exit(exitCode);
    }
}//کلاس    

فایل پرس‌وجوی زیر ایجاد می‌شود:

select * from articles
update articles set stock_mini=stock_mini+5 where stock_mini<5
select nom,stock_mini from articles
insert into articles (code,nom,prix,stock_actu,stock_mini) values ('x400','nouveau',100,20,10)
select * from articles
delete from articles where code='x400'
select * from articles
fin

برنامه به شرح زیر راه‌اندازی می‌شود:

E:\data\java\jdbc\0>java sql3 sun.jdbc.odbc.JdbcOdbcDriver jdbc:odbc:articles <requetes >results

بنابراین برنامه ورودی خود را از فایل requetes می‌خواند و خروجی خود را در فایل results می‌نویسد. نتایج به‌دست‌آمده به شرح زیر است:

Connexion avec la base jdbc:odbc:articles établie

Requête : (requete 1 du fichier des requetes : select * from articles)
Résultats obtenus
-----------------

a300,vélo,1202,31,3
d600,arc,5000,10,3
d800,canoé,1502,13,7
x123,fusil,3000,10,3
s345,skis nautiques,1800,3,3
f450,essai3,3,3,4
f807,cachalot,200000,0,1
z400,léopard,500000,1,2
g457,panthère,800000,1,2

Nouvelle Requête : (requete 2 du fichier des requetes : update articles set stock_mini=stock_mini+5 where stock_mini<5)

8 ligne(s) ont é mises à jour

Nouvelle Requête : (requete 3 du fichier des requetes : select nom,stock_mini from articles)

Résultats obtenus
-----------------

vélo,8
arc,8
canoé,7
fusil,8
skis nautiques,8
essai3,9
cachalot,6
léopard,7
panthère,7

Nouvelle Requête : (requete 4 du fichier des requetes : insert into articles (code,nom,prix,stock_actu,stock_mini) values ('x400','nouveau',100,20,10))

1 ligne(s) ont é mises à jour

Nouvelle Requête : (requete 5 du fichier des requetes : select * from articles)

Résultats obtenus
-----------------

a300,vélo,1202,31,8
d600,arc,5000,10,8
d800,canoé,1502,13,7
x123,fusil,3000,10,8
s345,skis nautiques,1800,3,8
f450,essai3,3,3,9
f807,cachalot,200000,0,6
z400,léopard,500000,1,7
g457,panthère,800000,1,7
x400,nouveau,100,20,10

Nouvelle Requête : (requete 6 du fichier des requêtes : delete from articles where code='x400')


1 ligne(s) ont é mises à jour

Nouvelle Requête : (requete 7 du fichier des requêtes : select * from articles)

Résultats obtenus
-----------------

a300,vélo,1202,31,8
d600,arc,5000,10,8
d800,canoé,1502,13,7
x123,fusil,3000,10,8
s345,skis nautiques,1800,3,8
f450,essai3,3,3,9
f807,cachalot,200000,0,6
z400,léopard,500000,1,7
g457,panthère,800000,1,7

6.3. IMPOTS با استفاده از پایگاه داده

آخرین باری که به مسئله محاسبه مالیات پرداختیم، از یک رابط کاربری گرافیکی استفاده کردیم و داده‌ها در یک فایل ذخیره می‌شدند. ما این نسخه را دوباره بررسی می‌کنیم، اکنون با این فرض که داده‌ها در یک پایگاه داده ODBC-MySQL ذخیره شده‌اند. MySQL نسخه‌ای در مالکیت عمومی از SGBD است که می‌توان از آن روی پلتفرم‌های مختلف، از جمله ویندوز و لینوکس، استفاده کرد. با این SGBD، یک پایگاه داده به نام dbimpots ایجاد شده است که شامل یک جدول واحد به نام impots می‌باشد. دسترسی به پایگاه داده توسط نام کاربری و رمز عبور کنترل می‌شود، که در این مورد admimpots و mdpimpots هستند. اسکرین‌شات نشان می‌دهد که چگونه از پایگاه داده dbimpots با MySQL استفاده شود:


C:\Program Files\EasyPHP\mysql\bin>mysql -u admimpots -p
Enter password: *********
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 18 to server version: 3.23.49-max-nt

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> use dbimpots;
Database changed

mysql> show tables;
+--------------------+
| Tables_in_dbimpots |
+--------------------+
| impots             |
+--------------------+
1 row in set (0.00 sec)

mysql> describe impots;
+---------+--------+------+-----+---------+-------+
| Field   | Type   | Null | Key | Default | Extra |
+---------+--------+------+-----+---------+-------+
| limites | double | YES  |     | NULL    |       |
| coeffR  | double | YES  |     | NULL    |       |
| coeffN  | double | YES  |     | NULL    |       |
+---------+--------+------+-----+---------+-------+
3 rows in set (0.02 sec)

mysql> select * from impots;
+---------+--------+---------+
| limites | coeffR | coeffN  |
+---------+--------+---------+
|   12620 |      0 |       0 |
|   13190 |   0.05 |     631 |
|   15640 |    0.1 |  1290.5 |
|   24740 |   0.15 |  2072.5 |
|   31810 |    0.2 |  3309.5 |
|   39970 |   0.25 |    4900 |
|   48360 |    0.3 |    6898 |
|   55790 |   0.35 |  9316.5 |
|   92970 |    0.4 |   12106 |
|  127860 |   0.45 |   16754 |
|  151250 |    0.5 | 23147.5 |
|  172040 |   0.55 |   30710 |
|  195000 |    0.6 |   39312 |
|       0 |   0.65 |   49062 |
+---------+--------+---------+
14 rows in set (0.00 sec)

mysql>quit

رابط کاربری گرافیکی برنامه به شرح زیر است:

Image

رابط کاربری گرافیکی چند تغییری داشته است:

خیر.
نوع
نام
نقش
1
JTextField
txtConnexion
رشته اتصال پایگاه داده ODBC
2
JScrollPane
JScrollPane1
ظرف برای ناحیه متن ۳
3
JTextArea
txtStatus
نمایش پیام‌های وضعیت، از جمله پیام‌های خطا

رشتهٔ ورود واردشده در (۱) به شرح زیر است: DSN;login;password, با

DSN
نام DSN منبع داده ODBC

login
هویت کاربری که دسترسی خواندن به پایگاه داده دارد

motdepasse
رمز عبور آنها

پایگاه داده dbimpots به‌صورت دستی با استفاده از MySQL ایجاد شد. این پایگاه داده به منبع داده ODBC به شرح زیر تبدیل می‌شود:

  • مدیر منبع داده ۳۲ بیتی ODBC را راه‌اندازی کنید

Image

  • برای افزودن منبع داده جدید ODBC از دکمه [Add] استفاده کنید

Image

  • درایور MySQL را انتخاب کرده و آن را روی [Terminer] تنظیم کنید

Image

  • راننده MySQL به اطلاعات خاصی نیاز دارد:
۱
نام DSN که باید به منبع داده ODBC داده شود – این می‌تواند هر چیزی باشد
۲
ماشینی که SGBD MySQL روی آن در حال اجرا است – در این مورد، localhost. شایان ذکر است که پایگاه داده می‌تواند یک پایگاه داده از راه دور باشد. برنامه‌های محلی که از منبع داده ODBC استفاده می‌کنند، از این موضوع مطلع نخواهند بود. این موضوع به‌ویژه برای برنامهٔ جاوا ما صدق می‌کند.
۳
پایگاه داده MySQL برای استفاده. MySQL یک SGBD است که پایگاه‌های داده رابطه‌ای را مدیریت می‌کند، که مجموعه‌ای از جداول مرتبط با یکدیگر از طریق روابط هستند. در اینجا، ما نام پایگاه داده در حال مدیریت را مشخص می‌کنیم.
۴
نام کاربری با حقوق دسترسی به این پایگاه داده
5
رمز عبور آنها

پس از تعریف منبع داده ODBC، می‌توانیم برنامه خود را آزمایش کنیم:

 

بیایید کد را بررسی کنیم که در مقایسه با نسخه گرافیکی بدون پایگاه داده تغییر کرده است. بیایید کد کلاس impots را که تاکنون استفاده شده است، به یاد بیاوریم:

// ایجاد کلاس 'taxes'

public class impots{

    //داده‌های مورد نیاز برای محاسبه مالیات
     //از یک منبع خارجی می‌آید

    private double[] limites, coeffR, coeffN;

     // سازنده
    public impots(double[] LIMITES, double[] COEFFR, double[] COEFFN) throws Exception{
         // ما بررسی می‌کنیم که سه آرایه اندازه یکسانی داشته باشند
        boolean OK=LIMITES.length==COEFFR.length && LIMITES.length==COEFFN.length;
        if (! OK) throw new Exception ("Les 3 tableaux fournis n'ont pas la même taille("+
                                LIMITES.length+","+COEFFR.length+","+COEFFN.length+")");
        // همه چیز درست است
        this.limites=LIMITES;
        this.coeffR=COEFFR;
        this.coeffN=COEFFN;
    }//تولیدکننده

     //محاسبه مالیات
    public long calculer(boolean marié, int nbEnfants, int salaire){
         //محاسبه تعداد سهام
        double nbParts;
        if (marié) nbParts=(double)nbEnfants/2+2;
        else nbParts=(double)nbEnfants/2+1;
        if (nbEnfants>=3) nbParts+=0.5;
         //محاسبه درآمد مشمول مالیات و ضریب خانوادگی
        double revenu=0.72*salaire;
        double QF=revenu/nbParts;
         //محاسبه مالیات
        limites[limites.length-1]=QF+1;
        int i=0;
        while(QF>limites[i]) i++;
        // نتیجه اظهارنامه
        return (long)(revenu*coeffR[i]-nbParts*coeffN[i]);
    }//محاسبه
}// محدوده

این کلاس سه آرایه limites، coeffR و coeffN را از سه آرایه‌ای که به‌عنوان پارامتر به سازند آن ارسال می‌شوند، ایجاد می‌کند. ما تصمیم گرفته‌ایم یک سازند جدید اضافه کنیم که امکان ایجاد همان سه آرایه را از یک پایگاه داده فراهم کند:

  public impots(String dsnIMPOTS, String userIMPOTS, String mdpIMPOTS)
      throws SQLException,ClassNotFoundException{

    // dsnIMPOTS: نام پایگاه داده DSN
     //userIMPOTS, mdpIMPOTS: نام کاربری/رمز عبور پایگاه داده

برای این مثال، ما تصمیم گرفته‌ایم که این سازنده جدید را در کلاس impots پیاده‌سازی نکنیم، بلکه در یک کلاس مشتق شده، impotsJDBC:

//بستههای واردشده
import java.sql.*;
import java.util.*;

public class impotsJDBC extends impots{
  // افزودن یک سازنده برای تولید
   // جدولهای 'limites'، 'coeffr' و 'coeffn' از
   //استخراج از یک پایگاه داده
  public impotsJDBC(String dsnIMPOTS, String userIMPOTS, String mdpIMPOTS)
      throws SQLException,ClassNotFoundException{

    //dsnIMPOTS: نام پایگاه داده DSN
     // userIMPOTS, mdpIMPOTS: نام کاربری/رمز عبور برای دسترسی به پایگاه داده

     // جدولهای داده
    ArrayList aLimites=new ArrayList();
    ArrayList aCoeffR=new ArrayList();
    ArrayList aCoeffN=new ArrayList();

    //اتصال به پایگاه داده
    Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
    Connection connect=DriverManager.getConnection("jdbc:odbc:"+dsnIMPOTS,userIMPOTS,mdpIMPOTS);
    //ایجاد یک شیء Statement
    Statement S=connect.createStatement();
    // پرسوجوی SELECT
    String select="select limites, coeffr, coeffn from impots";
    // اجرای پرسوجو
    ResultSet RS=S.executeQuery(select);
    while(RS.next()){
      //پردازش سطر فعلی
      aLimites.add(RS.getString("limites"));
      aCoeffR.add(RS.getString("coeffr"));
      aCoeffN.add(RS.getString("coeffn"));
    }// ردیف بعدی
     //بستن منابع
    RS.close();
    S.close();
    connect.close();
     //انتقال دادهها به آرایههای محدود
    int n=aLimites.size();
    limites=new double[n];
    coeffR=new double[n];
    coeffN=new double[n];
    for(int i=0;i<n;i++){
      limites[i]=Double.parseDouble((String)aLimites.get(i));
      coeffR[i]=Double.parseDouble((String)aCoeffR.get(i));
      coeffN[i]=Double.parseDouble((String)aCoeffN.get(i));
    }//برای
  }//سازنده
}//کلاس

سازنده محتویات جدول impots را از پایگاه داده که به‌عنوان پارامتر به آن ارسال شده است می‌خواند و آرایه‌های limites، coeffR و coeffN را پر می‌کند. ممکن است تعدادی خطا رخ دهد. سازنده این خطاها را مدیریت نمی‌کند، بلکه آن‌ها را به برنامه فراخواننده منتقل می‌کند:

  public impotsJDBC(String dsnIMPOTS, String userIMPOTS, String mdpIMPOTS)
      throws SQLException,ClassNotFoundException{

اگر با دقت به کد بالا نگاه کنیم، می‌توانیم ببینیم که کلاس impotsJDBC مستقیماً از فیلدهای limites، coeffR، استفاده می‌کند، coeffN از کلاس پایهٔ خود impots. از آنجا که این فیلدها به‌صورت خصوصی تعریف شده‌اند:

    private double[] limites, coeffR, coeffN;

کلاس impotsJDBC دسترسی مستقیم به این فیلدها ندارد. بنابراین ما با نوشتن: یک اصلاح اولیه در کلاس پایه انجام می‌دهیم:

  protected double[] limites=null;
  protected double[] coeffR=null;
  protected double[] coeffN=null;

ویژگی protected به کلاس‌های مشتق‌شده از کلاس impots اجازه می‌دهد تا به فیلدهایی که با این ویژگی اعلام شده‌اند دسترسی مستقیم داشته باشند. ما باید یک تغییر دوم ایجاد کنیم. سازنده کلاس فرزند impotsJDBC به صورت زیر اعلام شده است:

  public impotsJDBC(String dsnIMPOTS, String userIMPOTS, String mdpIMPOTS)
      throws SQLException,ClassNotFoundException{

ما می‌دانیم که قبل از ساختن یک شیء از یک کلاس فرزند، ابتدا باید یک شیء از کلاس والد بسازیم. برای این کار، سازنده کلاس فرزند باید به صراحت با استفاده از یک دستور super(....)، سازنده کلاس والد را فراخوانی کند. این کار در اینجا انجام نشده است زیرا مشخص نیست کدام سازنده از کلاس والد را می‌توان فراخوانی کرد. در حال حاضر، تنها یک سازنده وجود دارد و آن مناسب نیست. کامپایلر سپس در کلاس والد به دنبال یک سازنده بدون پارامتر می‌گردد که بتواند آن را فراخوانی کند. کامپایلر چنین سازنده‌ای را پیدا نمی‌کند و این منجر به خطای کامپایل می‌شود. بنابراین ما یک سازنده بدون پارامتر به کلاس خود اضافه می‌کنیم impots:

   // سازنده خالی
  protected impots(){}

ما آن را به صورت «protected» اعلام می‌کنیم تا فقط توسط کلاس‌های فرزند قابل استفاده باشد. اسکلت کلاس impots اکنون به صورت زیر است:

public class impots{

  //داده‌های مورد نیاز برای محاسبه مالیات
   //از منبع خارجی آمده است

  protected double[] limites=null;
  protected double[] coeffR=null;
  protected double[] coeffN=null;

   // سازندهٔ خالی
  protected impots(){}

   //سازنده
  public impots(double[] LIMITES, double[] COEFFR, double[] COEFFN) throws Exception{
...........
  }//سازنده

   //محاسبه مالیات
  public long calculer(boolean marié, int nbEnfants, int salaire){
.............
    }//محاسبه
}//

عمل برای آیتم منوی Initialiser در برنامه ما به صورت زیر در می‌آید:

  void mnuInitialiser_actionPerformed(ActionEvent e) {
    // بازیابی رشته اتصال
    Pattern séparateur=Pattern.compile("\\s*;\\s*");
    String[] champs=séparateur.split(txtConnexion.getText().trim());
     //سه فیلد الزامی هستند
    if(champs.length!=3){
      //خطا
      txtStatus.setText("Chaîne de connexion (DSN;uid;mdp) incorrecte");
       //بازگشت به رابط کاربری گرافیکی
      txtConnexion.requestFocus();
      return;
    }//اگر
     // بارگذاری داده‌ها
    try{
       // ایجاد شیء impotsJDBC
      objImpots=new impotsJDBC(champs[0],champs[1],champs[2]);
       //تأیید
      txtStatus.setText("Données chargées");
       // حقوق قابل اصلاح است
      txtSalaire.setEditable(true);
       // امکان تغییرات بیشتر وجود ندارد
      mnuInitialiser.setEnabled(false);
      txtConnexion.setEditable(false);
    }catch(Exception ex){
       // مشکل
      txtStatus.setText("Erreur : " + ex.getMessage());
      //پایان
      return;
    }//catch
  }

پس از ایجاد شیء objImpots، برنامه کاربردی با برنامه گرافیکی که قبلاً نوشته شده یکسان است. از خواننده دعوت می‌شود به آن مراجعه کند.

6.4. تمرین‌ها

6.4.1. تمرین ۱

یک رابط کاربری گرافیکی برای برنامه قبلی sql3 فراهم کنید.

6.4.2. تمرین ۲

یک اپلت جاوا تنها می‌تواند از طریق سرور میزبان خود به پایگاه داده دسترسی پیدا کند. از آنجا که اپلت به هارد دیسک دستگاهی که روی آن اجرا می‌شود دسترسی ندارد، پایگاه داده نمی‌تواند روی دستگاه کلاینت که اپلت را اجرا می‌کند قرار گیرد. بنابراین با وضعیت زیر مواجه می‌شویم:

Image

ماشینی که اپلِت را اجرا می‌کند، سرور و ماشینی که میزبان پایگاه داده است ممکن است سه ماشین مجزا باشند. در اینجا فرض می‌کنیم که پایگاه داده روی سرور قرار دارد.

مسئله ۱

برنامهٔ سرور زیر را به زبان جاوا بنویسید:

  • برنامهٔ سرور روی پورتی که به‌عنوان پارامتر به آن ارسال می‌شود، اجرا می‌شود
  • وقتی یک کلاینت متصل می‌شود، برنامهٔ سرور پیام را ارسال می‌کند
200 - Bienvenue - Envoyez votre requête
  • سپس کلاینت پارامترهای لازم برای اتصال به پایگاه داده و پرس‌وجویی را که می‌خواهد اجرا کند، به شکل زیر ارسال می‌کند:
Pilote Java/URL base/UID/MDP/requête SQL

پارامترها با یک اسلش از هم جدا می‌شوند. چهار پارامتر اول مربوط به برنامه sql3 توصیف‌شده در این فصل هستند.

  • سپس برنامهٔ سرور به پایگاه دادهٔ مشخص‌شده که باید روی همان ماشین برنامه قرار داشته باشد، متصل می‌شود و پرس‌وجوی SQL را روی آن اجرا می‌کند. نتایج به شکل زیر به کلاینت بازگردانده می‌شوند:
100 - ligne1
100 - ligne2

...

اگر نتیجه یک پرس‌وجوی SELECT باشد، یا

101 - nbLignes

برای بازگرداندن تعداد ردیف‌های تحت تأثیر یک پرس‌وجوی به‌روزرسانی. اگر خطای اتصال به پایگاه داده یا خطای اجرای پرس‌وجو رخ دهد، برنامه بازمی‌گرداند

500 - Message d’erreur
  • پس از اجرای پرس‌وجو، برنامهٔ سرور اتصال را می‌بندد.

مسئله ۲

یک اپلت جاوا بسازید که بتواند از سرور توصیف‌شده در بالا پرس‌وجو کند. می‌توانید از رابط گرافیکی در تمرین ۱ بالا الهام بگیرید. از آنجا که پورت سرور ممکن است متفاوت باشد، از طریق رابط اپلت وارد می‌شود. همین امر در مورد تمام پارامترهای لازم برای ارسال خط نیز صدق می‌کند:

Pilote Java/URL base/UID/MDP/requête SQL

که کلاینت باید آن را به سرور ارسال کند.

6.4.3. تمرین ۳

متن زیر مشکلی را توصیف می‌کند که در اصل برای حل شدن در ویژوال بیسیک در نظر گرفته شده بود. آن را برای پیاده‌سازی در جاوا در یک اپلت تطبیق دهید. این اپلت به سرور تمرین ۲ متکی خواهد بود. رابط کاربری گرافیکی می‌تواند برای در نظر گرفتن زمینه اجرایی جدید اصلاح شود.

هدف ایجاد یک برنامه‌ای است که عملیات‌های مختلف به‌روزرسانی ممکن بر روی یک جدول در پایگاه داده ACCESS را نشان دهد. پایگاه داده ACCESS با نام articles.mdb شناخته می‌شود. این پایگاه داده شامل یک جدول واحد به نام «articles» است که اقلام فروخته‌شده توسط یک شرکت را فهرست می‌کند. ساختار آن به شرح زیر است:

name
نوع
code
کد محصول ۴ کاراکتری
nom
نام آن (رشتهٔ کاراکتری)
prix
قیمت آن (واقعی)
stock_actu
میزان موجودی فعلی آن (اعداد صحیح)
stock_mini
حداقل سطح موجودی (اعداد صحیح) که زیر آن باید کالا دوباره موجودی شود

پیشنهاد می‌کنیم این جدول را با استفاده از فرم زیر مشاهده و به‌روزرسانی کنیم:

Image

کنترل‌های فرم به شرح زیر است:

خیر.
نوع
نام
عملکرد
۱
جعبه‌متنی
رکورد
شماره رکورد در حال مشاهده
'enabled' روی false تنظیم شده است
2
کادر متن
کد
کد آیتم
۳
کادر متن
نام
نام آیتم
۴
 
قیمت
قیمت آیتم
۵
 
فعلی
موجودی فعلی کالا
۶
کادر متن
حداقل
حداقل موجودی برای کالا
۷
داده‌ها
data1
اعتبارسنجی داده‌ها مرتبط با پایگاه داده
databasename=مسیر فایل articles.mdb
recordsource=articles
connect=access
8
HScrollBar
موقعیت
به شما امکان می‌دهد در جدول پیمایش کنید
۹
دکمه
OK
امکان تأیید به‌روزرسانی را فراهم می‌کند – تنها زمانی ظاهر می‌شود که در حال انجام به‌روزرسانی باشد
10
دکمه
لغو
به شما امکان می‌دهد یک به‌روزرسانی را لغو کنید – فقط در حین به‌روزرسانی نمایش داده می‌شود
۱۱
فریم
فریم۱
برای اهداف زیبایی‌شناختی
12
جعبه‌متن
نام پایه
نام پایگاه دادهٔ باز
'enabled' روی 'false' تنظیم شده است
۱۳
textbox
نام منبع
نام جدول باز
'enabled' روی 'false' تنظیم شده است

ایجاد صفحه‌ورق در VB

تأیید
ویژگی‌های ویژه
data1
میدان‌های 'databasename' و 'recordsource' پر شده‌اند. 'databasename' باید به پایگاه داده Access با نام articles.mdb در دایرکتوری شما اشاره کند و 'recordsource' به جدول 'articles' اشاره کند.
code
این یک کادر متن است که می‌خواهیم آن را به فیلد «code» رکورد جاری در «data1» متصل کنیم. برای این کار، دو فیلد را پر می‌کنیم:
datasource: مقدار 'data1' را وارد کنید تا نشان دهید که این کادر متن به جدول مرتبط با 'data1' پیوند خورده است
datafield: فیلد «code» را از جدول «articles» انتخاب می‌کنیم
پس از انجام این مراحل، کادر متن «code» همیشه حاوی فیلد «code» رکورد جاری در data1 خواهد بود. برعکس، تغییر محتوای این کادر متن، فیلد «code» رکورد جاری را به‌روزرسانی می‌کند.
همین کار را برای سایر کادرهای متنی نیز انجام دهید
nom
منبع داده: data1 میدان داده: name
prix
منبع داده: data1 فیلد داده: price
actuel
منبع داده: data1 میدان داده: stock_actu
minimum
منبع داده: data1 میدان داده: stock_mini

منوها

ساختار منو به شرح زیر است

ویرایش
گشت‌وگذار
خروج
افزودن
بازگشت
 
ویرایش
بعدی
 
حذف
اول
 
 
آخرین
 

نقش گزینه‌های مختلف به شرح زیر است:

منو
نام
تابع
Ajouter
افزودن منو
برای افزودن یک رکورد جدید به جدول اقلام
Supprimer
حذف
برای حذف رکورد نمایش‌داده‌شده در جدول اقلام
Modifier
mnumodify
برای ویرایش رکورد نمایش‌داده‌شده در جدول آیتم‌ها
Précédent
mnuprecedent
برای حرکت به رکورد قبلی
Suivant
mnusuivant
برای رفتن به رکورد بعدی
Premier
قبلی
رفتن به اولین رکورد
Dernier
mnudernier
برای رفتن به آخرین رکورد
Quitter
خروج
برای خروج از برنامه

در حال بارگذاری صفحه

در طول رویداد form_load، جدولی که با data1 مرتبط است باز می‌شود (data1.refresh). اگر جدول باز نشود، پیغام خطا نمایش داده می‌شود و برنامه خاتمه می‌یابد (end). در غیر این صورت، فرم نمایش داده می‌شود و اولین رکورد جدول articles را نشان می‌دهد. نمی‌توان داده‌ای در فیلدها وارد کرد (ویژگی 'enabled' روی false تنظیم شده است). ورود داده تنها از طریق گزینه‌های 'Add' و 'Edit' امکان‌پذیر است. دکمه‌های 'OK' و 'Cancel' پنهان هستند (visible=false).


بخش ۱

ما پیشنهاد می‌کنیم که رویه‌های مرتبط با گزینه‌های مختلف منو و همچنین دکمه‌های OK و «Cancel» ایجاد شوند. در ابتدا، ما نکات زیر را نادیده می‌گیریم:

  • فعال/غیرفعال‌سازی برخی گزینه‌های منو: برای مثال، گزینه «بعدی» باید زمانی که مکان‌نما روی آخرین رکورد جدول قرار دارد، غیرفعال شود
  • مدیریت نوار پیمایش افقی

منوی مرور/بعدی

  • در صورتی که در انتهای فایل نباشید، به رکورد بعدی می‌رود (data1.RecordSet.MoveNext). بخش متن رکورد را به‌روزرسانی می‌کند (data1.recordset.absoluteposition/ data1.recordset.recordcount).

منوی مرور/قبلی

  • در صورت نرسیدن به انتهای فایل (data1.RecordSet.BOF)، به رکورد قبلی (data1.RecordSet.MovePrevious) می‌رود. کادر متن رکورد را به‌روزرسانی می‌کند.

منوی مرور/اولین

  • به اولین رکورد (data1.RecordSet.MoveFirst) می‌رود اگر فایل خالی نباشد (data1.recordset.recordcount=0). کادر متن رکورد را به‌روزرسانی می‌کند.

منوی مرور/آخرین

  • به آخرین رکورد (data1.RecordSet.MoveLast) می‌رود اگر فایل خالی نباشد (data1.recordset.recordcount=0). کادر متن رکورد را به‌روزرسانی می‌کند.

منوی ویرایش/افزودن

  • امکان افزودن یک رکورد به جدول را برای شما فراهم می‌کند
  • وارد حالت افزودن رکورد می‌شود (data1.recordset.addnew)
  • امکان وارد کردن اطلاعات در ۵ فیلد: کد، نام، قیمت و غیره را فراهم می‌کند (فعال=true)
  • منوهای ویرایش، مرور و خروج را غیرفعال می‌کند (enabled=false)
  • نمایش دکمه‌های OK و لغو (visible=true)

دکمه OK

  • ذخیره تغییر رکورد (data1.recordset.Update)
  • دکمه‌های OK و لغو را مخفی می‌کند (visible=false)
  • گزینه‌های ویرایش، مرور و خروج را فعال می‌کند (enabled=true)
  • بخش متن رکورد را به‌روزرسانی می‌کند

دکمه لغو

  • لغو به‌روزرسانی رکورد (data1.recordset.CancelUpdate)
  • دکمه‌های OK و لغو را مخفی می‌کند (visible=false)
  • فعال‌سازی گزینه‌های ویرایش، مرور و خروج (enabled=true)
  • بخش متن رکورد اصلی را به‌روزرسانی می‌کند

منوی ویرایش/اصلاح

  • اجازه می‌دهد رکورد نمایش‌داده‌شده در فرم ویرایش شود
  • وارد حالت ویرایش رکورد (data1.recordset.edit) می‌شود
  • ورودی داده‌ها را در ۴ فیلد: نام، قیمت و غیره (enabled=true) فعال می‌کند اما در فیلد کد (enabled=false) فعال نمی‌کند
  • منوهای ویرایش، مرور و خروج را غیرفعال می‌کند (enabled=false)
  • دکمه‌های OK و لغو را نمایش می‌دهد (visible=true)

منوی ویرایش/حذف

  • امکان حذف (data1.recordset.delete) رکوردی را که در جدول نمایش داده می‌شود، فراهم می‌کند
  • به رکورد بعدی منتقل می‌شود (data1.recordset.movenext)

منوی خروج

  • برگه را تخلیه می‌کند (unload me)

رویداد form_unload (لغو به صورت عدد صحیح)

  • توسط عملیات «unload me» یا با بستن فرم با کلیدهای Alt-F4 یا دوبار کلیک روی کادر سیستم، بنابراین لزوماً توسط گزینه «Exit» نیست.
  • سؤال «آیا واقعاً می‌خواهید از برنامه خارج شوید؟» را با دو دکمه: بله/خیر (MsgBox با style=vbyes+vbno) نمایش می‌دهد
  • اگر پاسخ «خیر» (=vbno) باشد، مقدار «cancel» روی -1 تنظیم شده و رویه form_unload خاتمه می‌یابد. مقدار -1 برای «cancel» نشان‌دهنده این است که بستن پنجره رد شده است.
  • اگر پاسخ بله (=vbyes) باشد، پایگاه داده بسته می‌شود (data1.recordset.close, data1.database.close).

بخش ۲ – مدیریت منو

در اینجا ما به فعال‌سازی/غیرفعال‌سازی منوها می‌پردازیم. پس از هر عملی که رکورد جاری را تغییر می‌دهد، فرایندی را که آن را Oueston می‌نامیم فراخوانی خواهیم کرد. این فرایند شرایط زیر را بررسی می‌کند:

. اگر فایل خالی باشد، ما

  • منوهای مرور و ویرایش/حذف را غیرفعال کنید،
  • سایر منوها را فعال می‌کنیم

. اگر رکورد فعلی اولین رکورد باشد، ما

  • غیرفعال کردن «مرور» و «پیشین»
  • و بقیه را مجاز می‌کند

. اگر رکورد فعلی آخرین باشد، ما

  • غیرفعال کردن «مرور/بعدی»
  • بقیه را مجاز می‌کند

بخش ۳ – مدیریت اسلایدر افقی

یک اسلایدر افقی سه فیلد مهم دارد:

  • min: حداقل مقدار آن
  • max: حداکثر مقدار آن
  • مقدار: مقدار فعلی آن

ابتدایی‌سازی درایو

پس از بارگذاری (form_load)، درایو به شرح زیر راه‌اندازی خواهد شد:

  • min=0
  • max=data1.recordset.recordcount-1
  • value=1

توجه داشته باشید که بلافاصله پس از باز شدن پایگاه داده (data1.refresh)، تعداد رکوردها در جدولی که توسط data1.recordset.recordcount نمایش داده می‌شود، نادرست است. برای صحیح شدن، باید به انتهای جدول (MoveLast) بروید و سپس به ابتدای جدول (MoveFirst) بازگردید.

اقدام مستقیم روی درایو

موقعیت نشانگر درایو نمایانگر موقعیت در جدول است.

وقتی کاربر درایو را تنظیم می‌کند (که در اینجا «موقعیت» نامیده می‌شود)، رویداد position_change فعال می‌شود. در این رویداد، رکورد جاری در جدول برای انعکاس تنظیم انجام‌شده روی اسلایدر به‌روزرسانی می‌شود. برای این کار از فیلد absoluteposition در data1.recordset استفاده می‌شود. هنگامی که مقدار i به این فیلد اختصاص داده می‌شود، رکورد شماره i در جدول به رکورد جاری تبدیل می‌شود. رکوردها از 0 شماره‌گذاری می‌شوند و بنابراین عددی در بازه [0,data1.recordset.recordcount-1] دارند. در رویه position_change، کافی است بنویسیم

    data1.recordset.absoluteposition=position.value

تا رکورد فعلی نمایش‌داده‌شده در فرم، تنظیم انجام‌شده روی درایو را منعکس کند.

پس از انجام این کار، سپس رویه Oueston را برای به‌روزرسانی منوها فراخوانی خواهیم کرد.

به‌روزرسانی درایو

از آنجا که موقعیت نشانگر درایو باید موقعیت در جدول را منعکس کند، مقدار درایو باید هر زمان که رکورد جاری در جدول تغییر کند، که توسط هر یک از منوها تحریک می‌شود، به‌روزرسانی شود. از آنجا که هر یک از این فراخوانی‌ها رویه Oueston را فرا می‌خواند، بهتر است این به‌روزرسانی را نیز در داخل آن رویه قرار دهید. کافی است موارد زیر را اینجا وارد کنید:

    position.value=data1.recordset.absoluteposition

بخش ۴ – گزینه جستجو

ما در حال افزودن گزینه مرور/جستجو هستیم که به کاربر اجازه می‌دهد با وارد کردن کد یک آیتم، آن را مشاهده کند.

وقتی این گزینه فعال می‌شود، توالی رویدادهای زیر رخ می‌دهد:

  • سیستم به حالت «افزودن جدید» سوئیچ می‌کند، صرفاً برای جلوگیری از تغییر رکورد فعلی که هنگام فعال شدن گزینه باز بود،
  • میدان «کد» قابل ویرایش می‌شود و محتویات میدان «رکورد» پاک می‌شود،
  • منوها غیرفعال می‌شوند و دکمه‌های OK و لغو نمایش داده می‌شوند
  • هنگامی که کاربر روی OK کلیک می‌کند، باید رکورد متناظر با کدی را که کاربر وارد کرده است جستجو کنیم. با این حال، رویه OK_click در حال حاضر برای گزینه‌های «مرور/افزودن» و «مرور/ویرایش» استفاده می‌شود. برای تمایز قائل شدن بین این موارد، باید یک متغیر سراسری را مدیریت کنیم که در اینجا آن را «وضعیت» می‌نامیم و این متغیر سه مقدار ممکن خواهد داشت: «افزودن»، «ویرایش» و «جستجو». رویه‌های مرتبط با دکمه‌های OK و لغو از این متغیر برای تعیین موقعیتی که در آن فراخوانی می‌شوند، استفاده خواهند کرد.
  • اگر `state` روی 'search' تنظیم شود، در داخل رویه‌ای که به OK لینک شده است، ما
    • عملیات addnew (data1.recordset.cancelupdate) را لغو می‌کند، زیرا قصدی برای افزودن رکورد وجود نداشته است. توجه باید به این نکته جلب شود که در این حالت، رکورد فعلی به رکوردی که قبل از عملیات مرور/جستجو (Browse/Search) روی صفحه نمایش داده شده بود، بازمی‌گردد.
    • معیارهای جستجو بر اساس کد ساخته شده و جستجو آغاز می‌شود (data1.recordset.findfirst criteria
    • اگر جستجو ناموفق باشد (data1.recordset.nomatch=true)، به کاربر اطلاع داده می‌شود، سپس سیستم به حالت افزودن (addnew) بازمی‌گردد و از رویه OK خارج می‌شود. کاربر باید یک کد جدید را دوباره وارد کند یا گزینه لغو (Cancel) را انتخاب نماید.
    • اگر جستجو موفقیت‌آمیز باشد، رکورد یافت‌شده به رکورد جاری جدید تبدیل می‌شود. منوها بازگردانده می‌شوند، دکمه‌های OK/Cancel پنهان می‌شوند، ورود اطلاعات در فیلد کد غیرفعال می‌شود و رویه خروجی می‌گیرد.
  • . اگر وضعیت «جستجو» باشد، در داخل رویه‌ای که به لغو پیوند داده شده است، ما
    • عملیات addnew را لغو می‌کند (data1.recordset.cancelupdate). سپس سیستم به‌طور خودکار به رکوردی که قبل از عملیات مرور/جستجو فعال بود بازمی‌گردد.
    • منوها را بازیابی می‌کند، دکمه‌های OK/Cancel را مخفی می‌کند، ورودی در فیلد کد را غیرفعال کرده و از رویه خارج می‌شود.

بخش ۵ – مدیریت کد

یک آیتم باید به‌طور منحصربه‌فرد با کد خود شناسایی شود. اطمینان حاصل کنید که در گزینه مرور/افزودن، اگر کد آیتم رکوردی که قرار است اضافه شود قبلاً در جدول وجود داشته باشد، افزودن رد شود.

6.4.4. تمرین ۴

در اینجا یک برنامه وب مبتنی بر سرور تمرین ۲ ارائه می‌شود. این یک برنامه تجارت الکترونیک پایه است.

مشتری از طریق رابط وب زیر اقلام را سفارش می‌دهد:

Image

آنها می‌توانند اقدامات زیر را انجام دهند:

  • انتخاب یک آیتم از فهرست کشویی
  • مقدار مورد نظر را مشخص می‌کند
  • با استفاده از دکمه Acheter خرید خود را تأیید می‌کند
  • خرید آنها در فهرست اقلام خریداری‌شده نمایش داده می‌شود
  • آنها می‌توانند با انتخاب یک آیتم و کلیک روی دکمه Retirer، آیتم‌ها را از این لیست حذف کنند
  • وقتی روی دکمه Bilan کلیک می‌کنند، خلاصه زیر را مشاهده می‌کنند:

Image

این عبارت به کاربر اجازه می‌دهد جزئیات فاکتور خود را مشاهده کند. کاربر می‌تواند با استفاده از دکمه Informations به جزئیات مربوط به مورد انتخاب‌شده از لیست کشویی دسترسی پیدا کند:

Image

پس از اینکه کاربر جزئیات فاکتور خود را درخواست کرد، می‌تواند آن را در صفحه بعد تأیید کند. برای این کار، باید آدرس ایمیل خود را وارد کرده و با استفاده از دکمه مناسب، سفارش خود را تأیید کند.

Image

قبل از ذخیره سفارش، برنامه درخواست تأیید می‌کند:

Image

پس از تأیید سفارش، اپلیکیشن آن را پردازش کرده و صفحه تأیید را نمایش می‌دهد:

Image

در واقع، اپلیکیشن سفارش را پردازش نمی‌کند. این برنامه صرفاً ایمیلی برای کاربر ارسال می‌کند و از او می‌خواهد که خریدهای خود را پرداخت کند:

Cher client,

Vous trouverez ci-dessous le détail de votre commande au magasin SuperPrix. Elle vous sera livrée après réception de votre chèque établi à l'ordre de SuperPrix et à envoyer à l'adresse suivante :

SuperPrix 
ISTIA 
62 av Notre-Dame du Lac 
49000 Angers 
France

Nous vous remercions vivement de votre commande

---------------------------------------- 
Votre commande 
---------------------------------------- 
article, quantité, prix unitaire, total 
======================================== 
vélo, 2, 1202.00 F, 2404.00 F 
skis nautiques, 3, 1800.00 F, 5400.00 F
Total à payer : 7804 F

سؤال: معادل این برنامهٔ وب را با استفاده از یک اپلِت جاوا ایجاد کنید.