“ เปิด / ปิด” SqlConnection หรือเปิดค้างไว้?


122

ฉันมีการนำตรรกะทางธุรกิจของฉันไปใช้ในคลาสแบบคงที่ด้วยวิธีการคงที่ แต่ละวิธีเหล่านี้เปิด / ปิดการเชื่อมต่อ SQL เมื่อถูกเรียก:

public static void DoSomething(string something)
{
    using (SqlConnection connection = new SqlConnection("..."))
    {
        connection.Open();

        // ...

        connection.Close();
    }
}

แต่ฉันคิดว่าการหลีกเลี่ยงการเปิดและปิดการเชื่อมต่อจะช่วยประหยัดประสิทธิภาพได้ ฉันทำการทดสอบบางอย่างเมื่อครั้งก่อนด้วยคลาสOleDbConnection (ไม่แน่ใจเกี่ยวกับ SqlConnection) และมันช่วยได้มากในการทำงานเช่นนี้ (เท่าที่ฉันจำได้):

//pass the connection object into the method
public static void DoSomething(string something, SqlConnection connection)
{
    bool openConn = (connection.State == ConnectionState.Open);
    if (!openConn)
    {
        connection.Open();
    }

    // ....

    if (openConn) 
    {
        connection.Close();
    }
}

คำถามคือ - ฉันควรเลือก method (a) หรือ method (b)? ฉันอ่านคำถามสแตกโอเวอร์โฟลว์อื่นที่การเชื่อมต่อร่วมกันบันทึกประสิทธิภาพสำหรับฉันฉันไม่ต้องกังวลเลย ...

PS เป็นแอป ASP.NET - มีการเชื่อมต่อระหว่างการร้องขอทางเว็บเท่านั้น ไม่ใช่วินแอปหรือบริการ


1
เพียงคำแนะนำ: ใช้DbConnection.StateChangeเหตุการณ์เพื่อตรวจสอบการเปลี่ยนแปลงการเปลี่ยนแปลงสถานะของการเชื่อมต่อ (และอาจจัดเก็บไว้ในเครื่อง) แทนที่จะตรวจสอบDbConnection.Stateคุณสมบัติโดยตรง จะช่วยให้คุณประหยัดต้นทุนด้านประสิทธิภาพ
decyclone

1
รายละเอียดอย่างหนึ่งที่ขาดหายไปคือวิธีนี้เป็นส่วนหนึ่งของคำขอเพจ เป็นวิธีเดียวที่เรียกว่าหรือเป็นอย่างที่ฉันสันนิษฐานในคำตอบของฉันหนึ่งในหลาย ๆ วิธีที่ถูกเรียกในการร้องขอหน้าเว็บจะมีผลต่อคำตอบที่ถูกต้อง;)
David Mårtensson

เดวิด - มีการเรียกวิธีการมากมายเช่นนี้ :)
อเล็กซ์

1
กรณี A แสดงการขาดความเชื่อใน Dispose: ดูstackoverflow.com/questions/1195829/…และตัวอย่างบน MSDN msdn.microsoft.com/en-us/library/…
user2864740

คำตอบ:


82

ยึดติดกับตัวเลือกก .

การเชื่อมต่อร่วมกันเป็นเพื่อนของคุณ


37
IMHO - เขาไม่ควรปิดด้วยซ้ำ การกำจัดจะทำ
Royi Namir

2
@RoyiNamir ฉันชอบการโทรเพื่อปิดการเชื่อมต่อ โดยเฉพาะอย่างยิ่งสำหรับผู้เริ่มต้นและผู้มาใหม่ในฐานรหัส มีความชัดเจนและอ่านง่ายกว่า
edhedges

27
@edhedges การใช้ทั้ง "using" และ Close () ในท้ายที่สุดจะทำให้เกิดความสับสนสำหรับผู้มาใหม่ พวกเขาจะไม่เข้าใจวัตถุประสงค์ของการ "ใช้" อย่าใช้ "ปิด" แทนสอนจุดประสงค์ของการ "ใช้" เพื่อให้พวกเขาสามารถเรียนรู้ได้ดีขึ้นและนำสิ่งที่เรียนรู้ไปใช้กับส่วนอื่น ๆ ของโค้ด
Luis Perez

1
ควรเรียก "Open ()" หรือไม่ ฉันกำลังใช้มันในลักษณะนี้: โดยใช้ (var conn = GetConnection ()) {} SqlConnection GetConnection () สาธารณะ {return new SqlConnection (_connectionString); }
ganders

79

ใช้วิธีการ (a) ทุกครั้ง เมื่อคุณเริ่มปรับขนาดแอปพลิเคชันของคุณตรรกะที่เกี่ยวข้องกับสถานะจะกลายเป็นความเจ็บปวดอย่างแท้จริงหากคุณไม่ทำเช่นนั้น

