Android SQLite DB কখন বন্ধ হবে D


98

আমি অ্যান্ড্রয়েডে একটি এসকিউএল ডাটাবেস নিয়ে কাজ করছি। আমার ডাটাবেস ম্যানেজার একটি সিঙ্গলটন এবং এখনই এটি ডাটাবেসের সাথে সংযোগ খুলবে যখন এটি আরম্ভ করা হয়। পুরো সময় ডাটাবেসটি খোলা রাখা নিরাপদ যাতে কেউ যখন আমার ক্লাসকে ডেটাবেস দিয়ে কাজ করতে ডাকে এটি ইতিমধ্যে খোলা থাকে? অথবা প্রতিটি অ্যাক্সেস প্রয়োজন হওয়ার আগে এবং পরে আমার ডাটাবেসটি খুলতে এবং বন্ধ করা উচিত। পুরোটা সময় খোলা রেখে কি কোনও ক্ষতি আছে?

ধন্যবাদ!

উত্তর:


60

আমি এটা পুরো সময় খুলতে রাখা, এবং যেমন কিছু জীবনচক্র পদ্ধতিতে এটি বন্ধ হবে onStopবা onDestroy। এইভাবে, আপনি সহজেই এটি ব্যবহারের আগে প্রতিবার কল করে isDbLockedByCurrentThreadবা isDbLockedByOtherThreadsএকক SQLiteDatabaseবস্তুতে ডাটাবেসটি ইতিমধ্যে ব্যবহার হচ্ছে কিনা তা পরীক্ষা করে দেখতে পারেন। এটি ডাটাবেসে একাধিক ম্যানিপুলেশনগুলি রোধ করবে এবং আপনার অ্যাপ্লিকেশনটিকে সম্ভাব্য ক্রাশ থেকে রক্ষা করবে

সুতরাং আপনার সিঙ্গলটনে আপনার একক SQLiteOpenHelperবস্তুটি পেতে এই জাতীয় পদ্ধতি থাকতে পারে :

private SQLiteDatabase db;
private MyDBOpenHelper mySingletonHelperField;
public MyDBOpenHelper getDbHelper() {
    db = mySingletonHelperField.getDatabase();//returns the already created database object in my MyDBOpenHelper class(which extends `SQLiteOpenHelper`)
    while(db.isDbLockedByCurrentThread() || db.isDbLockedByOtherThreads()) {
        //db is locked, keep looping
    }
    return mySingletonHelperField;
}

সুতরাং আপনি যখনই নিজের উন্মুক্ত সহায়ক অবজেক্টটি ব্যবহার করতে চান তখন এই গেটর পদ্ধতিটি কল করুন (এটির থ্রেডেড রয়েছে তা নিশ্চিত করুন)

আপনার সিঙ্গলটনে অন্য একটি পদ্ধতি হতে পারে (আপনি উপরের গেটটি কল করার চেষ্টা করার আগে প্রতিটি সময় বলা হয়):

public void setDbHelper(MyDBOpenHelper mySingletonHelperField) {
    if(null == this.mySingletonHelperField) {
        this.mySingletonHelperField = mySingletonHelperField;
        this.mySingletonHelperField.setDb(this.mySingletonHelperField.getWritableDatabase());//creates and sets the database object in the MyDBOpenHelper class
    }
}

আপনি সিঙ্গলটনে ডাটাবেসটিও বন্ধ করতে চাইতে পারেন:

public void finalize() throws Throwable {
    if(null != mySingletonHelperField)
        mySingletonHelperField.close();
    if(null != db)
        db.close();
    super.finalize();
}

যদি আপনার অ্যাপ্লিকেশনটির ব্যবহারকারীরা খুব দ্রুত অনেকগুলি ডাটাবেস ইন্টারঅ্যাকশন তৈরি করার ক্ষমতা রাখেন তবে আপনার উপরে যেমন আমি প্রদর্শন করেছি তেমন কিছু ব্যবহার করা উচিত। তবে যদি সেখানে ন্যূনতম ডাটাবেস ইন্টারঅ্যাকশন হয় তবে আমি এটি নিয়ে চিন্তা করব না এবং প্রতিবারই ডেটাবেস তৈরি এবং বন্ধ করব।


আমি এই পদ্ধতির সাথে 2
টির

4
কাটা খুব খারাপ কৌশল। আমার উত্তর নীচে দেখুন।
মিশেল

4
@ মিক্সেল ভাল পয়েন্ট। আমি বিশ্বাস করি এপিআই 16 উপলব্ধ হওয়ার আগে আমি এই উত্তরটি পোস্ট করেছি তবে আমি ভুল হতে পারি
জেমস

4
@ বিন্নিব আমি মনে করি আপনার উত্তর আপডেট করা ভাল তাই এটি লোককে বিভ্রান্ত না করে।
18-18 এ

