基础类 User 如下
@Data
private class User {
private long id;
private String username;
private String password;
private Boolean enabled;
}
一、JDBC直接访问关系库的代码样例如下
/**
* 创建单个连接查询数据库
*/
public void queryUserByJdbc(String url, String username, String password) {
if(null == url) {
url = "jdbc:postgresql://localhost:18921/performdb?currentSchema=smy&useSSL=false&useUnicode=true&characterEncoding=UTF-8";
username = "postgres";
password = "******";
}
List<User> users = new ArrayList<> ();
// 使用try-with-resources自动关闭连接/语句/结果集,避免资源泄漏
try (Connection conn = DriverManager.getConnection(url, username, password);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM user")) {
while (rs.next()) {
User user = new User();
user.setId(rs.getLong("id"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
user.setEnabled(rs.getBoolean("enabled"));
users.add(user);
}
} catch (SQLException se) {
se.printStackTrace();
} catch (Exception e) {
// e.printStackTrace();
}
System.out.println(users);
}
二、Hikari数据源访问关系库
2.1、Hikari数据源的配置属性如下
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import com.zaxxer.hikari.pool.ProxyConnection;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class DataSourceUtils {
private static DataSource dataSource;
/**
* Hikari获取连接
*/
public static Connection getConnection(/*DataSource dataSource*/) throws SQLException {
if (dataSource == null) {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://localhost:18921/performdb?currentSchema=smy&useSSL=false&useUnicode=true&characterEncoding=UTF-8");
config.setUsername("postgres");
config.setPassword("******");
config.setPoolName("Hikari-performdb"); // 连接池名称(日志与JMX监控标识)
config.setDataSourceJNDI("java:com/ctsi/jdbc/DataSourceUtils"); // 数据源的JNDI位置
/// 连接数量控制
config.setMaximumPoolSize(20); // 连接池最大连接数量(含活跃与空闲连接), 生产环境建议20 - 50
config.setMinimumIdle(5); // 连接池最小空闲连接数量,其数量既要避免资源浪费,又要减少新建连接的开销
/// 连接质量控制
config.setMaxLifetime(30 * 60 * 1000); // 连接最大存活时间(毫秒), 超时将被标记为过期并关闭
config.setIdleTimeout(10 * 60 * 1000); // 空闲连接存活时间(毫秒),需 < maxLifetime
config.setConnectionTestQuery("SELECT 1"); // 测试连接有效性的SQL查询(仅限不支持JDBC4的驱动)
/// 连接租借控制
config.setConnectionTimeout(30 * 1000); // 获取连接的最大等待时间(毫秒),超时抛出SQLTimeoutException
config.setLeakDetectionThreshold(60 * 1000); // 60秒未归还连接则自动回收
dataSource = new HikariDataSource(config);
}
return dataSource.getConnection();
}
/**
* Hikari归还连接
*/
public static void closeConnection(ProxyConnection conn/*, DataSource dataSource*/) throws SQLException {
conn.close();
}
}
关于maxLifetime属性需要特别说明:
- 【物理含义】 连接最大存活时间(毫秒), 超时将被标记为过期并关闭,该值有助于避免数据库端因长时间不活动而断开连接导致的无效连接问题 !!!该属性的推荐数值是小于数据库端的超时阈值2-3分钟,如:wait_timeout(MySQL)、idle_in_transaction_session_timeout(PostgreSQL)。
- 【不良后果】 该值未配置或值过大,导致数据库主动断开连接后,连接池仍持有无效连接,出现Connection is not available或Communications link failure或No operations allowed after connection closed错误; 该值过小,导致频繁重建连接增加数据库端负载;
- 【回收时机】 连接在以下场景会被检测并回收:1、归还到连接池时检测到过期; 2、后台维护线程定期扫描空闲线程发现过期;过期连接会被物理关闭,不再复用。
2.2、连接池的使用
/**
* 从连接池获取连接查询数据库
*/
public void queryUserByDataSource() {
Connection conn = null;
List<User> users = new ArrayList<> ();
try {
conn = DataSourceUtils.getConnection() ;
try(Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM smy.user")) {
while (rs.next()) {
User user = new User();
user.setId(rs.getLong("id"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password")) ;
user.setEnabled(rs.getBoolean("enabled")) ;
users.add(user) ;
}
}
} catch(Exception e) {
e.printStackTrace();
} finally {
try{
DataSourceUtils.closeConnection((ProxyConnection) conn);
}catch(SQLException se) {
se.printStackTrace();
}
}
System.out.println(users);
}
1906

被折叠的 条评论
为什么被折叠?