การรวมการเชื่อมต่อทำตามที่กล่าวไว้ในกระป๋อง ลองคิดดูว่าจะเกิดอะไรขึ้นเมื่อแอปพลิเคชันปรับขนาดและจะยากเพียงใดในการจัดการสถานะเปิด / ปิดการเชื่อมต่อด้วยตนเอง กลุ่มการเชื่อมต่อทำงานได้ดีในการจัดการสิ่งนี้โดยอัตโนมัติ หากคุณกังวลเกี่ยวกับประสิทธิภาพให้ลองนึกถึงกลไกแคชหน่วยความจำบางประเภทเพื่อที่จะไม่มีอะไรถูกบล็อก


34

ปิดการเชื่อมต่อทันทีที่คุณดำเนินการเสร็จสิ้นดังนั้นการเชื่อมต่อฐานข้อมูลที่อยู่เบื้องหลังจะสามารถกลับไปที่พูลและพร้อมใช้งานสำหรับผู้โทรรายอื่น การรวมการเชื่อมต่อได้รับการปรับให้เหมาะสมเป็นอย่างดีดังนั้นจึงไม่มีการลงโทษใด ๆ สำหรับการทำเช่นนั้น โดยทั่วไปคำแนะนำจะเหมือนกับการทำธุรกรรม - ให้สั้นและปิดเมื่อคุณทำเสร็จแล้ว

จะมีความซับซ้อนมากขึ้นหากคุณประสบปัญหา MSDTC โดยใช้ธุรกรรมเดียวรอบ ๆ รหัสที่ใช้การเชื่อมต่อหลายรายการซึ่งในกรณีนี้คุณต้องแชร์ออบเจ็กต์การเชื่อมต่อจริง ๆ และปิดเมื่อทำธุรกรรมด้วยเท่านั้น

อย่างไรก็ตามคุณกำลังทำสิ่งต่างๆด้วยตนเองที่นี่ดังนั้นคุณอาจต้องการตรวจสอบเครื่องมือที่จัดการการเชื่อมต่อสำหรับคุณเช่น DataSets, Linq to SQL, Entity Framework หรือ NHibernate


คุณไม่ควรเปิดและปิดการเชื่อมต่อในการเรียกใช้ทุกวิธีเพียงครั้งเดียวสำหรับคำขอแต่ละหน้า นั่นคือสิ่งที่ฉันได้เรียนรู้อย่างน้อย;) เวลาเปิดและปิดต้นทุน
David Mårtensson

8
@David Martensson - การเชื่อมต่อไม่ได้เปิดและปิดจริงเมื่อคุณเรียกใช้ SqlConnection เปิด ASP.NET รีไซเคิลการเชื่อมต่อที่ใช้งานอยู่จากพูลเมื่อสตริงการเชื่อมต่อตรงกับสตริงการเชื่อมต่อที่ใช้ก่อนหน้านี้ ค่าโสหุ้ยที่เกี่ยวข้องกับสิ่งนี้ไม่สำคัญและนอกจากนี้การพยายาม "ทำด้วยตัวเอง" หมายความว่าคุณต้องรับผิดชอบงานการจัดการทั้งหมดเพื่อให้แน่ใจว่าการเชื่อมต่อยังคงทำงานอยู่สำหรับการใช้งานแต่ละครั้งในภายหลังซึ่งจะเพิ่มความซับซ้อนและค่าใช้จ่าย ด้วยการรวมการเชื่อมต่อแนวทางปฏิบัติที่ดีที่สุดคือการเปิดและปิดสำหรับการใช้งานทุกครั้ง
Jamie Treworgy

2
ด้วยความเคารพของฉันคำตอบ "การเชื่อมต่อที่ใกล้ชิดเสมอ" ไม่เหมาะกับคำถามมากนัก ... ฉันปิดมัน คำถามคือ - เมื่อ.
Alex

@David Martensson "หนึ่งครั้งสำหรับแต่ละหน้า" จะใหญ่เกินไป คุณคิดถูกว่าหากคุณมีคำสั่งฐานข้อมูลหลายคำสั่งเพื่อดำเนินการทีละคำสั่งคุณสามารถเปิดการเชื่อมต่อไว้ได้ในขณะที่ดำเนินการ จะมีค่าใช้จ่ายเล็กน้อยหากคุณปิดและเปิดใหม่ - การเชื่อมต่อจะเข้าสู่สระว่ายน้ำและถูกดึงออกมาจากนั้นสักครู่
Concrete Gannet

1
@David Martensson แต่อย่าให้การเชื่อมต่อไม่ได้ใช้งาน หากคุณกำลังรอการดำเนินการจากผู้ใช้หรือเพื่อสิ่งอื่นใดให้ปิด หากมีข้อสงสัยให้ปิด คุณเปิดให้ช้าที่สุดเท่าที่จะทำได้ด้วยความหวังว่าจะมีคนอื่นเชื่อมต่อเสร็จและรวบรวมไว้ จากนั้นคุณจะคืนความโปรดปราน - ปิดให้เร็วที่สุดเท่าที่จะทำได้
Concrete Gannet

13