4
WARN isDbLockByOtherThreads () সঙ্কলিত এবং এপিআই 16 এর পরে থেকে মিথ্যা প্রত্যাবর্তন করে Also এছাড়াও ডিএসএলকডবাইক্র্যান্টথ্রেড () পরীক্ষা করা অসীম লুপিং দেবে কারণ এটি বর্তমান থ্রেডটি বন্ধ করে দেয় এবং কিছুই 'ডিবি আনলক করতে পারে না' যাতে এই পদ্ধতিটি সত্য ফিরে আসে।
ম্যাটরেশকিন

20

এখন পর্যন্ত অন্য থ্রেড দ্বারা ডাটাবেস লক হয়েছে কিনা তা খতিয়ে দেখার দরকার নেই। আপনি প্রতিটি থ্রেডে সিঙ্গলটন এসকিউএলাইট ওপেনহেলপার ব্যবহার করার সময় আপনি নিরাপদ। isDbLockedByCurrentThreadডকুমেন্টেশন থেকে :

এই পদ্ধতির নামটি এমন এক সময় থেকে আসে যখন ডাটাবেসের সাথে সক্রিয় সংযোগ থাকার অর্থ থ্রেডটি ডাটাবেসে একটি আসল লক ধারণ করে। আজকাল, সত্যিকারের "ডাটাবেস লক" আর নেই, যদিও থ্রেডগুলি কোনও নির্দিষ্ট ক্রিয়াকলাপ সম্পাদনের জন্য ডাটাবেস সংযোগ অর্জন করতে না পারলে ব্লক হতে পারে।

isDbLockedByOtherThreads এপিআই লেভেল 16 থেকে অবহেলিত।


প্রতিটি থ্রেডের জন্য একটি উদাহরণ ব্যবহার করার কোনও মানে নেই। SQLiteOpenHelper থ্রেড নিরাপদ। এটিও খুব স্মৃতিশক্তি অযোগ্য। পরিবর্তে কোনও অ্যাপ্লিকেশনটিতে প্রতি ডেটাবেস SQLiteOpenHelper এর একক উদাহরণ রাখা উচিত। আরও ভাল একযোগের জন্য, WritAheadLogging ব্যবহার করার পরামর্শ দেওয়া হচ্ছে যা 4 টি সংযোগের জন্য সংযোগ পুলিং সরবরাহ করে।
ইজবয়

@ ইজবয় আমার মানে "প্রতি থ্রেডে নয়, প্রতিটি থ্রেডে সিঙ্গলটন (= এক) এসকিউএলাইট ওপেন হেল্পার ব্যবহার করুন"।
মিশ্র

15

প্রশ্ন সম্পর্কিত:

আমার ডাটাবেস ম্যানেজার একটি সিঙ্গলটন এবং এখনই এটি ডাটাবেসের সাথে সংযোগ খুলবে যখন এটি আরম্ভ করা হয়।

আমাদের 'ওপেনিং ডিবি', 'সংযোগ খোলার' ভাগ করা উচিত। SQLiteOpenHelper.getWritableDatabase () একটি খোলা ডিবি দেয়। তবে সংযোগগুলি অভ্যন্তরীণভাবে করা হওয়ায় আমাদের নিয়ন্ত্রণ করতে হবে না।

পুরো সময় ডাটাবেসটি খোলা রাখা নিরাপদ যাতে কেউ যখন আমার ক্লাসকে ডেটাবেস দিয়ে কাজ করতে ডাকে এটি ইতিমধ্যে খোলা থাকে?

হ্যাঁ, তাই লেনদেন সঠিকভাবে বন্ধ থাকলে সংযোগগুলি স্থগিত হয় না। নোট করুন যে জিসি এটি চূড়ান্ত করলে আপনার ডিবিও স্বয়ংক্রিয়ভাবে বন্ধ হয়ে যাবে।

অথবা প্রতিটি অ্যাক্সেস প্রয়োজন হওয়ার আগে এবং পরে আমার ডাটাবেসটি খুলতে এবং বন্ধ করা উচিত।

এসকিউএলডিটি ডাটাবেস দৃষ্টান্তটি বন্ধ করা সংযোগগুলি বন্ধ করার ব্যতীত দুর্দান্ত কিছু দেয় না তবে এই মুহুর্তে কিছু সংযোগ থাকলে এটি কোনও বিকাশকারীর পক্ষে খারাপ। এছাড়াও, এসকিউএলডিট ডাটাবেস.ক্লোজ () এর পরে, এসকিউএলইটওপেনহেল্পার.সেট রাইটিংড্যাটাবেস () একটি নতুন উদাহরণ ফিরে আসবে।

পুরোটা সময় খোলা রেখে কি কোনও ক্ষতি আছে?

না, নেই। এও নোট করুন যে কোনও সম্পর্কযুক্ত মুহুর্তে থ্রিজি বন্ধ করা এবং থ্রেড যেমন অ্যাক্টিভিটি.অনসটপ () এ সক্রিয় সংযোগগুলি বন্ধ করতে পারে এবং ডেটাটি অসামঞ্জস্য অবস্থায় রেখে যেতে পারে।


