System.Data.SQLite Close () डेटाबेस फ़ाइल को जारी नहीं कर रहा है


93

फ़ाइल को हटाने के प्रयास से पहले मुझे अपने डेटाबेस को बंद करने में समस्या हो रही है। कोड बस है

 myconnection.Close();    
 File.Delete(filename);

और हटाएं एक अपवाद को फेंकता है जो फ़ाइल अभी भी उपयोग में है। मैंने डिबगर में डिलीट () को कुछ मिनटों के बाद फिर से करने की कोशिश की है, इसलिए यह समय का मुद्दा नहीं है।

मेरे पास लेनदेन कोड है, लेकिन यह बंद () कॉल से पहले बिल्कुल नहीं चलता है। इसलिए मुझे पूरा यकीन है कि यह एक खुला लेनदेन नहीं है। खुले और बंद के बीच sql कमांड केवल चयन हैं।

ProcMon मेरा प्रोग्राम और मेरा एंटीवायरस डेटाबेस फ़ाइल को देख रहा है। यह बंद () के बाद db फ़ाइल को जारी करने के लिए मेरे कार्यक्रम को नहीं दिखाता है।

विज़ुअल स्टूडियो 2010, C #, System.Data.SQLite संस्करण 1.0.77.0, Win7

मैंने एक दो साल की बग को इस तरह देखा, लेकिन चैंज कहता है कि यह ठीक है।

क्या मैं जाँच कर सकता हूँ? क्या किसी खुली आज्ञा या लेनदेन की सूची प्राप्त करने का कोई तरीका है?


नया, काम कोड:

 db.Close();
 GC.Collect();   // yes, really release the db

 bool worked = false;
 int tries = 1;
 while ((tries < 4) && (!worked))
 {
    try
    {
       Thread.Sleep(tries * 100);
       File.Delete(filename);
       worked = true;
    }
    catch (IOException e)   // delete only throws this on locking
    {
       tries++;
    }
 }
 if (!worked)
    throw new IOException("Unable to close file" + filename);

क्या आपने कोशिश की: myconnection.Close (); myconnection.Dispose (); ?
उग्येन

1
साइक्लाइट-नेट का उपयोग करते समय , आप उपयोग कर सकते हैं SQLiteAsyncConnection.ResetPool(), विवरण के लिए इस मुद्दे को देखें।
उवे कीम

जवाबों:


109

सी # के लिए एक DB अमूर्त परत लिखते समय थोड़ी देर पहले एक ही समस्या का सामना करना पड़ा और मुझे वास्तव में कभी भी यह पता लगाने के लिए आसपास नहीं मिला कि मुद्दा क्या था। जब आपने अपने पुस्तकालय का उपयोग करते हुए SQLite DB को हटाने का प्रयास किया तो मैंने एक अपवाद फेंक दिया।

वैसे भी, आज दोपहर मैं यह सब फिर से देख रहा था और मुझे लगा कि मैं कोशिश करूंगा और यह पता लगाऊंगा कि यह एक बार और सभी के लिए क्यों किया गया था, इसलिए यहां मैंने अभी तक यही पाया है।

जब आप कॉल करते हैं तो क्या होता SQLiteConnection.Close()है (कई चेक और अन्य चीजों के साथ) SQLiteConnectionHandleजो SQLite डेटाबेस इंस्टेंस को इंगित करता है। यह एक कॉल के माध्यम से किया जाता है SQLiteConnectionHandle.Dispose(), हालांकि यह वास्तव में पॉइंटर को जारी नहीं करता है जब तक कि सीएलआर का कचरा कलेक्टर कुछ कचरा संग्रह नहीं करता है। चूंकि फ़ंक्शन को कॉल करने के लिए SQLiteConnectionHandleओवरराइड CriticalHandle.ReleaseHandle()करता है sqlite3_close_interop()(किसी अन्य फ़ंक्शन के माध्यम से) यह डेटाबेस को बंद नहीं करता है।

