全部
This commit is contained in:
@ -27,10 +27,10 @@ public class SQLiteUtil {
|
||||
// 统一日期格式(LocalDateTime)
|
||||
private static final DateTimeFormatter LOCAL_DATE_TIME_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
|
||||
|
||||
// 连接池缓存:key=数据库文件路径、value=DBCP2数据源(支持多连接复用)
|
||||
// 连接池缓存: key=数据库文件路径、value=DBCP2数据源(支持多连接复用)
|
||||
private static final Map<String, BasicDataSource> DATA_SOURCE_POOL = new ConcurrentHashMap<>();
|
||||
|
||||
// 字段缓存:缓存类的字段映射(避免反射重复开销)
|
||||
// 字段缓存: 缓存类的字段映射(避免反射重复开销)
|
||||
private static final Map<Class<?>, Map<String, Field>> FIELD_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
@ -64,17 +64,17 @@ public class SQLiteUtil {
|
||||
dataSource.setUrl("jdbc:sqlite:" + dbFilePath);
|
||||
|
||||
// 2. 连接池核心参数(根据并发量调整、SQLite不建议过多连接)
|
||||
dataSource.setMaxTotal(30); // 最大连接数:20-50(根据服务器CPU/内存调整)
|
||||
dataSource.setMaxIdle(15); // 最大空闲连接:保留部分连接避免频繁创建
|
||||
dataSource.setMinIdle(5); // 最小空闲连接:保证基础并发响应速度
|
||||
dataSource.setTimeBetweenEvictionRunsMillis(60000); // 连接检测间隔:1分钟
|
||||
dataSource.setMinEvictableIdleTimeMillis(300000); // 连接空闲超时:5分钟(清理长期空闲连接)
|
||||
dataSource.setMaxTotal(30); // 最大连接数: 20-50(根据服务器CPU/内存调整)
|
||||
dataSource.setMaxIdle(15); // 最大空闲连接: 保留部分连接避免频繁创建
|
||||
dataSource.setMinIdle(5); // 最小空闲连接: 保证基础并发响应速度
|
||||
dataSource.setTimeBetweenEvictionRunsMillis(60000); // 连接检测间隔: 1分钟
|
||||
dataSource.setMinEvictableIdleTimeMillis(300000); // 连接空闲超时: 5分钟(清理长期空闲连接)
|
||||
|
||||
// 3. 连接有效性验证(避免使用失效连接)
|
||||
dataSource.setTestOnBorrow(true); // 借连接时验证
|
||||
dataSource.setTestOnReturn(false); // 还连接时不验证(减少开销)
|
||||
dataSource.setValidationQuery("SELECT 1"); // 轻量验证SQL(SQLite支持)
|
||||
dataSource.setValidationQueryTimeout(2); // 验证超时:2秒
|
||||
dataSource.setValidationQueryTimeout(2); // 验证超时: 2秒
|
||||
|
||||
// 4. PreparedStatement缓存(减少SQL解析开销)
|
||||
dataSource.setPoolPreparedStatements(true);
|
||||
@ -83,11 +83,11 @@ public class SQLiteUtil {
|
||||
// 5. SQLite底层性能优化(关键!提升并发能力)
|
||||
try (Connection conn = dataSource.getConnection();
|
||||
Statement stmt = conn.createStatement()) {
|
||||
stmt.execute("PRAGMA journal_mode=WAL;"); // 启用WAL模式:支持多读者+单写者(核心优化)
|
||||
stmt.execute("PRAGMA journal_mode=WAL;"); // 启用WAL模式: 支持多读者+单写者(核心优化)
|
||||
stmt.execute("PRAGMA cache_size=-20000;"); // 页面缓存20MB(负号表示KB单位、内存足可调大)
|
||||
stmt.execute("PRAGMA synchronous=NORMAL;"); // 同步级别:平衡性能与安全(崩溃最多丢WAL日志)
|
||||
stmt.execute("PRAGMA synchronous=NORMAL;"); // 同步级别: 平衡性能与安全(崩溃最多丢WAL日志)
|
||||
stmt.execute("PRAGMA temp_store=MEMORY;"); // 临时表/索引存内存(减少磁盘IO)
|
||||
stmt.execute("PRAGMA busy_timeout=2000;"); // 忙等待超时:2秒(避免瞬时并发锁等待)
|
||||
stmt.execute("PRAGMA busy_timeout=2000;"); // 忙等待超时: 2秒(避免瞬时并发锁等待)
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("请检查路径是否存在");
|
||||
@ -108,7 +108,7 @@ public class SQLiteUtil {
|
||||
try {
|
||||
dataSource.close(); // DBCP2会自动关闭所有活跃/空闲连接
|
||||
} catch (SQLException e) {
|
||||
System.err.println("关闭SQLite数据源失败(路径:" + dbFilePath + "):" + e.getMessage());
|
||||
System.err.println("关闭SQLite数据源失败(路径: " + dbFilePath + "): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -121,7 +121,7 @@ public class SQLiteUtil {
|
||||
try {
|
||||
dataSource.close();
|
||||
} catch (SQLException e) {
|
||||
System.err.println("关闭SQLite数据源失败:" + e.getMessage());
|
||||
System.err.println("关闭SQLite数据源失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
// 清理缓存(避免内存泄漏)
|
||||
@ -129,7 +129,7 @@ public class SQLiteUtil {
|
||||
FIELD_CACHE.clear();
|
||||
}
|
||||
|
||||
// JVM关闭钩子:确保程序退出时释放所有数据源资源
|
||||
// JVM关闭钩子: 确保程序退出时释放所有数据源资源
|
||||
static {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(SQLiteUtil::closeAllDataSources));
|
||||
}
|
||||
@ -138,7 +138,7 @@ public class SQLiteUtil {
|
||||
// ========================== 数据查询核心方法 ==========================
|
||||
|
||||
/**
|
||||
* 执行查询并返回单个对象(优化版:连接池+字段缓存)
|
||||
* 执行查询并返回单个对象(优化版: 连接池+字段缓存)
|
||||
*
|
||||
* @param dbFilePath 数据库路径
|
||||
* @param sql 查询SQL
|
||||
@ -152,7 +152,7 @@ public class SQLiteUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行查询并返回对象列表(优化版:预构建字段映射+资源自动回收)
|
||||
* 执行查询并返回对象列表(优化版: 预构建字段映射+资源自动回收)
|
||||
*
|
||||
* @param dbFilePath 数据库路径
|
||||
* @param sql 查询SQL
|
||||
@ -169,7 +169,7 @@ public class SQLiteUtil {
|
||||
// 预加载字段映射(缓存生效、避免重复反射)
|
||||
Map<String, Field> fieldMap = getFieldMap(clazz);
|
||||
|
||||
// try-with-resources:自动关闭Connection、PreparedStatement、ResultSet
|
||||
// try-with-resources: 自动关闭Connection、PreparedStatement、ResultSet
|
||||
try (Connection conn = getConnection(dbFilePath);
|
||||
PreparedStatement pstmt = createPreparedStatement(conn, sql, params);
|
||||
ResultSet rs = pstmt.executeQuery()) {
|
||||
@ -193,20 +193,20 @@ public class SQLiteUtil {
|
||||
resultList.add(obj);
|
||||
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException |
|
||||
InvocationTargetException e) {
|
||||
throw new SQLException("创建对象实例失败(类型:" + clazz.getName() + ")", e);
|
||||
throw new SQLException("创建对象实例失败(类型: " + clazz.getName() + ")", e);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
// 异常时关闭当前数据源(避免后续请求使用异常连接)
|
||||
closeDataSource(dbFilePath);
|
||||
throw new SQLException("执行查询失败(SQL:" + sql + ")", e);
|
||||
throw new SQLException("执行查询失败(SQL: " + sql + ")", e);
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行增删改SQL(优化版:连接池+自动提交)
|
||||
* 执行增删改SQL(优化版: 连接池+自动提交)
|
||||
*
|
||||
* @param dbFilePath 数据库路径
|
||||
* @param sql 增删改SQL
|
||||
@ -223,12 +223,12 @@ public class SQLiteUtil {
|
||||
return pstmt.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
closeDataSource(dbFilePath);
|
||||
throw new SQLException("执行增删改失败(SQL:" + sql + ")", e);
|
||||
throw new SQLException("执行增删改失败(SQL: " + sql + ")", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行计数查询(优化版:轻量结果处理)
|
||||
* 执行计数查询(优化版: 轻量结果处理)
|
||||
*
|
||||
* @param dbFilePath 数据库路径
|
||||
* @param sql 计数SQL(如SELECT COUNT(*) ...)
|
||||
@ -246,7 +246,7 @@ public class SQLiteUtil {
|
||||
return rs.next() ? rs.getInt(1) : 0;
|
||||
} catch (SQLException e) {
|
||||
closeDataSource(dbFilePath);
|
||||
throw new SQLException("执行计数查询失败(SQL:" + sql + ")", e);
|
||||
throw new SQLException("执行计数查询失败(SQL: " + sql + ")", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -270,12 +270,12 @@ public class SQLiteUtil {
|
||||
pstmt.execute();
|
||||
} catch (SQLException e) {
|
||||
closeDataSource(dbFilePath);
|
||||
throw new SQLException("执行DDL失败(SQL:" + sql + "、路径:" + dbFilePath + ")", e);
|
||||
throw new SQLException("执行DDL失败(SQL: " + sql + "、路径: " + dbFilePath + ")", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重载:无参数的DDL执行
|
||||
* 重载: 无参数的DDL执行
|
||||
*/
|
||||
public static void executeDDL(String dbFilePath, String sql) throws SQLException {
|
||||
executeDDL(dbFilePath, sql, null);
|
||||
@ -408,7 +408,7 @@ public class SQLiteUtil {
|
||||
field.set(obj, convertedValue);
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
System.err.println("警告:字段赋值失败(字段:" + field.getName() + "、值类型:" + value.getClass().getName() + "):" + e.getMessage());
|
||||
System.err.println("警告: 字段赋值失败(字段: " + field.getName() + "、值类型: " + value.getClass().getName() + "): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ -452,7 +452,7 @@ public class SQLiteUtil {
|
||||
}
|
||||
|
||||
// 不支持的类型转换(打印警告)
|
||||
System.err.println("警告:不支持的类型转换(目标类型:" + targetType.getName() + "、原始值类型:" + value.getClass().getName() + ")");
|
||||
System.err.println("警告: 不支持的类型转换(目标类型: " + targetType.getName() + "、原始值类型: " + value.getClass().getName() + ")");
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -461,7 +461,7 @@ public class SQLiteUtil {
|
||||
try {
|
||||
return Integer.parseInt(value.trim());
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("警告:字符串转Integer失败(值:" + value + ")");
|
||||
System.err.println("警告: 字符串转Integer失败(值: " + value + ")");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -470,7 +470,7 @@ public class SQLiteUtil {
|
||||
try {
|
||||
return Long.parseLong(value.trim());
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("警告:字符串转Long失败(值:" + value + ")");
|
||||
System.err.println("警告: 字符串转Long失败(值: " + value + ")");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -479,7 +479,7 @@ public class SQLiteUtil {
|
||||
try {
|
||||
return Double.parseDouble(value.trim());
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("警告:字符串转Double失败(值:" + value + ")");
|
||||
System.err.println("警告: 字符串转Double失败(值: " + value + ")");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -489,7 +489,7 @@ public class SQLiteUtil {
|
||||
try {
|
||||
return LocalDateTime.parse((String) value, LOCAL_DATE_TIME_FORMATTER);
|
||||
} catch (DateTimeParseException e) {
|
||||
System.err.println("警告:字符串转LocalDateTime失败(值:" + value + ")");
|
||||
System.err.println("警告: 字符串转LocalDateTime失败(值: " + value + ")");
|
||||
return null;
|
||||
}
|
||||
} else if (value instanceof Timestamp) {
|
||||
@ -513,7 +513,7 @@ public class SQLiteUtil {
|
||||
try {
|
||||
return blob.getBytes(1, (int) blob.length());
|
||||
} catch (SQLException e) {
|
||||
System.err.println("警告:Blob转byte[]失败:" + e.getMessage());
|
||||
System.err.println("警告: Blob转byte[]失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user