使用jdbc时,每操作一次都需要获取连接,用完后便将其释放、销毁。
选择利用连接池来优化curd操作。
连接池:管理数据库的连接,提高项目的性能。
作用:在连接池初始化的时候存入一定数量的连接,用的时候通过方法获取,不用的时候归还即可。
接口:所有的连接池必须实现 javax.sql.DataSource 接口。
c3p0使用步骤:
- 导入jar包
- 使用api
a. 硬编码(不推荐)
new ComboPooledDataSource();
b. 配置文件
配置文件名称:c3p0.properties 或者 c3p0-config.xml
配置文件的路径:src下
编码:
new ComboPooledDataSource(); //使用默认的配置
new ComboPooledDataSource(String configName); //使用命名的配置,若配置找不到则使用默认配置
工具类代码:
package com.cdf.utils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class DataSourceUtils {
private static ComboPooledDataSource ds = new ComboPooledDataSource();
private static ThreadLocal<Connection> tl=new ThreadLocal<>();
/**
* 从线程中获取连接
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
//从线程中获取conneciton
Connection conn = tl.get();
if(conn==null){
conn=ds.getConnection();
//和当前线程绑定
tl.set(conn);
}
return conn;
}
// 获取数据源
public static DataSource getDataSource() {
return ds;
}
// 释放资源
public static void closeResource( Statement st, ResultSet rs) {
closeResultSet(rs);
closeStatement(st);
}
// 释放资源
public static void closeResource(Connection conn, Statement st, ResultSet rs) {
closeResource(st, rs);
closeConn(conn);
}
// 释放 connection
public static void closeConn(Connection conn) {
if (conn != null) {
try {
conn.close();
//和线程解绑
tl.remove();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
// 释放 statement ctrl + shift + f 格式化代码
public static void closeStatement(Statement st) {
if (st != null) {
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
st = null;
}
}
// 释放结果集
public static void closeResultSet(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
}
//开启事务
public static void startTransaction() throws SQLException{
getConnection().setAutoCommit(false);
}
/**
* 事务提交且释放连接
*/
public static void commitAndClose(){
Connection conn = null;
try {
conn=getConnection();
//事务提交
conn.commit();
//关闭资源
conn.close();
//解除版定
tl.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 事务回滚且释放资源
*/
public static void rollbackAndClose(){
Connection conn = null;
try {
conn=getConnection();
//事务回滚
conn.rollback();
//关闭资源
conn.close();
//解除版定
tl.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
为什么要关闭Statement 和 ResultSet
线程从外界获取一个conn,然后创建自己地stmt,rs,然后执行逻辑操作,然后将conn返回给pool。 如果程序员忘记手动关地话。当这个线程执行完以后stmt,rs都成垃圾,当他们被垃圾搜集地时候,gc会替我们把它们给关闭地。这就是很多代码没有关闭,仍然正常运行。但是这样会有一个潜在地问题。就是gc无法确定什么时候运行。如果free地内存很多,很可能有些gc就不会被启动,这样stmt迟迟没有被关闭,执行一段时间会报错。所以健壮地代码应该手工把rs,stmt都关闭
关闭顺序最优:ResultSet -> Statement -> connection