मेरे दृष्टिकोण से यह चीजों को करने का एक बहुत ही बुरा तरीका है क्योंकि प्रोग्रामर वास्तव में निश्चित नहीं है जब डेटाबेस बंद हो जाता है, लेकिन यही वह तरीका है जिससे यह किया गया है इसलिए मुझे लगता है कि हमें इसके लिए अभी रहना होगा, या प्रतिबद्ध होना चाहिए। System.Data.SQLite में कुछ बदलाव। किसी भी स्वयंसेवक का ऐसा करने के लिए स्वागत है, दुर्भाग्य से मैं अगले साल से पहले ऐसा करने के लिए समय से बाहर हूं।

टीएल; डीआर समाधान आपके कॉल के बाद SQLiteConnection.Close()और आपके कॉल करने से पहले एक जीसी को मजबूर करना है File.Delete()

यहाँ नमूना कोड है:

string filename = "testFile.db";
SQLiteConnection connection = new SQLiteConnection("Data Source=" + filename + ";Version=3;");
connection.Close();
GC.Collect();
GC.WaitForPendingFinalizers();
File.Delete(filename);

इसके साथ सौभाग्य, और मुझे आशा है कि यह मदद करता है


1
हाँ! धन्यवाद! ऐसा लग रहा है कि जीसी को अपना काम पूरा करने के लिए थोड़ी जरूरत हो सकती है।
टॉम सेरुल

1
आप C # SQLite को भी देखना चाह सकते हैं, मैंने इसे उपयोग करने के लिए अपने सभी कोड को स्थानांतरित कर दिया है। बेशक, अगर आप कुछ महत्वपूर्ण प्रदर्शन कर रहे हैं, तो C शायद C # से तेज है, लेकिन मैं प्रबंधित कोड का प्रशंसक हूं ...
बेंजामिन पाननेल

1
मुझे पता है कि यह पुराना है, लेकिन मुझे कुछ दर्द से बचाने के लिए धन्यवाद। यह बग SQLite के विंडोज मोबाइल / कॉम्पैक्ट फ्रेमवर्क बिल्ड को भी प्रभावित करता है।
StrayPointer

2
अच्छा कार्य! मेरी समस्या का तुरंत समाधान किया। C # विकास के 11 वर्षों में मुझे GC.Clect का उपयोग करने की कभी आवश्यकता नहीं थी। अब यह पहला उदाहरण है जो मैं ऐसा करने के लिए मजबूर हूं।
पिल्सलेटर

10
GC.Collect (); काम करता है, लेकिन System.Data.SQLite.SQLiteConnection.ClearAllPools (); लायब्रेरी के API का उपयोग करके समस्या से संबंधित है।
आरोन हडोन

57

बस GC.Collect()मेरे लिए काम नहीं किया।

फ़ाइल हटाने के साथ आगे बढ़ने के लिए मुझे GC.WaitForPendingFinalizers()बाद GC.Collect()में जोड़ना पड़ा ।


5
यह आश्चर्य की बात नहीं है, GC.Collect()बस एक कचरा संग्रह शुरू होता है जो अतुल्यकालिक है ताकि यह सुनिश्चित हो सके कि सभी को साफ किया गया है आपको इसके लिए स्पष्ट रूप से इंतजार करना होगा।
क्रिसवे जूल

2
मुझे वही अनुभव हुआ, GC.aitForPendingFinalizers () को जोड़ना पड़ा। यह 1.0.103 में था
Vort3x

18

मेरे मामले में मैं SQLiteCommandस्पष्ट रूप से उन्हें निपटाने के बिना वस्तुओं का निर्माण कर रहा था ।

var command = connection.CreateCommand();
command.CommandText = commandText;
value = command.ExecuteScalar();

मैंने अपने आदेश को एक usingबयान में लपेटा और इसने मेरा मुद्दा तय किया।

static public class SqliteExtensions
{
    public static object ExecuteScalar(this SQLiteConnection connection, string commandText)
    {
        using (var command = connection.CreateCommand())
        {
            command.CommandText = commandText;
            return command.ExecuteScalar();
        }
    }
}

usingबयान निपटान में कहा जाता है कि एक अपवाद तब होता है, भले ही यह सुनिश्चित करता है।

