Sqlite 连接池和批量操作实现
前情提要
针对 Sqlite-OOP 最近重新扩展列出了一些要封装的功能,就对最近实现的连接池和批量操作做一些总结。
自动建表增删查改等基本功能数量查询功能分表分库Sqlite 控制台基础功能类自定义配置加载- 批量操作(事务)
- 缓存库基础功能类实现
- 缓存库和文件库混用实现
- 连接池实现
- 查询分页功能实现
- 备份工具实现
- 密码连接实现
- 带密码数据库生成实现
连接池
连接池,众所周知,做过有数据库的应用的程序员都应该听过这个名词。鉴于数据库是一个独立的系统,应用要想和它交互就需要建立连接,但是就这个过程慢成狗(相比其他操作)。因此,在抗压、响应速度等方面都因为这个瓶颈,相比于其他更慢的语言(比如 python)都没有什么大的优势,就算虚拟机再优化提升也不能提高数据库的效率。所以知道了瓶颈,就能发现问题,解决最慢的部分就是必须要去考虑的,那就是连接。连接最慢的不是通过连接的交互过程,而是建立连接的过程。
解决方案:预先建好一堆连接屯在那里,等到想用的时候拿一个出来直接用,我们称这堆连接和其相关的机制是一个连接池(Connection Pool)。
自定义连接对象包装盒
为了便于管理,需要在容纳原生连接对象的同时记录连接建立时的一些额外信息,以便于连接的管理。至于为什么不用继承,那是为了后期扩展能够更方便、灵活。连接池的实现可以想象成连接对象的生产和消费的市场,每个连接像是一个产品,预先生产出来后,用于应用中不同的地方去消费。而市场的良好状态就是供需平衡,不能频繁出现供不应求和供应过剩的情况。
/**
* Sqlite 连接自定义封装类
* @author 欧阳洁
* @since 2018-05-02 13:26
*/
public class SqliteBaseConnection {
private String uri;//数据库连接
private long createTime;// 时间戳
private Connection connection;// 链接对象
/**
* 重置连接 uri,并且同时会刷新连接对象
* @param uri
*/
public boolean resetUri(String uri){
try {
this.uri = uri;
this.createTime = SqliteUtils.getNowStamp();
if(SqliteBaseConnectionFactory.USE_SELF_INNER_CONFIG){
this.connection = DriverManager.getConnection(uri, SqliteConfig.getConfig().toProperties());
}else {
this.connection = DriverManager.getConnection(uri);
}
return true;
} catch (SQLException e) {
SqliteLogUtils.error("[resetUri] 重置连接对象失败!",e);
e.printStackTrace();
return false;
}
}
/**
* 刷新连接对象
* @return
*/
public boolean refreshConnection(){
try {
this.createTime = SqliteUtils.getNowStamp();
if(SqliteBaseConnectionFactory.USE_SELF_INNER_CONFIG){
this.connection = DriverManager.getConnection(uri, SqliteConfig.getConfig().toProperties());
}else {
this.connection = DriverManager.getConnection(uri);
}
return true;
} catch (SQLException e) {
SqliteLogUtils.error("[refreshConnection] 重新建立连接对象失败!",e);
e.printStackTrace();
return false;
}
}
/**
* 获取连接
* @return
*/
public Connection getConnection() {
if(null == this.connection){
try {
if(SqliteBaseConnectionFactory.USE_SELF_INNER_CONFIG){
this.connection = DriverManager.getConnection(uri, SqliteConfig.getConfig().toProperties());
}else {
this.connection = DriverManager.getConnection(uri);
}
} catch (SQLException e) {
SqliteLogUtils.error("连接建立失败!",e);
e.printStackTrace();
}
}
return connection;
}
...
}
连接工厂功能车间
连接工厂用于提供连接池连接的生产、质检、发放的功能,让连接池公司能够正常的运作的功能车间组。
/**
* Sqlite 连接工厂
* @author 欧阳洁
* @since 2018-05-02 13:30
*/
public class SqliteBaseConnectionFactory {
private static String DEFAULT_DB_PATH = SqliteConfig.getUri();//默认库
private static int CON_MAX = SqliteConfig.getPoolConnectionMax();// 最大池链接
private static int CON_MIN = SqliteConfig.getPoolConnectionMin();// 初始池链接
private static int CON_STEP = SqliteConfig.getPoolConnectionStep();// 每次最大补充线程数量
protected static boolean REFRESH_CON_POOL = false;
protected static boolean USE_CONNECT_POOL = SqliteConfig.isConnectionPoolEnable();
protected static long CON_TIMEOUT = SqliteConfig.getPoolConnectionTimeout();// 超时线程回收
protected static boolean USE_SELF_INNER_CONFIG = SqliteConfig.isConnectionWithCofig();
protected static Vector<SqliteBaseConnection> idleConList = new Vector<SqliteBaseConnection>();// 闲置连接
protected static Vector<SqliteBaseConnection> runConList = new Vector<SqliteBaseConnection>();// 已分配的连接
static {
init();
// 是否启用线程池
if(USE_CONNECT_POOL){
SqliteConnectionPool.initConnectPoolThreads();
}
}
/**
* 初始化连接池
*/
private static void init() {
try {
if(SqliteConfig.isPathBaseClasspath()){
DEFAULT_DB_PATH = SqliteUtils.getClassRootPath(DEFAULT_DB_PATH);
}
loadSqliteJdbcClass();//加载 org.sqlite.JDBC
addConnection(DEFAULT_DB_PATH, CON_MIN);//默认预先建立一些连接到链接对象
} catch (Exception e) {
idleConList.clear();
SqliteLogUtils.error("ERROR:[池初始化失败][池容器已清空]");
e.printStackTrace();
}
}
/**
* 加载 org.sqlite.JDBC
*
* @return 返回结果
*/
private static void loadSqliteJdbcClass() throws ClassNotFoundException {
Class.forName("org.sqlite.JDBC");
}
/**
* 获取链接
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
// 先进先出原则
SqliteBaseConnection currCon = null;
synchronized (idleConList) {
// 当可用连接池不为空时候
if (SqliteUtils.isNotEmpty(idleConList)) {
currCon = idleConList.get(0);
idleConList.remove(0);
addRunningConnection(currCon);
}
if (currCon == null || currCon.getConnection() == null || currCon.getConnection().isClosed()) {
currCon = createBaseConnection();
addRunningConnection(currCon);
}
}
return currCon.getConnection();
}
/**
* 获取链接
*
* @return
* @throws Exception
* @throws SQLException
*/
public static Connection getConnection(String dbPath) throws SQLException {
if(DEFAULT_DB_PATH.equals(dbPath)){
return getConnection();
}else {
SqliteBaseConnection currCon = createBaseConnection(dbPath);
addRunningConnection(currCon);
return currCon.getConnection();
}
}
/**
* 添加已分配的连接到已分配队列
* @param running
* @return
*/
private static boolean addRunningConnection(SqliteBaseConnection running) {
if (runConList.size() < CON_MAX) {
runConList.add(running);
return true;
}
SqliteLogUtils.warn("当前连接数量大于自定义的最大连接数量!");
return false;
}
/**
* 检查容器是否满足使用需求
* @return
*/
protected static boolean checkConnectionBox(String dbPath){
// 如果连接池里闲置的连接没有
int addNum = 0;
if (idleConList.size() == 0) {
// 超过最大线程数
addNum = CON_MAX - runConList.size();
if (addNum <= 0) {
SqliteLogUtils.warn("当前使用的连接数量大于自定义的最大连接 [{}] 限制!", CON_MAX);
return false;
}
} else if (idleConList.size() < CON_MIN) {
addNum = CON_MAX - idleConList.size() - runConList.size();
if (addNum <= 0) {
SqliteLogUtils.warn("连接池中当前使用的连接数量太多,闲置连接数量小于自定义的最小 [{}] 闲置连接!", CON_MIN);
return false;
}
}
// 剩余可增加连接对象数,默认每次最多增加 CON_STEP 个
addNum = addNum > CON_STEP ? CON_STEP : addNum;
if (SqliteUtils.isBlank(dbPath)) {
addConnection(DEFAULT_DB_PATH, addNum);
} else {
addConnection(dbPath, addNum);
}
return true;
}
/**
* 检查闲置连接
* @return 检查到并重置的无效闲置连接数量
* @author 欧阳洁
*/
protected synchronized static int checkAllIdleConnection() {
int idleRefreshCount = 0;
SqliteLogUtils.info("INFO:[可用链接数:{}],[已用连接数:{}]",idleConList.size(),runConList.size());
try {
if (REFRESH_CON_POOL) {//是否刷新闲置连接池里面的连接
for (SqliteBaseConnection con : idleConList) {
if (null == con.getConnection() || con.getConnection().isClosed()) {
con.refreshConnection();
idleRefreshCount++;
}
}
REFRESH_CON_POOL = false;
}
} catch (Exception e) {
SqliteLogUtils.error("ERROR:[新日期检查更新失败][池容器已清空]");
e.printStackTrace();
}
SqliteLogUtils.info("检测到闲置连接池中无效连接并重置的数量:{}",idleRefreshCount);
return idleRefreshCount;
}
/**
* 检查已分配的连接
* @return 清除已分配使用中的无效连接数量
* @author 欧阳洁
*/
protected synchronized static int checkAllRunningConnection() {
int runningRemoveCount = 0;
SqliteLogUtils.info("INFO:[可用链接数:{}],[已用连接数:{}]",idleConList.size(),runConList.size());
SqliteBaseConnection con = null;
for (int i = 0; i < runConList.size(); i++) {
con = runConList.get(i);
try {
if(null == con || null == con.getConnection() || con.getConnection().isClosed() || SqliteUtils.getNowStamp() - con.getCreateTime() > CON_TIMEOUT){
runConList.remove(i--);
runningRemoveCount++;
}
} catch (SQLException e) {
SqliteLogUtils.error("检查已分配的连接出现异常!",e);
e.printStackTrace();
}
}
SqliteLogUtils.info("定时清除已分配的废弃或超时连接,清除数量:{}",runningRemoveCount);
return runningRemoveCount;
}
/**
* 添加新的链接到容器
*
* @param dbPath 数据库的路径
* @param num 添加的数量
* @throws SQLException
*/
private static void addConnection(String dbPath, int num) {
for (int i = 0; i < num; i++) {
// 添加前检查连接池里面所有连接对象
// checkAllIdleConnection();
// 创建新的连接对象
SqliteBaseConnection newSqliteConnection = null;
try {
newSqliteConnection = createBaseConnection(dbPath);
} catch (SQLException e) {
SqliteLogUtils.error("[addConnection] 添加新连接异常!",e);
e.printStackTrace();
}
idleConList.add(newSqliteConnection);
}
}
...
}
连接池工厂员工
此前连接池的基本解决方案就是预先建好一堆连接屯在那里,等到想用的时候拿一个出来直接用。因此这个预先不能在主进程里面去干。当然,上面功能车间已经有了,我们只需要在每个这间里安排相应的员工就行,每个员工负责自己的那部分,工厂就能按部就班的运作了。而这些员工的特性就像一个个线程,各尽其责,互不干扰。
/**
* 池回收线程
*
* @author 欧阳洁
* @since 2018-05-02 13:41
*/
public class SqliteConnectionPool extends SqliteBaseConnectionFactory {
private static int SLEEP = SqliteConfig.getPoolThreadSleep();// 线程每次 SLEEP 时长
private static boolean CHECK_RUN_ACTIVE = false;// 检查 ClearRunConnectionThread 线程是否在
private static boolean CHECK_IDLE_ACTIVE = false;// 检查 RefreshIdleConnectionThread 线程是否在
private static boolean CHECK_MONITOR_ACTIVE = false;// 检查 MonitorConnectionPoolThread 线程是否在
private static int COUNT_RUN_ACTIVE = 0;// 检查 ClearRunConnectionThread 线程活跃数量
private static int COUNT_IDLE_ACTIVE = 0;// 检查 RefreshIdleConnectionThread 线程活跃数量
private static int COUNT_MONITOR_ACTIVE = 0;// 检查 MonitorConnectionPoolThread 线程活跃数量
/**
* LINK 线程池
*/
private static final ExecutorService CONNECTION_POOL_EXETHREAD = new ThreadPoolExecutor(3, 10,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(2000),
SqliteThreadUtils.buildJobFactory("Sqlite 连接池 监控系统 线程池"), new ThreadPoolExecutor.AbortPolicy());
/**
* 获取用于 Sqlite 连接池监控用的线程池服务
* @return
*/
public static ExecutorService getExethread() {
return CONNECTION_POOL_EXETHREAD;
}
/**
* 开启连接池的线程检查,一次性
*/
public static void checkTreadActiveStatus() {
SqliteConnectionPool.CHECK_RUN_ACTIVE = true;
SqliteConnectionPool.CHECK_IDLE_ACTIVE = true;
SqliteConnectionPool.CHECK_MONITOR_ACTIVE = true;
}
/**
* 开启或关闭连接池线程
*/
public static void switchPool(boolean on_off) {
SqliteConnectionPool.USE_CONNECT_POOL = on_off;
if (!on_off) {
idleConList.clear();
runConList.clear();
}
}
/**
* 初始化连接池线程
*/
public static void initConnectPoolThreads() {
SqliteConnectionPool.USE_CONNECT_POOL = true;
// 添加 池监控并适时生产新连接对象的 线程
SqliteConnectionPool.addMonitorConnectionPoolThread();
// 添加 池回收无效或久置超时的连接对象的 线程
SqliteConnectionPool.addClearRunConnectionThread();
// 添加 池检查刷新闲置连接对象的 线程
SqliteConnectionPool.addRefreshIdleConnectionThread();
}
/**
* 监控连接池中已分配的连接对象,定时收取没用的连接对象
*/
public static void addClearRunConnectionThread() {
CONNECTION_POOL_EXETHREAD.execute(new Runnable() {
public void run() {
COUNT_RUN_ACTIVE++;
while (true) {
try {
if (SqliteConnectionPool.CHECK_RUN_ACTIVE) {
SqliteLogUtils.info("池回收无效或久置超时的连接对象的 线程运行中。.. 当前该类线程数量:{}", COUNT_RUN_ACTIVE);
SqliteConnectionPool.CHECK_RUN_ACTIVE = false;
}
if (!SqliteConnectionPool.USE_CONNECT_POOL) {
SqliteLogUtils.info("池回收无效或久置超时的连接对象的 线程结束。.. 当前该类线程数量:{}", COUNT_RUN_ACTIVE - 1);
break;// 如果配置不使用连接池,结束线程
}
SqliteThreadUtils.sleep(SLEEP);
checkAllRunningConnection();
} catch (InterruptedException e) {
idleConList.clear();
runConList.clear();
addClearRunConnectionThread();
SqliteLogUtils.error("ERROR:[池回收无效或久置超时的连接对象的 线程死掉,重新添加新线程!]", e);
e.printStackTrace();
break;
}
}
COUNT_RUN_ACTIVE--;
}
});
}
/**
* 监控连接池中闲置的连接对象,定时收取没用的连接对象
*/
public static void addRefreshIdleConnectionThread() {
CONNECTION_POOL_EXETHREAD.execute(new Runnable() {
public void run() {
COUNT_IDLE_ACTIVE++;
while (true) {
try {
if (SqliteConnectionPool.CHECK_MONITOR_ACTIVE) {
SqliteLogUtils.info("池检查刷新闲置连接对象的 线程运行中。.. 当前该类线程数量:{}", COUNT_IDLE_ACTIVE);
SqliteConnectionPool.CHECK_MONITOR_ACTIVE = false;
}
if (!SqliteConnectionPool.USE_CONNECT_POOL) {
SqliteLogUtils.info("池检查刷新闲置连接对象的 线程结束。.. 当前该类线程数量:{}", COUNT_IDLE_ACTIVE - 1);
break;// 如果配置不使用连接池,结束线程
}
SqliteThreadUtils.sleep(SLEEP);
REFRESH_CON_POOL = true;
checkAllIdleConnection();
} catch (InterruptedException e) {
idleConList.clear();
runConList.clear();
addRefreshIdleConnectionThread();
SqliteLogUtils.error("ERROR:[池检查刷新闲置连接对象的 线程死掉,重新添加新线程!]", e);
e.printStackTrace();
break;
}
}
COUNT_IDLE_ACTIVE--;
}
});
}
/**
* 监控连接池中闲置的连接对象,定时收取没用的连接对象
*/
public static void addMonitorConnectionPoolThread() {
CONNECTION_POOL_EXETHREAD.execute(new Runnable() {
public void run() {
COUNT_MONITOR_ACTIVE++;
while (true) {
try {
if (SqliteConnectionPool.CHECK_IDLE_ACTIVE) {
SqliteLogUtils.info("池监控并适时生产新连接对象的 线程运行中。.. 当前该类线程数量:{}", COUNT_MONITOR_ACTIVE);
SqliteConnectionPool.CHECK_IDLE_ACTIVE = false;
}
if (!SqliteConnectionPool.USE_CONNECT_POOL) {
SqliteLogUtils.info("池监控并适时生产新连接对象的 线程结束。.. 当前该类线程数量:{}", COUNT_MONITOR_ACTIVE - 1);
break;// 如果配置不使用连接池,结束线程
}
SqliteThreadUtils.sleep(SLEEP);
checkConnectionBox(null);
} catch (InterruptedException e) {
idleConList.clear();
runConList.clear();
addMonitorConnectionPoolThread();
SqliteLogUtils.error("ERROR:[池监控并适时生产新连接对象的 线程死掉,重新添加新线程!]", e);
e.printStackTrace();
break;
}
}
COUNT_MONITOR_ACTIVE--;
}
});
}
}
默认配置
# 自定义属性配置
# 默认路径从 class 路径,此时 sqlite.uri 可以写相对路径
sqlite.path.classpath=true
# 数据库路径
sqlite.uri=database/sqlite.db
# 自定义连接池配置
# 是否开启连接池,如果不用配置开启可以手动代码开启:SqliteConnectionPool.initConnectPoolThreads();
sqlite.connection.pool.enable=false
# 最大连接数
sqlite.connection.max=20
# 最少连接数
sqlite.connection.min=10
# 每次最大添加数
sqlite.connection.step=5
# 已分配连接的超时设置,超时会被回收
sqlite.connection.timeout=5000
# 连接池线程轮询间隔
sqlite.pool.thread.sleep=2000
# 用户名密码登陆支持
sqlite.username=
sqlite.password=
# 是否启用非自定义属性的自定义,下面这些属性是 Sqlite 或 JDBC 自带属性,一般有默认值,自定义请在专业选手陪同下,默认不启用
sqlite.config.enable=false
# 内置属性配置 详细请见:https://github.com/petterobam/database-oop/blob/master/sqlite-oop/src/main/resources/config/sqlite.properties
...
批量操作
数据库的增、删、改语句都是独立的句子,每个句子都能独立的表达各自的意思,而不会因为上一句没有,下一句不能独立执行。JDBC 默认执行每个非查询 SQL 语句都会自动提交,完成一个原子操作。然而,每次提交就意味着一次对库的修改操作,这对于常规沟通是没有问题的,也是值得肯定的,但是如果是一个批量修改,一个个提交就太耗时了,而且提交还可能导致连接关闭。所以像这种作文题要把所有的句子组成文章才能交卷,否则时间不够只能交白卷了。
/**
* 非查询语句批量执行 Sql 语句
* @param sqlList
* @param batchCount
* @return
*/
public int batchExecuteSql(List<String> sqlList, int batchCount) {
Connection connection = null;
try {
int result = 0;
if (SqliteUtils.isNotEmpty(sqlList)) {
if (batchCount <= 0) {//默认批量提交粒度 100 条
batchCount = SqliteConstant.DEFAULT_BATCH_COUNT;
}
// create a database connection
connection = this.getConnection();
connection.setAutoCommit(false);//单次执行不自动提交
Statement statement = connection.createStatement();
for (String sql : sqlList) {
if (!SqliteUtils.isBlank(sql)) {
statement.addBatch(sql);
result++;
}
if (result % batchCount == 0) {
statement.executeBatch();
connection.commit();// 提交
if (null == connection || connection.isClosed()) {
//如果连接关闭了 就在创建一个 为什么要这样 原因是 connection.commit() 后可能 conn 被关闭
connection = this.getConnection();
connection.setAutoCommit(false);
statement = connection.createStatement();
}
}
}
statement.executeBatch();
statement.close();
connection.commit();// 提交
connection.setAutoCommit(true);
}
return result;
} catch (SQLException e) {
e.printStackTrace();
return -1;
} finally {
try {
if (connection != null) connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 非查询语句(带参数)批量执行 Sql 语句
*
* @param sqlWithParamList
* @param batchCount
* @return
*/
public int batchExecute(List<T> sqlWithParamList, int batchCount) {
Connection connection = null;
try {
int result = 0;
if (SqliteUtils.isNotEmpty(sqlWithParamList)) {
if (batchCount <= 0) {//默认批量提交粒度 100 条
batchCount = SqliteConstant.DEFAULT_BATCH_COUNT;
}
// create a database connection
connection = this.getConnection();
connection.setAutoCommit(false);//单次执行不自动提交
PreparedStatement prep = null;
String preSql = null;
int currCount = 0;
for (T sqlAndParam : sqlWithParamList) {
if (SqliteUtils.isBlank(sqlAndParam.getCurrentSql())) {
continue;
}
if (!SqliteUtils.equals(preSql, sqlAndParam.getCurrentSql()) || currCount % batchCount == 0) {
if(currCount > 0) {
currCount = 0;
prep.executeBatch();
connection.commit();// 提交
if (null == connection || connection.isClosed()) {
//如果连接关闭了 就在创建一个 为什么要这样 原因是 connection.commit() 后可能 conn 被关闭
connection = this.getConnection();
connection.setAutoCommit(false);
}
}
prep = connection.prepareStatement(sqlAndParam.getCurrentSql());
}
if (SqliteUtils.isNotEmpty(sqlAndParam.getCurrentParam())) {
int count = 1;
for (Object o : sqlAndParam.getCurrentParam()) {
prep.setObject(count++, o);
}
}
prep.addBatch();
result++;
currCount++;
preSql = sqlAndParam.getCurrentSql();
}
prep.executeBatch();
connection.commit();// 提交
connection.setAutoCommit(true);
}
return result;
} catch (SQLException e) {
e.printStackTrace();
return -1;
} finally {
try {
if (connection != null) connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
...
测试
连接池测试
/**
* Sqlite 线程连接池测试
* @author 欧阳洁
* @since 2018-05-03 18:27
*/
public class SqliteConnectionPoolTest {
@Test
public void test() throws ClassNotFoundException {
// 初始化连接池线程
SqliteConnectionPool.initConnectPoolThreads();
// 检查连接池线程
SqliteConnectionPool.checkTreadActiveStatus();
try {
// 取两个连接,观察十秒看线程执行打印日志
SqliteConnectionPool.getConnection();
SqliteThreadUtils.sleep(10000);
// 取三个连接,观察十秒看线程执行打印日志
SqliteConnectionPool.getConnection();
SqliteThreadUtils.sleep(10000);
// 关闭所有连接池线程,观察十秒看线程执行打印日志
SqliteConnectionPool.switchPool(false);
SqliteThreadUtils.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
测试结果:
[sqlite-oop]-[info]-[Fri May 18 22:15:00 CST 2018]-[池检查刷新闲置连接对象的 线程运行中。.. 当前该类线程数量:1]
[sqlite-oop]-[info]-[Fri May 18 22:15:02 CST 2018]-[池监控并适时生产新连接对象的 线程运行中。.. 当前该类线程数量:1]
[sqlite-oop]-[info]-[Fri May 18 22:15:02 CST 2018]-[INFO:[可用链接数:13],[已用连接数:2]]
[sqlite-oop]-[info]-[Fri May 18 22:15:02 CST 2018]-[定时清除已分配的废弃或超时连接,清除数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:02 CST 2018]-[池回收无效或久置超时的连接对象的 线程运行中。.. 当前该类线程数量:1]
[sqlite-oop]-[info]-[Fri May 18 22:15:02 CST 2018]-[INFO:[可用链接数:13],[已用连接数:2]]
[sqlite-oop]-[info]-[Fri May 18 22:15:02 CST 2018]-[检测到闲置连接池中无效连接并重置的数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:04 CST 2018]-[INFO:[可用链接数:13],[已用连接数:2]]
[sqlite-oop]-[info]-[Fri May 18 22:15:04 CST 2018]-[定时清除已分配的废弃或超时连接,清除数量:1]
[sqlite-oop]-[info]-[Fri May 18 22:15:04 CST 2018]-[INFO:[可用链接数:13],[已用连接数:1]]
[sqlite-oop]-[info]-[Fri May 18 22:15:04 CST 2018]-[检测到闲置连接池中无效连接并重置的数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:06 CST 2018]-[INFO:[可用链接数:13],[已用连接数:1]]
[sqlite-oop]-[info]-[Fri May 18 22:15:06 CST 2018]-[定时清除已分配的废弃或超时连接,清除数量:1]
[sqlite-oop]-[info]-[Fri May 18 22:15:06 CST 2018]-[INFO:[可用链接数:13],[已用连接数:0]]
[sqlite-oop]-[info]-[Fri May 18 22:15:06 CST 2018]-[检测到闲置连接池中无效连接并重置的数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:08 CST 2018]-[INFO:[可用链接数:13],[已用连接数:0]]
[sqlite-oop]-[info]-[Fri May 18 22:15:08 CST 2018]-[定时清除已分配的废弃或超时连接,清除数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:08 CST 2018]-[INFO:[可用链接数:13],[已用连接数:0]]
[sqlite-oop]-[info]-[Fri May 18 22:15:08 CST 2018]-[检测到闲置连接池中无效连接并重置的数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:10 CST 2018]-[INFO:[可用链接数:10],[已用连接数:3]]
[sqlite-oop]-[info]-[Fri May 18 22:15:10 CST 2018]-[定时清除已分配的废弃或超时连接,清除数量:3]
[sqlite-oop]-[info]-[Fri May 18 22:15:10 CST 2018]-[INFO:[可用链接数:10],[已用连接数:0]]
[sqlite-oop]-[info]-[Fri May 18 22:15:10 CST 2018]-[检测到闲置连接池中无效连接并重置的数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:12 CST 2018]-[INFO:[可用链接数:10],[已用连接数:0]]
[sqlite-oop]-[info]-[Fri May 18 22:15:12 CST 2018]-[定时清除已分配的废弃或超时连接,清除数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:12 CST 2018]-[INFO:[可用链接数:10],[已用连接数:0]]
[sqlite-oop]-[info]-[Fri May 18 22:15:12 CST 2018]-[检测到闲置连接池中无效连接并重置的数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:14 CST 2018]-[INFO:[可用链接数:10],[已用连接数:0]]
[sqlite-oop]-[info]-[Fri May 18 22:15:14 CST 2018]-[定时清除已分配的废弃或超时连接,清除数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:14 CST 2018]-[INFO:[可用链接数:10],[已用连接数:0]]
[sqlite-oop]-[info]-[Fri May 18 22:15:14 CST 2018]-[检测到闲置连接池中无效连接并重置的数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:16 CST 2018]-[INFO:[可用链接数:10],[已用连接数:0]]
[sqlite-oop]-[info]-[Fri May 18 22:15:16 CST 2018]-[定时清除已分配的废弃或超时连接,清除数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:16 CST 2018]-[INFO:[可用链接数:10],[已用连接数:0]]
[sqlite-oop]-[info]-[Fri May 18 22:15:16 CST 2018]-[检测到闲置连接池中无效连接并重置的数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:18 CST 2018]-[INFO:[可用链接数:10],[已用连接数:0]]
[sqlite-oop]-[info]-[Fri May 18 22:15:18 CST 2018]-[定时清除已分配的废弃或超时连接,清除数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:18 CST 2018]-[INFO:[可用链接数:10],[已用连接数:0]]
[sqlite-oop]-[info]-[Fri May 18 22:15:18 CST 2018]-[检测到闲置连接池中无效连接并重置的数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:20 CST 2018]-[池监控并适时生产新连接对象的 线程结束。.. 当前该类线程数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:20 CST 2018]-[INFO:[可用链接数:5],[已用连接数:0]]
[sqlite-oop]-[info]-[Fri May 18 22:15:20 CST 2018]-[定时清除已分配的废弃或超时连接,清除数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:20 CST 2018]-[池回收无效或久置超时的连接对象的 线程结束。.. 当前该类线程数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:20 CST 2018]-[INFO:[可用链接数:5],[已用连接数:0]]
[sqlite-oop]-[info]-[Fri May 18 22:15:20 CST 2018]-[检测到闲置连接池中无效连接并重置的数量:0]
[sqlite-oop]-[info]-[Fri May 18 22:15:20 CST 2018]-[池检查刷新闲置连接对象的 线程结束。.. 当前该类线程数量:0]
批量操作测试
/**
* Sqlite 批量操作测试
* @author 欧阳洁
* @since 2018-05-14 16:47
*/
public class SqliteBatchTest {
@Test
public void test() throws ClassNotFoundException {
TestTableService sqliteService = new TestTableService();//没有使用 spring 注入,暂时自己构建
sqliteService.delete("delete from t_test_table");
SqliteLogUtils.info("===数据总条数:{}",sqliteService.count(new TestTable()));
List<TestTable> batchList = new ArrayList<TestTable>();
TestTable entity = new TestTable();
entity.setName("test1");
entity.setAuthor("petter");
entity.setArticle("article1");
entity.setCreateTime(SqliteUtils.getStringDate());
batchList.add(entity);
entity = new TestTable();
entity.setName("test2");
entity.setAuthor("petter");
entity.setArticle("article1");
entity.setCreateTime(SqliteUtils.getStringDate());
batchList.add(entity);
entity = new TestTable();
entity.setName("title4");
entity.setAuthor("bob");
entity.setArticle("article2");
entity.setCreateTime(SqliteUtils.getStringDate());
batchList.add(entity);
SqliteLogUtils.info("--开始执行批量插入操作!");
sqliteService.batchInsert(batchList);
SqliteLogUtils.info("--结束执行批量插入操作!");
SqliteLogUtils.info("===数据总条数:{}",sqliteService.count(new TestTable()));
List<TestTable> tableList = sqliteService.query(new TestTable());
if(SqliteUtils.isNotEmpty(tableList)){
tableList.remove(0);
}
for (TestTable testTable : tableList) {
testTable.setName("Update");
}
SqliteLogUtils.info("--开始执行批量修改操作!");
sqliteService.batchUpdate(tableList);
SqliteLogUtils.info("--结束执行批量修改操作!");
SqliteLogUtils.info("===数据总条数:{}",sqliteService.count(new TestTable()));
sqliteService.query(new TestTable());
SqliteLogUtils.info("--开始执行批量删除操作!");
sqliteService.batchDelete(tableList);
SqliteLogUtils.info("--结束执行批量删除操作!");
SqliteLogUtils.info("===数据总条数:{}",sqliteService.count(new TestTable()));
}
}
测试结果:
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[执行非查询语句==> create table if not exists t_test_table(id integer primary key autoincrement not null,name char(100) not null,author char(20) not null,article text ,create_time char(20) not null)]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[执行非查询语句影响行数==> 0]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[执行非查询语句==> delete from t_test_table]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[执行非查询语句影响行数==> 0]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[执行查询语句==> SELECT COUNT(1) FROM t_test_table WHERE 1=1 ]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[===数据总条数:0]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[–开始执行批量插入操作!]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[–结束执行批量插入操作!]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[执行查询语句==> SELECT COUNT(1) FROM t_test_table WHERE 1=1 ]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[===数据总条数:3]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[执行查询语句==> SELECT * FROM t_test_table WHERE 1=1 ]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[执行查询语句结果==> [{"id":1,"name":"test1","author":"petter","article":"article1","createTime":"2018-05-18 22:08:10"},{"id":2,"name":"test2","author":"petter","article":"article1","createTime":"2018-05-18 22:08:10"},{"id":3,"name":"title4","author":"bob","article":"article2","createTime":"2018-05-18 22:08:10"}]]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[–开始执行批量修改操作!]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[–结束执行批量修改操作!]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[执行查询语句==> SELECT COUNT(1) FROM t_test_table WHERE 1=1 ]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[===数据总条数:3]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[执行查询语句==> SELECT * FROM t_test_table WHERE 1=1 ]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[执行查询语句结果==> [{"id":1,"name":"test1","author":"petter","article":"article1","createTime":"2018-05-18 22:08:10"},{"id":2,"name":"Update","author":"petter","article":"article1","createTime":"2018-05-18 22:08:10"},{"id":3,"name":"Update","author":"bob","article":"article2","createTime":"2018-05-18 22:08:10"}]]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[–开始执行批量删除操作!]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[–结束执行批量删除操作!]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[执行查询语句==> SELECT COUNT(1) FROM t_test_table WHERE 1=1 ]
[sqlite-oop]-[info]-[Fri May 18 22:08:10 CST 2018]-[===数据总条数:1]
后记
- 当前的连接池还是属于初级阶段,只是实现基本功能,也没有过多验证其可行性,后期借鉴优秀的连接池思路进一步优化。
- 批量操作只是实现单表的单函数级别批量操作,并没有实现多表操作的批量操作,没有实现事务回滚功能,后期研究。