একযোগে ডেটাবেস অ্যাক্সেস
আমার ব্লগে একই নিবন্ধ (আমি আরও ফর্ম্যাটিং পছন্দ করি)
আমি একটি ছোট্ট নিবন্ধ লিখেছিলাম যা আপনার অ্যান্ড্রয়েড ডাটাবেস থ্রেডটিতে কীভাবে অ্যাক্সেস রাখবে তা বর্ণনা করে।
ধরে নিচ্ছি আপনার নিজের SQLiteOpenHelper আছে ।
public class DatabaseHelper extends SQLiteOpenHelper { ... }
এখন আপনি আলাদা থ্রেডে ডাটাবেসে ডেটা লিখতে চান।
// Thread 1
Context context = getApplicationContext();
DatabaseHelper helper = new DatabaseHelper(context);
SQLiteDatabase database = helper.getWritableDatabase();
database.insert(…);
database.close();
// Thread 2
Context context = getApplicationContext();
DatabaseHelper helper = new DatabaseHelper(context);
SQLiteDatabase database = helper.getWritableDatabase();
database.insert(…);
database.close();
আপনি আপনার লগকটে নিম্নলিখিত বার্তা পাবেন এবং আপনার কোনও একটি পরিবর্তন লিখিত হবে না।
android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5)
এটি ঘটছে কারণ প্রতিবার আপনি নতুন এসকিউএলইপেনহেল্পার বস্তুটি তৈরি করার সময় আপনি আসলে নতুন ডাটাবেস সংযোগ তৈরি করছেন making আপনি যদি একই সময়ে প্রকৃত স্বতন্ত্র সংযোগগুলি থেকে ডাটাবেসে লেখার চেষ্টা করেন তবে একটি ব্যর্থ হবে। (উপরের উত্তর থেকে)
একাধিক থ্রেড সহ ডাটাবেস ব্যবহার করতে আমাদের এটি নিশ্চিত করতে হবে যে আমরা একটি ডাটাবেস সংযোগ ব্যবহার করছি।
আসুন সিঙ্গলটন ক্লাসের ডেটাবেস ম্যানেজার তৈরি করি যা একক SQLiteOpenHelper অবজেক্টটি ধরে এবং ফিরে আসবে ।
public class DatabaseManager {
private static DatabaseManager instance;
private static SQLiteOpenHelper mDatabaseHelper;
public static synchronized void initializeInstance(SQLiteOpenHelper helper) {
if (instance == null) {
instance = new DatabaseManager();
mDatabaseHelper = helper;
}
}
public static synchronized DatabaseManager getInstance() {
if (instance == null) {
throw new IllegalStateException(DatabaseManager.class.getSimpleName() +
" is not initialized, call initialize(..) method first.");
}
return instance;
}
public SQLiteDatabase getDatabase() {
return new mDatabaseHelper.getWritableDatabase();
}
}
আপডেট করা কোড যা পৃথক থ্রেডে ডাটাবেসে ডেটা লেখেন এটির মতো দেখাবে।
// In your application class
DatabaseManager.initializeInstance(new MySQLiteOpenHelper());
// Thread 1
DatabaseManager manager = DatabaseManager.getInstance();
SQLiteDatabase database = manager.getDatabase()
database.insert(…);
database.close();
// Thread 2
DatabaseManager manager = DatabaseManager.getInstance();
SQLiteDatabase database = manager.getDatabase()
database.insert(…);
database.close();
এটি আপনার জন্য আরও একটি ক্রাশ নিয়ে আসবে।
java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase
যেহেতু আমরা কেবল একটি ডেটাবেস সংযোগ ব্যবহার করছি, পদ্ধতি getDatbox () থ্রেডড 1 এবং থ্রেড 2 এর জন্য এসকিউএলডিটি ডাটাবেস অবজেক্টের একই উদাহরণ দেয় । কি ঘটছে, থ্রেড 1 ডাটাবেস বন্ধ করতে পারে, যখন থ্রেডড 2 এখনও এটি ব্যবহার করছে। এজন্য আমাদের ইলিজালস্টেট এক্সপশন ক্র্যাশ হয়েছে।
আমাদের নিশ্চিত করতে হবে যে কেউ ডেটাবেস ব্যবহার করছে না এবং কেবল তখনই এটি বন্ধ করে দেওয়া উচিত। স্ট্যাকোভ্লোতে থাকা কিছু লোক আপনার এসকিউএলডিড ডাটাবেসটি কখনই বন্ধ না করার পরামর্শ দেয় । এর ফলে নিম্নলিখিত লগক্যাট বার্তাটি আসবে।
Leak found
Caused by: java.lang.IllegalStateException: SQLiteDatabase created and never closed
কাজের নমুনা
public class DatabaseManager {
private int mOpenCounter;
private static DatabaseManager instance;
private static SQLiteOpenHelper mDatabaseHelper;
private SQLiteDatabase mDatabase;
public static synchronized void initializeInstance(SQLiteOpenHelper helper) {
if (instance == null) {
instance = new DatabaseManager();
mDatabaseHelper = helper;
}
}
public static synchronized DatabaseManager getInstance() {
if (instance == null) {
throw new IllegalStateException(DatabaseManager.class.getSimpleName() +
" is not initialized, call initializeInstance(..) method first.");
}
return instance;
}
public synchronized SQLiteDatabase openDatabase() {
mOpenCounter++;
if(mOpenCounter == 1) {
// Opening new database
mDatabase = mDatabaseHelper.getWritableDatabase();
}
return mDatabase;
}
public synchronized void closeDatabase() {
mOpenCounter--;
if(mOpenCounter == 0) {
// Closing database
mDatabase.close();
}
}
}
এটি নিম্নলিখিত হিসাবে ব্যবহার করুন।
SQLiteDatabase database = DatabaseManager.getInstance().openDatabase();
database.insert(...);
// database.close(); Don't close it directly!
DatabaseManager.getInstance().closeDatabase(); // correct way
প্রতিটি সময় আপনি ডাটাবেস প্রয়োজন আপনাকে কল করা উচিত openDatabase () পদ্ধতি DatabaseManager বর্গ। এই পদ্ধতির অভ্যন্তরে, আমাদের একটি কাউন্টার রয়েছে, যা নির্দেশ করে যে কতবার ডাটাবেস খোলা হয়। যদি এটির সমান হয়, এর অর্থ আমাদের নতুন ডাটাবেস সংযোগ তৈরি করতে হবে, যদি না হয় তবে ডেটাবেস সংযোগ ইতিমধ্যে তৈরি করা হয়েছে।
ক্লোজড্যাটাবেস () পদ্ধতিতে একই ঘটে । যতবার আমরা এই পদ্ধতিটি কল করি, পাল্টা হ্রাস হয়, যখনই এটি শূন্য হয়, আমরা ডাটাবেস সংযোগটি বন্ধ করে দিই।
এখন আপনার আপনার ডাটাবেস ব্যবহার করতে সক্ষম হওয়া উচিত এবং নিশ্চিত হওয়া উচিত যে এটি থ্রেডটি নিরাপদ।