फिर कमांड को निष्पादित करना बहुत आसान है।

value = connection.ExecuteScalar(commandText)
// Command object created and disposed

6
मैं इस तरह के अपवादों को निगलने के खिलाफ बहुत सलाह देता हूं
टॉम मैककर्नी

16

एक समान मुद्दा था, हालांकि कचरा कलेक्टर समाधान ने इसे ठीक नहीं किया।

उपयोग के बाद वस्तुओं SQLiteCommandऔर SQLiteDataReaderवस्तुओं का निस्तारण पाया और मुझे कूड़ा उठाने वाले का उपयोग करने से बचाया।

SQLiteCommand command = new SQLiteCommand(sql, db);
command.ExecuteNonQuery();
command.Dispose();

2
बिल्कुल सही। सुनिश्चित करें SQLiteCommandकि यदि आप किसी SQLiteCommandचर को बाद में पुन: चक्रित करते हैं तो भी आप हर किसी को निपटाते हैं।
ब्रूनो बीरी

इसने मेरे लिए काम किया। मैंने किसी भी लेनदेन को निपटाना सुनिश्चित किया।
जे-निकोलस हैकलेमैन

1
महान! आपने मुझे काफी समय बचाया। जब मैंने निष्पादित की गई command.Dispose();प्रत्येक SQLiteCommandचीज़ में इसे जोड़ा, तो यह त्रुटि ठीक हो गई ।
इवान बी

यह भी सुनिश्चित करें कि .Dispose()यदि आपके पास कोई है तो SQLiteTransaction जैसी अन्य वस्तुओं को जारी करें (यानी )।
इवान बी

13

निम्नलिखित ने मेरे लिए काम किया:

MySQLiteConnection.Close();
SQLite.SQLiteConnection.ClearAllPools()

अधिक जानकारी : प्रदर्शन को बेहतर बनाने के लिए SQLite द्वारा कनेक्शनों को पूल किया जाता है। इसका मतलब है कि जब आप किसी कनेक्शन ऑब्जेक्ट पर क्लोज़ विधि को कॉल करते हैं, तो डेटाबेस से कनेक्शन अभी भी जीवित हो सकता है (पृष्ठभूमि में) ताकि अगली ओपन विधि तेजी से हो जाए। जब ​​आप जानते हैं कि आप एक नया कनेक्शन अब नहीं चाहते हैं, ClearAllPools को कॉल करने से सभी कनेक्शन बंद हो जाते हैं जो पृष्ठभूमि और फ़ाइल हैंडल (s?) में ज़िंदा हैं। db फ़ाइल रिलीज़ हो जाती है। फिर db फ़ाइल को किसी अन्य प्रक्रिया द्वारा हटाया, हटाया या उपयोग किया जा सकता है।


1
क्या आप इस बात का स्पष्टीकरण जोड़ सकते हैं कि यह समस्या का अच्छा समाधान क्यों है।
माटस वैटकेविसियस

आप भी इस्तेमाल कर सकते हैं SQLiteConnectionPool.Shared.Reset()। यह सभी कनेक्शनों को बंद कर देगा। विशेष रूप से, यह एक समाधान है यदि आप उपयोग करते हैं SQLiteAsyncConnectionजिसमें कोई Close()विधि नहीं है ।
लोरेंजो पोलिडोरी

9

मुझे एक समान समस्या हो रही थी, मैंने समाधान की कोशिश की है GC.Collectलेकिन, जैसा कि उल्लेख किया गया है, फ़ाइल को लॉक नहीं होने से पहले एक लंबा समय लग सकता है।

मुझे एक वैकल्पिक समाधान मिला है जिसमें SQLiteCommandTableAdapters में अंतर्निहित s का निपटान शामिल है , अतिरिक्त जानकारी के लिए यह उत्तर देखें।


तुम सही थे! कुछ मामलों में सरल 'GC.Collect' ने मेरे लिए काम किया, दूसरों में मुझे GC.Collect को कॉल करने से पहले कनेक्शन से जुड़े किसी भी SqliteCommands को डिस्पोज करना पड़ा वरना यह काम नहीं करेगा!
Eitan HS

