2011-09-16 89 views
4

我想在android中有一个连接池,因为并行线程必须同时访问数据库。SQLite连接池

Android提供了PooledConnection接口,用于与javax.sql连接一起使用。由于jdbc for SQLite在Android中没有得到官方支持,我正在考虑另一种方法来实现SQLite数据库的连接池。

您对这种方法有什么看法。有什么风险?我忽略了什么?

我的代码如下:

数据库的连接包装类:

public class PoolConnection { 

    protected SQLiteDatabase sqlDb; 
    protected long openedAt; 

    private static final String DB_NAME = Environment 
      .getExternalStorageDirectory() 
      + "/data/DBNAME.sqlite"; 
    private static final int DB_VERSION = 1; 

    private static class DatabaseHelper extends SQLiteOpenHelper { 
     DatabaseHelper(Context context) { 
      super(context, DB_NAME, null, DB_VERSION); 
     } 
     @Override 
     public void onCreate(SQLiteDatabase db) { 
      // nothing to do here 
     } 
     @Override 
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
      // no upgrade planned yet 
     } 
    } 

    public PoolConnection(Context context) throws Exception { 
     sqlDb = new DatabaseHelper(context).getWritableDatabase(); 
     openedAt = System.currentTimeMillis(); 
    } 

    public boolean isAvailable() { 
     if (!sqlDb.isOpen() || sqlDb.inTransaction() 
       || sqlDb.isDbLockedByOtherThreads()) { 
      return false; 
     } else { 
      return true; 
     } 
    } 

    public void close() throws SQLException { 
     sqlDb.close(); 
    } 

    public SQLiteDatabase getConnection() throws SQLException { 
     return sqlDb; 
    } 

    public long getOpenedAt() { 
     return openedAt; 
    } 

} 

和连接池类:

public class ConnectionPool { 

    protected List<PoolConnection> connections; 

    protected long maxIdleTime = 30 * 1000; 

    public ConnectionPool() { 
     connections = Collections 
       .synchronizedList(new ArrayList<PoolConnection>()); 
     new PoolCleaner(maxIdleTime).start(); 
    } 

    public PoolConnection getConnection(Context context) throws Exception { 

     synchronized (connections) { 

      PoolConnection poolCon = null; 

      for (PoolConnection con : connections) { 
       poolCon = con; 
       if (poolCon.isAvailable()) { 
        return poolCon; 
       } 
      } 

     } 

     PoolConnection con = new PoolConnection(context); 

     synchronized (connections) { 
      connections.add(con); 
     } 

     return con; 

    } 

    public void removeExpired() { 

     synchronized (connections) { 
      for (int i = (connections.size() - 1); i >= 0; i--) { 
       PoolConnection con = connections.get(i); 
       if (con.isAvailable() 
         && maxIdleTime < (System.currentTimeMillis() - con 
           .getOpenedAt())) { 
        try { 
         con.close(); 
        } catch (SQLException e) { 
         e.printStackTrace(); 
        } 
        connections.remove(i); 
       } 
      } 
     } 

    } 

    class PoolCleaner extends Thread { 

     protected long cleaningInterval; 
     protected boolean mustStop; 

     public PoolCleaner(long cleaningInterval) { 
      if (cleaningInterval < 0) { 
       throw new IllegalArgumentException(
         "cleaningInterval must be >= 0"); 
      } 
      this.mustStop = false; 
      this.cleaningInterval = cleaningInterval; 

      setDaemon(true); 
     } 

     public void run() { 
      while (!mustStop) { 
       try { 
        sleep(cleaningInterval); 
       } catch (InterruptedException ignore) { 
       } 

       if (mustStop) { 
        break; 
       } 

       removeExpired(); 
      } 
     } 

     public void halt() { 
      mustStop = true; 
      synchronized (this) { 
       this.interrupt(); 
      } 
     } 
    } 

} 

回答

2

有用的相关话题,接受的答案专门针对多线程访问:

What are the best practices for SQLite on Android?

+0

谢谢Brian。所以我的方法会比有用的更危险,因为我可以在链接的文章中阅读。我将为只使用一个DatabaseHelper的方法进行研究。 – Dyonisos

+0

这里是我写/使用的包装,这使得在Android上下文中很好地使用SQLite - [Android的SqlDb](https://github.com/kashifrazzaqui/sqldb) – kashif

0

我不会写我自己的连接池,直到我确信没有其他东西可用。 Apache Commons有一个数据库连接池类。考虑利用自己的维护负担来换取另一个依赖关系。

+0

嗨duffymo。感谢您的回答。由于我正在为非jdbc轻量级连接池进行操作,因此我认为自己写了一个。阿帕奇公用事业非常好,但也很重。 – Dyonisos