ধন্যবাদ, আপনার শব্দগুলি "এসকিউএলডিট ডাটাবেস.ক্লোজ () পরে, এসকিউএলইপ ওপেনহেল্পার.সেট রাইটিংডেটাবেস () একটি নতুন উদাহরণ ফিরিয়ে দেবে" আমি বুঝতে পেরেছিলাম যে আমার আবেদনের একটি পুরানো সমস্যার উত্তর আমার কাছে আছে last একটি সমস্যা, যা অ্যান্ড্রয়েড 9 হিজরতের পর সমালোচনামূলক হন (দেখুন stackoverflow.com/a/54224922/297710 )
yvolk

1

অ্যান্ড্রয়েড 8.1 এর একটি SQLiteOpenHelper.setIdleConnectionTimeout(long)পদ্ধতি রয়েছে যা:

পুল থেকে সরানো এবং সরিয়ে দেওয়ার আগে এসকিউএল সংযোগটি নিষ্ক্রিয় হওয়ার অনুমতি দেওয়া সর্বাধিক সংখ্যক মিলিসেকেন্ড সেট করে।

https://developer.android.com/references/android/datedia/sqlite/SQLiteOpenHelper.html#setIdleConnicationTimeout(long)


4
আজকাল এটি অবহেলিত হয়ে উঠেছে।
ম্যাটরেশকিন

1

পারফরম্যান্সের দৃষ্টিকোণ থেকে সর্বোত্তম উপায় হ'ল অ্যাপ্লিকেশন স্তরে এসকিউএলওপেনহেল্পারের একক উদাহরণ রাখা। ডাটাবেস খোলার ব্যয়বহুল হতে পারে এবং এটি একটি ব্লকিং অপারেশন, তাই এটি মূল থ্রেড এবং / অথবা ক্রিয়াকলাপের জীবনচক্র পদ্ধতিতে করা উচিত নয়।

setIdleConnicationTimeout () পদ্ধতি (অ্যান্ড্রয়েড 8.1 তে প্রবর্তিত) ডাটাবেস ব্যবহার না করা অবস্থায় র‌্যাম মুক্ত করতে ব্যবহার করা যেতে পারে। নিষ্ক্রিয় সময়সীমা সেট করা থাকলে, নিষ্ক্রিয়তার একটি সময় পরে ডাটাবেস সংযোগ (গুলি) বন্ধ হয়ে যাবে, অর্থাৎ যখন ডাটাবেস অ্যাক্সেস করা হয়নি। নতুন কোয়েরি কার্যকর করা হলে সংযোগগুলি স্বচ্ছভাবে অ্যাপটিতে পুনরায় খোলা হবে।

যে ছাড়াও, একটি অ্যাপ্লিকেশন কল করতে পারেন releaseMemory () যখন এটি পটভূমি মধ্যে যায় বা মেমরি চাপ, যেমন মধ্যে সনাক্ত করে onTrimMemory ()



-9

আপনার নিজের অ্যাপ্লিকেশন প্রসঙ্গ তৈরি করুন, তারপরে সেখান থেকে ডাটাবেস খুলুন এবং বন্ধ করুন। সংযোগটি বন্ধ করতে আপনি ব্যবহার করতে পারেন সেই অবজেক্টটিতে একটি অন্টার্মিনেট () পদ্ধতিও রয়েছে। আমি এখনও চেষ্টা করে দেখিনি তবে এটি আরও ভাল পদ্ধতির বলে মনে হচ্ছে।

@ বিন্নিবি: আমি সংযোগটি বন্ধ করতে চূড়ান্তকরণ () ব্যবহার করতে চাই না। কাজ করতে পারে তবে জাভা চূড়ান্তকরণ () পদ্ধতিতে যা লেখার কোড আমি বুঝতে পারি তা থেকে একটি খারাপ ধারণা।


আপনি চূড়ান্ত করার উপর নির্ভর করতে চান না কারণ কখন কখন ডাকা হবে তা আপনি জানেন না। জিসি এটিকে পরিষ্কার করার সিদ্ধান্ত না দেওয়া পর্যন্ত কোনও বস্তু লম্বা অবস্থায় থাকতে পারে এবং কেবল তখনই চূড়ান্ত করা হবে () কল করা হবে। এ কারণেই এটি অকেজো। এটি করার সঠিক উপায় হ'ল এমন একটি পদ্ধতি বলা হয় যখন অবজেক্টটি আর ব্যবহার করা হয় না (আবর্জনা সংগ্রহ করা বা না হয় তা নির্বিশেষে) এবং অনটার্মিনেট () ঠিক এটিই।
ইরওয়ান

6
দস্তাবেজগুলি বেশ পরিষ্কারভাবে বলেছে যে onTerminateকোনও উত্পাদন পরিবেশে ডাকা হবে না - developer.android.com/references/android/app/…
এলিয়েজার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.