1
SQLiteCommand पर कॉलिंग डिस्पोज़ ने मेरे लिए काम किया। एक अलग टिप्पणी के रूप में - यदि आप GC को कॉल कर रहे हैं। तो ध्यान दें कि आप कुछ गलत कर रहे हैं।
नेटली एडम्स

@NathanAdams जब EntityFramework के साथ काम कर रहे हैं तो एक भी कमांड ऑब्जेक्ट नहीं है जिसे आप कभी भी डिस्पोज़ कर सकते हैं। तो या तो EntityFramework ही या EF आवरण के लिए SQLite भी गलत काम कर रहा है।
बसंत 76६

आपका उत्तर सही होना चाहिए। बहुत बहुत धन्यवाद।
अहमद शम्ल

5

यह कोशिश करो ... यह एक उपरोक्त सभी कोड की कोशिश करता है ... मेरे लिए काम किया

    Reader.Close()
    connection.Close()
    GC.Collect()
    GC.WaitForPendingFinalizers()
    command.Dispose()
    SQLite.SQLiteConnection.ClearAllPools()

उम्मीद है की वो मदद करदे


1
WaitForPendingFinalizers ने मेरे लिए सभी अंतर बनाए
टॉड

5

मैं EF और के साथ एक ही समस्या रहा है System.Data.Sqlite

मेरे लिए मैंने पाया SQLiteConnection.ClearAllPools()औरGC.Collect() कि फाइल लॉकिंग कितनी बार घटेगी कम होगी लेकिन यह अभी भी कभी-कभार होगा (लगभग 1% समय)।

मैं जांच कर रहा हूं और ऐसा प्रतीत होता है SQLiteCommandकि ईएफ द्वारा बनाए गए कुछ एस का निपटान नहीं किया गया है और अभी भी उनकी कनेक्शन संपत्ति बंद कनेक्शन पर सेट है। मैंने इन्हें निपटाने की कोशिश की लेकिन एंटिटी फ्रेमवर्क अगले के दौरान एक अपवाद फेंक देगाDbContext पढ़े जाने के - ऐसा लगता है कि ईएफ़ कभी-कभी कनेक्शन बंद होने के बाद भी उनका उपयोग करता है।

मेरा समाधान यह सुनिश्चित करने के लिए था कि Nullजब कनेक्शन कनेक्शन इन SQLiteCommandएस पर बंद हो जाए, तो प्रॉपर्टी सेट हो जाए । यह फ़ाइल लॉक को रिलीज़ करने के लिए पर्याप्त लगता है। मैं नीचे दिए गए कोड का परीक्षण कर रहा हूं और कुछ हज़ार परीक्षणों के बाद कोई फ़ाइल लॉक समस्या नहीं देखी गई है:

public static class ClearSQLiteCommandConnectionHelper
{
    private static readonly List<SQLiteCommand> OpenCommands = new List<SQLiteCommand>();

    public static void Initialise()
    {
        SQLiteConnection.Changed += SqLiteConnectionOnChanged;
    }

    private static void SqLiteConnectionOnChanged(object sender, ConnectionEventArgs connectionEventArgs)
    {
        if (connectionEventArgs.EventType == SQLiteConnectionEventType.NewCommand && connectionEventArgs.Command is SQLiteCommand)
        {
            OpenCommands.Add((SQLiteCommand)connectionEventArgs.Command);
        }
        else if (connectionEventArgs.EventType == SQLiteConnectionEventType.DisposingCommand && connectionEventArgs.Command is SQLiteCommand)
        {
            OpenCommands.Remove((SQLiteCommand)connectionEventArgs.Command);
        }

        if (connectionEventArgs.EventType == SQLiteConnectionEventType.Closed)
        {
            var commands = OpenCommands.ToList();
            foreach (var cmd in commands)
            {
                if (cmd.Connection == null)
                {
                    OpenCommands.Remove(cmd);
                }
                else if (cmd.Connection.State == ConnectionState.Closed)
                {
                    cmd.Connection = null;
                    OpenCommands.Remove(cmd);
                }
            }
        }
    }
}

