Skip to content

20. اپلیکیشن وب MVC در معماری سه‌لایه – مثال ۶، SQL سرور اکسپرس

20.1. پایگاه داده SQL Server Express

در این نسخه، فهرست افراد را در جدول پایگاه داده SQL Server Express 2005 که در URL [http://msdn.microsoft.com/vstudio/express/sql/] در دسترس است، نصب خواهیم کرد. تصاویر زیر از کلاینت EMS Manager Lite برای سرور اکسپرس SQL [http://www.sqlmanager.net/fr/products/mssql/manager] گرفته شده‌اند، یک کلاینت رایگان مدیریت برای SGBD SQL Server Express.

پایگاه داده [dbpersonnes] نام دارد. این پایگاه داده شامل جدولی به نام [PERSONNES] است:

Image

جدول [PERSONNES] شامل فهرست افرادی است که توسط برنامهٔ وب مدیریت می‌شوند. این جدول با استفاده از دستورات زیر در SQL ایجاد شده است:

CREATE TABLE [dbo].[PERSONNES] (
  [ID] int IDENTITY(1, 1) NOT NULL,
  [VERSION] int NOT NULL,
  [NOM] varchar(30) COLLATE French_CI_AS NOT NULL,
  [PRENOM] varchar(30) COLLATE French_CI_AS NOT NULL,
  [DATENAISSANCE] datetime NOT NULL,
  [MARIE] tinyint NOT NULL,
  [NBENFANTS] tinyint NOT NULL,
  PRIMARY KEY CLUSTERED ([ID]),
  CONSTRAINT [PERSONNES_ck_NOM] CHECK ([NOM]<>''),
  CONSTRAINT [PERSONNES_ck_PRENOM] CHECK ([PRENOM]<>''),
  CONSTRAINT [PERSONNES_ck_NBENFANTS] CHECK ([NBENFANTS]>=(0))
)
ON [PRIMARY]
GO
  • خط ۲: کلید اصلی [ID] از نوع عدد صحیح است. ویژگی IDENTITY مشخص می‌کند که اگر ردیفی بدون مقدار برای ستون ID در جدول درج شود، SQL Express به طور خودکار یک عدد صحیح برای آن ستون تولید خواهد کرد. در IDENTITY(1, 1)، پارامتر اول اولین مقدار ممکن برای کلید اصلی است و پارامتر دوم افزایشی است که در تولید اعداد استفاده می‌شود.

جدول [PERSONNES] ممکن است محتویات زیر را داشته باشد:

Image

ما می‌دانیم که وقتی یک شیء [Personne] توسط لایه ما [dao] درج می‌شود، میدان [id] آن شیء قبل از درج برابر با -1 است و پس از آن مقداری غیر از -1 دارد؛ این مقدار کلید اصلی اختصاص‌یافته به سطر جدید درج‌شده در جدول [PERSONNES] است. بیایید با یک مثال ببینیم چگونه می‌توانیم این مقدار را تعیین کنیم.

سفارش SQL

SELECT @@IDENTITY

به ما امکان می‌دهد آخرین مقداری را که در فیلد ID در جدول وارد شده است، بازیابی کنیم. این دستور باید پس از درج اجرا شود. این مورد با پرس‌وجوهای SGBD، [Firebird] و [Postgres] متفاوت است، که در آن‌ها مقدار کلید اصلی شخص در حال افزوده‌شدن قبل از درج درخواست می‌شد، اما مشابه تولید کلید اصلی در SGBD و MySQL است. ما از آن در فایل [personnes-sqlexpress.xml] استفاده خواهیم کرد، که دستورات صادر شده به پایگاه داده SQL را کامپایل می‌کند.

20.2. پروژهٔ Eclipse برای لایه‌های [dao] و [service]

برای توسعه لایه‌های [dao] و [service] اپلیکیشن خود با استفاده از پایگاه داده [SQL Server Express]، از پروژه Eclipse زیر، [mvc-personnes-06]، استفاده خواهیم کرد:

Image

این پروژه یک پروژه ساده جاوا است، نه یک پروژه وب تامکت.


پوشه [src]


این پوشه حاوی کد منبع لایه‌های [dao] و [service] است:

Image

هر فایلی که در نامش «[sqlexpress]» باشد ممکن است نسبت به نسخه‌های Firebird، Postgres و MySQL تغییر کرده باشد یا نکرده باشد. در ادامه تنها آن‌هایی را که تغییر کرده‌اند توضیح می‌دهیم.


پوشه [database]


این پوشه حاوی اسکریپت ایجاد پایگاه داده افراد SQL Express است:

Image

-- SQL مدیر ۲۰۰۵ لایت برای SQL سرور (۲.۲.۰.۱)
-- ---------------------------------------
-- میزبا    ن : (local)\SQLEXPRESS
-- پایگاه داده: dbpersonnes


--
--ساختار جدول PERSONNES: 
--

CREATE TABLE [dbo].[PERSONNES] (
  [ID] int IDENTITY(1, 1) NOT NULL,
  [VERSION] int NOT NULL,
  [NOM] varchar(30) COLLATE French_CI_AS NOT NULL,
  [PRENOM] varchar(30) COLLATE French_CI_AS NOT NULL,
  [DATENAISSANCE] datetime NOT NULL,
  [MARIE] tinyint NOT NULL,
  [NBENFANTS] tinyint NOT NULL,
  CONSTRAINT [PERSONNES_ck_NBENFANTS] CHECK ([NBENFANTS]>=(0)),
  CONSTRAINT [PERSONNES_ck_NOM] CHECK ([NOM]<>''),
  CONSTRAINT [PERSONNES_ck_PRENOM] CHECK ([PRENOM]<>'')
)
ON [PRIMARY]
GO

--
--داده‌ها برای جدول PERSONNE S (LIMIT 0.500)
--

SET IDENTITY_INSERT [dbo].[PERSONNES] ON
GO

INSERT INTO [dbo].[PERSONNES] ([ID], [VERSION], [NOM], [PRENOM], [DATENAISSANCE], [MARIE], [NBENFANTS])
VALUES 
  (1, 1, 'Major', 'Joachim', '19541113', 1, 2)
GO

INSERT INTO [dbo].[PERSONNES] ([ID], [VERSION], [NOM], [PRENOM], [DATENAISSANCE], [MARIE], [NBENFANTS])
VALUES 
  (2, 1, 'Humbort', 'Mélanie', '19850212', 0, 1)
GO

INSERT INTO [dbo].[PERSONNES] ([ID], [VERSION], [NOM], [PRENOM], [DATENAISSANCE], [MARIE], [NBENFANTS])
VALUES 
  (3, 1, 'Lemarchand', 'Charles', '19860301', 0, 0)
GO

SET IDENTITY_INSERT [dbo].[PERSONNES] OFF
GO

--
--تعریف شاخص‌ها: 
--

ALTER TABLE [dbo].[PERSONNES]
ADD PRIMARY KEY CLUSTERED ([ID])
WITH (
  PAD_INDEX = OFF,
  IGNORE_DUP_KEY = OFF,
  STATISTICS_NORECOMPUTE = OFF,
  ALLOW_ROW_LOCKS = ON,
  ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
GO

پوشه [lib]


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

توجه کنید که درایور JDBC [sqljdbc.jar] از SGBD و [Sql Server Express] موجود است. تمام این آرشیوها بخشی از بسته Classpath در پروژه Eclipse را تشکیل می‌دهند.


20.3. لایه [dao]

لایه [dao] به شرح زیر است:

Image

ما تنها تغییرات نسبت به نسخه [Firebird] را برجسته می‌کنیم.

فایل نگاشت [personne-sqlexpress.xml] به شرح زیر است:


<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE sqlMap
    PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
    "http://www.ibatis.com/dtd/sql-map-2.dtd">

<sqlMap>
    <!-- نام مستعار کلاس [Personne] -->
    <typeAlias alias="Personne.classe" 
        type="istia.st.mvc.personnes.entites.Personne"/>
    <!-- جدول نگاشت [PERSONNES] – شیء [Personne] -->
    <resultMap id="Personne.map" 
        class="istia.st.mvc.personnes.entites.Personne">
        <result property="id" column="ID" />
        <result property="version" column="VERSION" />
        <result property="nom" column="NOM"/>
        <result property="prenom" column="PRENOM"/>
        <result property="dateNaissance" column="DATENAISSANCE"/>
        <result property="marie" column="MARIE"/>
        <result property="nbEnfants" column="NBENFANTS"/>
    </resultMap>
    <!-- فهرست همه افراد -->
    <select id="Personne.getAll" resultMap="Personne.map" > select ID, VERSION, NOM, 
        PRENOM, DATENAISSANCE, MARIE, NBENFANTS FROM PERSONNES</select>
    <!--بازیابی یک شخص خاص -->
        <select id="Personne.getOne" resultMap="Personne.map" >select ID, VERSION, NOM, 
        PRENOM, DATENAISSANCE, MARIE, NBENFANTS FROM PERSONNES WHERE ID=#مقدار#</select>
    <!-- افزودن شخص -->
    <insert id="Personne.insertOne" parameterClass="Personne.classe">
        insert into 
        PERSONNES(VERSION, NOM, PRENOM, DATENAISSANCE, MARIE, NBENFANTS) 
        VALUES(#نسخه#, #نام خانوادگی#, #نام#, #dateNaissance#, #نام خانوادگی پس از ازدواج#, 
         #nbEnfants#) 
        <selectKey keyProperty="id">
            select @@IDENTITY as value
        </selectKey>         
    </insert>
    <!-- به‌روزرسانی یک شخص -->
    <update id="Personne.updateOne" parameterClass="Personne.classe"> update 
        PERSONNES set VERSION=#نسخه#+1, NOM=#نام خانوادگی#, PRENOM=#نام#, DATENAISSANCE=#dateNaissance#, 
        MARIE=#marie#, NBENFANTS=#nbEnfants# WHERE QZXW2HTMLCSuqZQX=#id# و 
        VERSION=#نسخه#</update>
    <!--حذف یک شخص -->
    <delete id="Personne.deleteOne" parameterClass="int"> delete FROM PERSONNES WHERE 
        ID=#مقدار# </حذف>
    <!--بازیابی مقدار کلید اصلی [id] آخرین شخص درج‌شده -->
    <select id="Personne.getNextId" resultClass="int">select 
        LAST_INSERT_ID()</select>
</sqlMap>

این فایل دارای همان محتوا با [personnes-firebird.xml] است، با تفاوت‌های جزئی زیر:

  • دستور SQL " Personne.insertOne " در خطوط ۲۹–۳۷ تغییر کرده است:
  • دستور درج SQL قبل از دستور SELECT اجرا می‌شود که مقدار کلید اصلی ردیف درج‌شده را بازیابی خواهد کرد
  • دستور درج SQL برای ستون ID در جدول [PERSONNES] هیچ ارزشی ندارد

این بازتاب‌دهنده مثال درج بحث‌شده در بند 20.1 است. باید توجه داشت که مشکل درج همزمان توسط نخ‌های مختلف، که برای MySQL در بند 19.3 توصیف شده است، در اینجا نیز وجود دارد.

کلاس پیاده‌سازی [DaoImplCommon] لایه [dao] همانند سه نسخه قبلی است.

پیکربندی لایه [dao] برای SGBD و [SQL Express] تطبیق داده شده است. در نتیجه، فایل پیکربندی [spring-config-test-dao-sqlexpress.xml] به شرح زیر است:


<?xml version="1.0" encoding="ISO_8859-1"?>
<!DOCTYPE beans SYSTEM "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <!--منبع داده DBCP -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 
        destroy-method="close">
        <property name="driverClassName">
            <value>com.microsoft.sqlserver.jdbc.SQLServerDriver</value>
        </property>
        <property name="url">
            <value>jdbc:sqlserver://localhost\\SQLEXPRESS:4000;databaseName=dbpersonnes</value>
        </property>
        <property name="username">
            <value>sa</value>
        </property>
        <property name="password">
            <value>msde</value>
        </property>
    </bean>
    <!--SqlMapCllient -->
    <bean id="sqlMapClient" 
        class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
        <property name="dataSource">
            <ref local="dataSource"/>
        </property>
        <property name="configLocation">
            <value>classpath:sql-map-config-sqlexpress.xml</value>
        </property>
    </bean>
    <!-- دسته‌بندی‌های دسترسی برای لایه [dao] -->
    <bean id="dao" class="istia.st.mvc.personnes.dao.DaoImplCommon">
        <property name="sqlMapClient">
            <ref local="sqlMapClient"/>
        </property>
    </bean>
</beans>
  • خطوط ۵–۱۹: بیان [dataSource] اکنون به پایگاه داده [SQL Express] [dbpersonnes] اشاره می‌کند که مدیر آن [sa] با رمز عبور [msde] است. خواننده باید این پیکربندی را برای مطابقت با محیط خود تغییر دهد.
  • خط ۳۱: کلاس [DaoImplCommon] کلاس پیاده‌سازی برای لایه [dao] است

خط ۱۱ نیازمند توضیحاتی است:

            <value>jdbc:sqlserver://localhost\\SQLEXPRESS:4000;databaseName=dbpersonnes</value>
  • //localhost: نشان می‌دهد که سرور SQL Express روی همان دستگاهی که برنامه جاوا ما روی آن است قرار دارد
  • \\SQLEXPRESS: نام یک نمونه از سرور SQL است. به نظر می‌رسد که چندین نمونه می‌توانند همزمان اجرا شوند. بنابراین منطقی است که به نمونه‌ای که در حال آدرس‌دهی آن هستیم، نامی بدهیم. این نام را می‌توان از طریق [SQL Server Configuration Manager] به دست آورد، که معمولاً همزمان با SQL Express نصب می‌شود:

Image

Image

  • ۴۰۰۰: پورت گوش‌دادن برای SQL Express. این بستگی به پیکربندی سرور دارد. به‌طور پیش‌فرض، از پورت‌های پویا استفاده می‌کند که بنابراین از قبل مشخص نیستند. بنابراین هیچ پورتی در URL JDBC مشخص نشده است. در اینجا از یک پورت ثابت، پورت ۴۰۰۰، استفاده کرده‌ایم. این امر از طریق پیکربندی زیر انجام می‌شود:
  • ویژگی dataBaseName پایگاه داده مورد استفاده را مشخص می‌کند. این همان پایگاه داده‌ای است که با کلاینت EMS ایجاد شده است:

Image

پس از اعمال این تغییرات، می‌توانیم به سراغ تست برویم.

20.4. آزمایش لایه‌های [dao] و [service]

تست‌های لایه‌های [dao] و [service] مشابه نسخه [Firebird] هستند. نتایج حاصل به شرح زیر است:

مشخص است که تست‌ها با پیاده‌سازی [DaoImplCommon] با موفقیت پاس شده‌اند. ما نیازی به ارث‌بری از این کلاس نخواهیم داشت، همان‌طور که در مورد SGBD و [Firebird] ضروری بود.

20.5. آزمایش اپلیکیشن [web]

برای تست اپلیکیشن وب با SGBD و [SQL Server Express]، ما یک پروژه اکلیپس ([mvc-personnes-06B]) را به روشی مشابه آنچه برای ساخت پروژه‌های وب قبلی استفاده شد، ایجاد می‌کنیم.

ما پروژه وب [mvc-personnes-05B] را در Tomcat مستقر می‌کنیم:

سرور اکسپرس SGBD SQL راه‌اندازی شد. سپس محتویات جدول [PERSONNES] به شرح زیر است:

Image

سپس Tomcat راه‌اندازی می‌شود. با استفاده از یک مرورگر وب، ما URL [http://localhost:8080/mvc-personnes-06B] را درخواست می‌کنیم:

Image

ما اضافه می‌کنیم یک شخص جدید از طریق لینک [Ajout]:

ما افزودن را در پایگاه داده بررسی می‌کنیم:

Image

از خواننده دعوت می‌شود تا آزمایش‌های بیشتری انجام دهد: [modification, suppression].