当前位置:网站首页>jdbc-连接池
jdbc-连接池
2022-07-01 05:51:00 【胖丁微笑】
Java 中常用的连接池有 C3P0、DBCP、Druid 等。我们使用Druid,好处:
- 它的帮助文档是中文,便于查看
- 它是经过阿里大量数据的使用后的产品,一定会好用
1,添加依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
2,修改连接数据库工具类
@Slf4j
public final class JdbcUtil {
// 定义连接数据库的几个参数
private static final String DRIVER;
private static final String URL;
private static final String USERNAME;
private static final String PASSWORD;
private JdbcUtil() {
}
// 加载驱动类,这个加载操作只在项目中执行一次即可,无须返回加载
static {
try {
// 读取db.properties配置文件
InputStream is = JdbcUtil.class.getClassLoader().getResourceAsStream("db.properties");
Properties prop = new Properties();
prop.load(is);
DRIVER = prop.getProperty("jdbc.driver");
URL = prop.getProperty("jdbc.url");
USERNAME = prop.getProperty("jdbc.username");
PASSWORD = prop.getProperty("jdbc.password");
} catch (IOException e) {
log.info("加载配置文件出错,错误信息为:" + e.getMessage());
throw new RuntimeException("加载配置文件出错,错误信息为:" + e.getMessage());
}
}
/** * 获取连接对象 * @return 返回连接对象 */
public static DataSource getDataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(DRIVER);
ds.setUrl(URL);
ds.setUsername(USERNAME);
ds.setPassword(PASSWORD);
return ds;
}
public static Connection getConnection() {
try {
return getDataSource().getConnection();
} catch (SQLException e) {
throw new RuntimeException("创建连接对象时出错,错误信息为:" + e.getMessage());
}
}
/** * 封装的通用增删改方法 * @param sql 需要操作的SQL语句 * @param params 执行SQL语句时需要的参数 */
public static int update(String sql, Object... params) {
Connection conn = null;
PreparedStatement pstm = null;
try {
// 2. 创建连接对象
conn = getConnection();
// 3. 创建执行SQL语句对象
pstm = conn.prepareStatement(sql);
// 4. 设置参数
for (int i = 0; i < params.length; i++) {
pstm.setObject(i + 1, params[i]);
}
// 5. 执行SQL语句
return pstm.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
return 0;
} finally {
// 6. 释放资源
destroy(conn, pstm, null);
}
}
/** * 查询多条数据的封装方法 * @param clazz 结果的封装对象 * @param sql 要执行的SQL语句 * @param params 执行SQL语句时需要的参数 * @param <T> 消费金融泛型类型 * @return 返回查询的结果集 */
public static <T> List<T> query(Class<T> clazz, String sql, Object...params) {
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
List<T> entities = null;
try {
conn = getConnection();
pstm = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
pstm.setObject(i + 1, params[i]);
}
rs = pstm.executeQuery();
entities = new ArrayList<>();
// 获取 ResultSet 对象来获取元数据信息
ResultSetMetaData metaData = rs.getMetaData();
// 获取SQL语名中字段的个数
int columnCount = metaData.getColumnCount();
// 处理结果集
while (rs.next()) {
// 通过反射来实例化对象
//T entity = clazz.newInstance();
T entity = clazz.getDeclaredConstructor().newInstance();
for (int i = 1; i <= columnCount; i++) {
// getColumnName() 是获取表中的字段名称 SELECT id,name,age FROM xxx
//metaData.getColumnName();
// getColumnLabel() 是获取SQL中的字段名称 SELECT id,name as n,age FROM xxx
// 获取字段的名称
String columnLabel = metaData.getColumnLabel(i);
// 通过反射获取对象的字段
Field field = clazz.getDeclaredField(columnLabel);
// 给这个字段设置值
field.setAccessible(true);
field.set(entity, rs.getObject(columnLabel));
}
entities.add(entity);
}
return entities;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("查询多条数据时出错,错误信息为:" + e.getMessage());
} finally {
destroy(conn, pstm, rs);
}
}
/** * 查询多条数据的封装方法 * @param clazz 结果的封装对象 * @param sql 要执行的SQL语句 * @param params 执行SQL语句时需要的参数 * @param <T> 消费金融泛型类型 * @return 返回查询的结果 */
public static <T> T queryForObject(Class<T> clazz, String sql, Object...params) {
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
T entity = null;
try {
conn = getConnection();
pstm = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
pstm.setObject(i + 1, params[i]);
}
rs = pstm.executeQuery();
ResultSetMetaData metaData = rs.getMetaData();
while (rs.next()) {
if (clazz == Integer.class) {
Constructor<T> constructor = clazz.getDeclaredConstructor(int.class);
entity = constructor.newInstance(rs.getInt(1));
} else if (clazz == Long.class) {
Constructor<T> constructor = clazz.getDeclaredConstructor(long.class);
entity = constructor.newInstance(rs.getLong(1));
} else {
throw new RuntimeException("参数中能传 int 类型或 long 类型。");
}
}
return entity;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("统计查询时出错,错误信息为:" + e.getMessage());
} finally {
destroy(conn, pstm, rs);
}
}
/** * 通用的释放资源的方法 * @param conn 连接对象 * @param pstm 执行语句对象 * @param rs 结果集对象 */
public static void destroy(Connection conn, PreparedStatement pstm, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
log.info("释放 ResultSet 对象时出错,错误信息为:" + e.getMessage());
}
}
if (pstm != null) {
try {
pstm.close();
} catch (SQLException e) {
log.info("释放 PreparedStatement 对象时出错,错误信息为:" + e.getMessage());
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
log.info("释放 Connection 对象时出错,错误信息为:" + e.getMessage());
}
}
}
}
在这个类中,我们增加了 getDataSource() 方法用于创建连接池对象。然后在 geConection() 方法中从连接池中获取连接对象。而静态代码块中的 加载驱动器类的代码就不再需要,因为这部分的功能已经放到的连接池对象中了。
3,ThreadLocal
JDK1.2 的版本中已经提供了 ThreadLocal对象了,它是为了解决多线程程序并发问题而产生。
这个类提供了以下几个静态方法:
- get() :用于获取ThreadLocal 中当前线程共享变量的值。
- set():设置ThreadLocal中当前线程共享的变量的值。
- remove():移除 ThreadLocal中当前线程共享的变量的值。
- initialValue:ThreadLocal没有被当前线程赋值时调用当前线程的remove方法后再调用 get 方法时就会返回这个值。
修改 JdbcUtil 这个工具类,让它支持 ThreadLocal
@Slf4j
public final class JdbcUtil {
// 数据源连接池对象
private static DataSource dataSource;
// ThreadLocal 对象
private static ThreadLocal<Connection> threadLocal;
private JdbcUtil() {
}
// 加载驱动类,这个加载操作只在项目中执行一次即可,无须返回加载
static {
try {
// 读取db.properties配置文件
InputStream is = JdbcUtil.class.getClassLoader().getResourceAsStream("db.properties");
Properties prop = new Properties();
prop.load(is);
// 使用Druid连接池工厂方式
dataSource = DruidDataSourceFactory.createDataSource(prop);
threadLocal = new ThreadLocal<>();
} catch (Exception e) {
log.info("加载配置文件出错,错误信息为:" + e.getMessage());
throw new RuntimeException("加载配置文件出错,错误信息为:" + e.getMessage());
}
}
/** * 获取连接对象 * @return 返回连接对象 */
public static Connection getConnection() {
// 从当前线程中获取连接
Connection conn = threadLocal.get();
if (conn == null) {
try {
// 如果没有就从连接池中去获取
conn = dataSource.getConnection();
// 放到ThreadLocal中
threadLocal.set(conn);
} catch (SQLException e) {
throw new RuntimeException("创建连接对象时出错,错误信息为:" + e.getMessage());
}
}
return conn;
}
/** * 封装的通用增删改方法 * @param sql 需要操作的SQL语句 * @param params 执行SQL语句时需要的参数 */
public static int update(String sql, Object... params) {
Connection conn = null;
PreparedStatement pstm = null;
try {
// 2. 创建连接对象
conn = getConnection();
// 3. 创建执行SQL语句对象
pstm = conn.prepareStatement(sql);
// 4. 设置参数
for (int i = 0; i < params.length; i++) {
pstm.setObject(i + 1, params[i]);
}
// 5. 执行SQL语句
return pstm.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
return 0;
} finally {
// 6. 释放资源
destroy(conn, pstm, null);
}
}
/** * 查询多条数据的封装方法 * @param clazz 结果的封装对象 * @param sql 要执行的SQL语句 * @param params 执行SQL语句时需要的参数 * @param <T> 消费金融泛型类型 * @return 返回查询的结果集 */
public static <T> List<T> query(Class<T> clazz, String sql, Object...params) {
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
List<T> entities = null;
try {
conn = getConnection();
pstm = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
pstm.setObject(i + 1, params[i]);
}
rs = pstm.executeQuery();
entities = new ArrayList<>();
// 获取 ResultSet 对象来获取元数据信息
ResultSetMetaData metaData = rs.getMetaData();
// 获取SQL语名中字段的个数
int columnCount = metaData.getColumnCount();
// 处理结果集
while (rs.next()) {
// 通过反射来实例化对象
//T entity = clazz.newInstance();
T entity = clazz.getDeclaredConstructor().newInstance();
for (int i = 1; i <= columnCount; i++) {
// getColumnName() 是获取表中的字段名称 SELECT id,name,age FROM xxx
//metaData.getColumnName();
// getColumnLabel() 是获取SQL中的字段名称 SELECT id,name as n,age FROM xxx
// 获取字段的名称
String columnLabel = metaData.getColumnLabel(i);
// 通过反射获取对象的字段
Field field = clazz.getDeclaredField(columnLabel);
// 给这个字段设置值
field.setAccessible(true);
field.set(entity, rs.getObject(columnLabel));
}
entities.add(entity);
}
return entities;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("查询多条数据时出错,错误信息为:" + e.getMessage());
} finally {
destroy(conn, pstm, rs);
}
}
/** * 查询多条数据的封装方法 * @param clazz 结果的封装对象 * @param sql 要执行的SQL语句 * @param params 执行SQL语句时需要的参数 * @param <T> 消费金融泛型类型 * @return 返回查询的结果 */
public static <T> T queryForObject(Class<T> clazz, String sql, Object...params) {
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
T entity = null;
try {
conn = getConnection();
pstm = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
pstm.setObject(i + 1, params[i]);
}
rs = pstm.executeQuery();
ResultSetMetaData metaData = rs.getMetaData();
while (rs.next()) {
if (clazz == Integer.class) {
Constructor<T> constructor = clazz.getDeclaredConstructor(int.class);
entity = constructor.newInstance(rs.getInt(1));
} else if (clazz == Long.class) {
Constructor<T> constructor = clazz.getDeclaredConstructor(long.class);
entity = constructor.newInstance(rs.getLong(1));
} else {
throw new RuntimeException("参数中能传 int 类型或 long 类型。");
}
}
return entity;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("统计查询时出错,错误信息为:" + e.getMessage());
} finally {
destroy(conn, pstm, rs);
}
}
/** * 通用的释放资源的方法 * @param conn 连接对象 * @param pstm 执行语句对象 * @param rs 结果集对象 */
public static void destroy(Connection conn, PreparedStatement pstm, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
log.info("释放 ResultSet 对象时出错,错误信息为:" + e.getMessage());
}
}
if (pstm != null) {
try {
pstm.close();
} catch (SQLException e) {
log.info("释放 PreparedStatement 对象时出错,错误信息为:" + e.getMessage());
}
}
if (conn != null) {
try {
conn.close();
// 从 ThreadLocal中删除当前连接对象
threadLocal.remove();
} catch (SQLException e) {
log.info("释放 Connection 对象时出错,错误信息为:" + e.getMessage());
}
}
}
}
边栏推荐
- 【笔记】电商订单数据分析实战
- Call us special providers of personal cloud services for College Students
- el-table 动态表头渲染 固定第一列 高度问题
- TiDB单机模拟部署生产环境集群(闭坑实践,亲测有效)
- How to add a gourd pie plate
- OneFlow源码解析:算子签名的自动推断
- Vscode function annotation / file header annotation shortcut
- Crossing pie · pie pan + Mountain duck = local data management
- Essay learning record essay multi label Global
- HCM 初学 ( 一 ) - 简介
猜你喜欢
![[note] e-commerce order data analysis practice](/img/03/367756437be947b5b995d5f7f55236.png)
[note] e-commerce order data analysis practice

