java-sqlite 多线程测试

sqlite

最近准备在项目中使用内存数据库作为缓存使用,听同事说的业界主要是h2和sqlite,经过简单的测试对比,内存模式下,sqlite的性能比h2有将近50%的性能提升。

在进行多线程测试的时候,使用的是sqlilte连接池进行测试,发现sqlite单线程和多线程方式下性能基本没有差别,这引起了我和团队成员的好奇心,下面介绍一下我们发现的过程。

sqlite使用

首先引入sqlite-jdbc.jar包,习惯maven方式

1
2
3
4
5
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.8.7</version>
</dependency>

用sqlite的连接池获取连接

1
2
3
4
5
6
7
8
9
10
11
12
13
Class.forName("org.sqlite.JDBC");
SQLiteConfig config = new org.sqlite.SQLiteConfig();
config.setReadOnly(false);
config.setPageSize(8192); //in bytes
SQLiteConnectionPoolDataSource ds = new SQLiteConnectionPoolDataSource(config);
// SQLiteConnectionPoolDataSource ds = new SQLiteConnectionPoolDataSource();
ds.setDatabaseName("myDatabase");
ds.setUrl("jdbc:sqlite:");//去掉数据库名字,即是内存模式,不会写入磁盘
final PooledConnection pool = ds.getPooledConnection();
Connection conn = pool.getConnection();
Statement stat = conn.createStatement();

测试结果

  • 16线程插入数据库 耗时 6805ms
  • 单线程插入数据库 耗时 7273ms

多线程下性能提升不明显,监控多线程情况如下,可以看到线程是轮流执行的,并不是并行:
sqlite-jdbc多线程

源码分析

查看SQLitePooledConnection.getConnection()方法, 可以看到,每次get之前,都会关闭已有的连接,再去实例化一个新连接,是一个伪’Pooled’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public Connection getConnection() throws SQLException
{
if (handleConn != null)
handleConn.close();
handleConn = (Connection)Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] {Connection.class},
new InvocationHandler()
{
boolean isClosed;
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
// some code
}
});
return handleConn;
}