ClearSQLiteCommandConnectionHelper.Initialise();एप्लिकेशन लोड की शुरुआत में सिर्फ कॉल करने के लिए। यह तब सक्रिय आदेशों की एक सूची रखेगा और Nullजब वे बंद होने वाले कनेक्शन की ओर इशारा करते हैं तो वे अपना कनेक्शन सेट करेंगे ।


मैं भी इस के DisposingCommand भाग में अशक्त करने के लिए कनेक्शन सेट किया था, या मैं कभी-कभी ObjectDisposedException प्राप्त होगा।
इलियट

यह मेरी राय में एक रेखांकित जवाब है। इसने मेरे सफाई मुद्दों को हल कर दिया, जो कि ईएफ परत के कारण मैं खुद नहीं कर सकता था। उस बदसूरत जीसी हैक पर इसका उपयोग करने के लिए बहुत खुश हैं। धन्यवाद!
जेसन टायलर

यदि आप एक बहुपरत वातावरण में इस समाधान का उपयोग करते हैं, तो OpenCommands सूची [थ्रेडस्टैटिक] होनी चाहिए।
बीर

3

उपयोग GC.WaitForPendingFinalizers()

उदाहरण:

Con.Close();  
GC.Collect();`
GC.WaitForPendingFinalizers();
File.Delete(Environment.CurrentDirectory + "\\DATABASENAME.DB");

3

इसी तरह की समस्या थी। कचरा उठाने वाले को बुलाने से मुझे मदद नहीं मिली। LAter मुझे समस्या को हल करने का एक तरीका मिला

लेखक ने यह भी लिखा कि उन्होंने उस डेटाबेस को हटाने का प्रयास करने से पहले उस क्वेरी का चयन किया। मेरी भी यही स्थिति है।

मेरे पास निम्नलिखित कोड हैं:

SQLiteConnection bc;
string sql;
var cmd = new SQLiteCommand(sql, bc);
SQLiteDataReader reader = cmd.ExecuteReader();
reader.Read();
reader.Close(); // when I added that string, the problem became solved.

इसके अलावा, मुझे डेटाबेस कनेक्शन को बंद करने और गारबेज कलेक्टर को कॉल करने की आवश्यकता नहीं है। मुझे केवल इतना करना है कि पाठक को बंद करना है जो SELECT क्वेरी निष्पादित करते समय बनाया गया था


2

मेरा मानना ​​है कि कॉल SQLite.SQLiteConnection.ClearAllPools()सबसे साफ समाधान है। जहां तक ​​मुझे पता है GC.Collect()कि WPF वातावरण में मैन्युअल रूप से कॉल करना उचित नहीं है। हालाँकि, मैंने समस्या को तब तक नोटिस नहीं किया जब तक मैंने System.Data.SQLite3/2016 में 1.0.99.0 को अपग्रेड नहीं किया


2

शायद आपको जीसी से निपटने की आवश्यकता नहीं है। कृपया, जांचें कि क्या सभी sqlite3_prepareको अंतिम रूप दिया गया है।

प्रत्येक के लिए sqlite3_prepare, आपको एक संवाददाता की आवश्यकता है sqlite3_finalize

यदि आप सही ढंग से अंतिम रूप नहीं देते हैं, sqlite3_closeतो कनेक्शन बंद नहीं करेंगे।


1

मैं इसी तरह की समस्या से जूझ रहा था। मुझ पर शर्म करो ... मुझे आखिरकार एहसास हुआ कि पाठक बंद नहीं हुआ था। किसी कारण से मैं सोच रहा था कि संबंधित कनेक्शन बंद होने पर रीडर बंद हो जाएगा। जाहिर है, GC.Collect () ने मेरे लिए काम नहीं किया।
पाठक को "उपयोग: बयान" के साथ लपेटना भी एक अच्छा विचार है। यहां एक त्वरित परीक्षण कोड है।

static void Main(string[] args)
{
    try
    {
        var dbPath = "myTestDb.db";
        ExecuteTestCommand(dbPath);
        File.Delete(dbPath);
        Console.WriteLine("DB removed");
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
    Console.Read();
}

private static void ExecuteTestCommand(string dbPath)
{
    using (var connection = new SQLiteConnection("Data Source=" + dbPath + ";"))
    {
        using (var command = connection.CreateCommand())
        {
            command.CommandText = "PRAGMA integrity_check";
            connection.Open();
            var reader = command.ExecuteReader();
            if (reader.Read())
                Console.WriteLine(reader.GetString(0));

            //without next line database file will remain locked
            reader.Close();
        }
    }   
}

0

मैं EF6 के साथ SQLite 1.0.101.0 का उपयोग कर रहा था और सभी कनेक्शन और संस्थाओं के निपटारे के बाद फाइल को लॉक होने की समस्या थी।

यह EF से अपडेट के साथ खराब हो गया, क्योंकि वे पूरा होने के बाद डेटाबेस को बंद रखते थे। GC.Collect () एकमात्र समाधान था जिसने मदद की और मुझे निराशा होने लगी थी।

हताशा में, मैंने ऑलिवर विकेंडेन्स क्लीयरसक्लाइटकॉन्डकॉन्नेक्शन हेल्पर (8 जुलाई का उसका उत्तर देखें) की कोशिश की। बहुत खुबस। सभी लॉकिंग समस्याएं चली गईं! धन्यवाद ओलिवर।


मुझे लगता है कि यह एक जवाब के बजाय एक टिप्पणी होनी चाहिए
केविन वालिस

1
केविन, मैं सहमत हूं, लेकिन मुझे टिप्पणी करने की अनुमति नहीं दी गई क्योंकि मुझे 50 प्रतिष्ठा (जाहिरा तौर पर) की आवश्यकता है।
टोनी सुलिवन

0

गारबेज कलेक्टर की प्रतीक्षा में हर समय डेटाबेस जारी नहीं हो सकता है और मेरे साथ ऐसा हुआ है। जब किसी प्रकार का अपवाद SQLite डेटाबेस में होता है उदाहरण के लिए प्राइमरीके के लिए मौजूदा मान के साथ एक पंक्ति सम्मिलित करने का प्रयास करते हुए यह डेटाबेस फ़ाइल को तब तक रखेगा जब तक कि आप इसे डिस्पोज नहीं करते। निम्न कोड SQLite अपवाद को पकड़ता है और समस्याग्रस्त कमांड को रद्द करता है।

SQLiteCommand insertCommand = connection.CreateCommand();
try {
    // some insert parameters
    insertCommand.ExecuteNonQuery();
} catch (SQLiteException exception) {
    insertCommand.Cancel();
    insertCommand.Dispose();
}

यदि आप समस्याग्रस्त आदेशों को नहीं संभालते हैं तो गारबेज कलेक्टर के अपवाद उनके बारे में कुछ नहीं कर सकते क्योंकि इन आदेशों के बारे में कुछ अनछुए अपवाद हैं इसलिए वे कचरा नहीं हैं। इस हैंडलिंग विधि ने मेरे लिए कचरा संग्रहकर्ता की प्रतीक्षा में अच्छा काम किया।


0

यह मेरे लिए काम करता है लेकिन मैंने देखा कि कभी-कभी पत्रिका फाइलें -wal -shm प्रक्रिया के बंद होने पर डिलीट नहीं होती हैं। यदि आप चाहते हैं कि SQLite -wal -mm फ़ाइलों को हटा दें जब सभी कनेक्शन अंतिम कनेक्शन बंद कर दें तो गैर-रीडायनली होना चाहिए। आशा है कि यह किसी की मदद करेगा।


0

सबसे अच्छा जवाब जो मेरे लिए काम किया।

dbConnection.Close();
System.Data.SQLite.SQLiteConnection.ClearAllPools();

GC.Collect();
GC.WaitForPendingFinalizers();

File.Delete(Environment.CurrentDirectory + "\\DATABASENAME.DB");
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.