Brief description of activation function

Call us special providers of personal cloud services for College Students

论文学习记录随笔 多标签之LIFT

excel动态图表

LeetCode 最大矩形,最大正方形系列 84. 85. 221. 1277. 1725. (单调栈,动态规划)

论文学习记录随笔 多标签之GLOCAL

FPGA - 7系列 FPGA内部结构之Clocking -02- 时钟布线资源

skywalking集成nacos动态配置

【医学分割】u2net
随机推荐
2022.6.30-----leetcode. one thousand one hundred and seventy-five
2022 the 8th China International "Internet +" college student innovation and entrepreneurship competition industry proposition track is open for registration!
College community management system based on boot+jsp (with source code download link)
win10、win11中Elan触摸板滚动方向反转、启动“双指点击打开右键菜单“、“双指滚动“
CJC8988带2个立体声耳机驱动器的低功率立体声编解码器
Ucosiii --- engineering transplantation
【医学分割】u2net
excel动态图表
tese_ Time_ 2h
MySQL数据迁移遇到的一些错误
Send you through the data cloud
TIDB数据库特性总结
Basic electrician knowledge 100 questions
扩展点系列之SmartInstantiationAwareBeanPostProcessor确定执行哪一个构造方法 - 第432篇
机械臂速成小指南(六):步进电机驱动器
[medical segmentation] u2net
芯片,建立在沙粒上的帝国!
Excel dynamic chart
Beauty of Mathematics - Application of Mathematics
OpenGL es: (4) detailed explanation of EGL API (Continued)