คำเตือน:ฉันรู้ว่ามันเก่า แต่ฉันพบวิธีง่ายๆในการแสดงให้เห็นถึงข้อเท็จจริงนี้ดังนั้นฉันจึงใส่เงินสองเซนต์ของฉัน

หากคุณมีปัญหาในการเชื่อว่าการรวมกลุ่มจะเร็วขึ้นจริงๆให้ลองทำตาม:

เพิ่มสิ่งต่อไปนี้ที่ใดที่หนึ่ง:

using System.Diagnostics;
public static class TestExtensions
{
    public static void TimedOpen(this SqlConnection conn)
    {
        Stopwatch sw = Stopwatch.StartNew();
        conn.Open();
        Console.WriteLine(sw.Elapsed);
    }
}

ตอนนี้เปลี่ยนสายทั้งหมดไปOpen()ด้วยTimedOpen()และเรียกใช้โปรแกรมของคุณ ตอนนี้สำหรับสตริงการเชื่อมต่อที่แตกต่างกันแต่ละรายการที่คุณมีหน้าต่างคอนโซล (เอาต์พุต) จะเปิดการทำงานที่ยาวนานเพียงครั้งเดียวและการเปิดที่รวดเร็วมาก

หากคุณต้องการติดป้ายกำกับคุณสามารถเพิ่มลงnew StackTrace(true).GetFrame(1) +ในการโทรWriteLineได้


9

มีความแตกต่างระหว่างการเชื่อมต่อทางกายภาพและทางตรรกะ DbConnection เป็นการเชื่อมต่อแบบลอจิคัลชนิดหนึ่งและใช้การเชื่อมต่อทางกายภาพพื้นฐานกับ Oracle การปิด / เปิด DbConnection ไม่ส่งผลกระทบต่อประสิทธิภาพของคุณ แต่ทำให้โค้ดของคุณสะอาดและเสถียร - การรั่วไหลของการเชื่อมต่อเป็นไปไม่ได้ในกรณีนี้

นอกจากนี้คุณควรจำเกี่ยวกับกรณีที่มีข้อ จำกัด สำหรับการเชื่อมต่อแบบขนานบนเซิร์ฟเวอร์ db โดยคำนึงถึงเรื่องนี้ว่าจำเป็นต้องทำให้การเชื่อมต่อของคุณสั้นมาก

พูลการเชื่อมต่อช่วยให้คุณพ้นจากการตรวจสอบสถานะการเชื่อมต่อ - เพียงแค่เปิดใช้และปิดทันที


ใช่การเชื่อมต่อไม่ใช่การเชื่อมต่อนั่นคือ DbConnection ไม่ใช่การเชื่อมต่อทางกายภาพ DbConnection เป็นคลาส. NET ที่จัดเตรียมเมธอดและคุณสมบัติเพื่อจัดการกับการเชื่อมต่อทางกายภาพพื้นฐาน
Concrete Gannet

น่าเสียดายที่มันไม่ชัดเจนในทันทีว่าสิ่งนี้เสร็จสิ้นโดยปริยายทั้งหมด แต่เอกสารประกอบอธิบายไว้อย่างละเอียด docs.microsoft.com/en-us/dotnet/framework/data/adonet/…
Austin Salgat

2

โดยปกติคุณควรเชื่อมต่อหนึ่งรายการสำหรับแต่ละธุรกรรม (ไม่มีการคำนวณแบบขนาน)

เช่นเมื่อผู้ใช้ดำเนินการเรียกเก็บเงินแอปพลิเคชันของคุณจำเป็นต้องค้นหายอดเงินของผู้ใช้ก่อนและอัปเดตพวกเขาควรใช้การเชื่อมต่อเดียวกัน

แม้ว่าแอดเน็ตจะมีพูลการเชื่อมต่อ แต่การจ่ายค่าเชื่อมต่อก็ต่ำมาก แต่การใช้การเชื่อมต่อซ้ำเป็นทางเลือกที่ดีกว่า

ทำไมไม่เก็บการเชื่อมต่อเพียงรายการเดียวในแอปพลิเคชัน

เนื่องจากการเชื่อมต่อถูกบล็อกเมื่อคุณรันเคียวรีหรือคำสั่งบางอย่างนั่นหมายความว่าแอ็พพลิเคชันของคุณกำลังดำเนินการ db เพียงครั้งเดียวใน sametime ประสิทธิภาพต่ำเพียงใด

อีกปัญหาหนึ่งคือแอปพลิเคชันของคุณจะมีการเชื่อมต่ออยู่เสมอแม้ว่าผู้ใช้ของคุณจะเพิ่งเปิด แต่ไม่มีการดำเนินการใด ๆ หากมีผู้ใช้จำนวนมากเปิดแอปพลิเคชันของคุณเซิร์ฟเวอร์ db จะเสียค่าแหล่งเชื่อมต่อทั้งหมดในไม่ช้าในขณะที่ผู้ใช้ของคุณไม่ได้ทำ สิ่งใด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.