数据库连接池
概念: 一个容器(集合),存放数据库连接的容器。当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,当用户访问完之后,会将连接对象归还给容器。
好处:
- 节约资源
- 用户访问高效
技术支持:
-
C3P0
:数据库连接池技术 -
Druid
:【很牛逼】数据库连接池实现技术,阿里巴巴提供
一、标准接口【javax.sql.DataSource】【具体实现由数据库厂商去完成】
javax.sql.DataSource接口中的方法:
-
Connection getConnection()
:获取连接 -
Connection.close()
:如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不再会关闭连接了。
二、C3P0数据库连接池技术
1.使用步骤
- 导包jar:
-
数据库驱动包
【前提】 c3p0-0.9.5.2.jar
mchange-commons-java-0.2.12.jar
-
- 定义配置文件
- 名称:
c3p0.properties
或者c3p0-config.xml
- 路径:src目录下
- 名称:
- 创建核心对象 数据库连接池对象
ComboPooledDataSource
- 获取连接:
getConnection()
,执行业务逻辑 - 归还连接:
Connection.close()
2.代码实现
// 对应的包
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
# ---------------------------------------- #
// 1.创建数据库连接池对象【使用默认配置,传入参数则使用对应的配置】
DataSource ds = new ComboPooledDataSource();
// 2.获取连接对象
Connection conn = ds.getConnection();
// 3.业务逻辑
String sql = "create table student(" +
"id int primary key auto_increment," +
"name varchar(10)," +
"age int," +
"gender char(3)," +
"birthday Date)";
PreparedStatement ps = conn.prepareStatement(sql);
ps.executeUpdate();
ps.close();
// 4. 归还连接对象
conn.close();
四、Druid数据库连接池技术,【阿里巴巴提供】
1.使用步骤
- 导入
druid-1.0.9.jar
包【也得导入数据库驱动包】 - 定义配置文件
- 可以是
properties
形式 - 可以叫任意名称,可以放在任意目录下
- 可以是
- 加载配置文件:推荐
properties
- 获取数据库连接池对象:通过工厂类来获取
DruidDataSourceFactory
- 获取连接:
getConnection
2. 代码实现
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
public class DruidLearn {
public static void main(String[] args) throws Exception {
// 1.加载配置文件
Properties pro = new Properties();
InputStream in = DruidLearn.class
.getClassLoader()
.getResourceAsStream("druid.properties");
pro.load(in);
// 2.获取连接池对象
DataSource ds = DruidDataSourceFactory.createDataSource(pro);
// 3.获取连接
Connection conn = ds.getConnection();
// 4.执行力业务逻辑
String sql1 = "create table user(id int primary key auto_increment,name varchar(10),password varchar(16))";
PreparedStatement ps = conn.prepareStatement(sql1);
int res = ps.executeUpdate();
String sql2 = "insert into user values(null,'晓庆','abc123'),(null,'小竹','123abc')";
ps = conn.prepareStatement(sql2);
int res2 = ps.executeUpdate();
String sql3 = "select * from user";
ps = conn.prepareStatement(sql3);
ResultSet rs = ps.executeQuery();
while (rs.next()) { int id = rs.getInt("id");String name = rs.getString("name");String password = rs.getString("password");System.out.println("编号:" + id + " 姓名:" + name + " 密码:" + password); }
// 5.释放资源
rs.close();
ps.close();
// 6.归还资源
conn.close();
}
}
五、封装一个Druid工具类JDBCUtils
- 提供静态代码块加载排至文件,初始化连接池对象
- 提供的方法:
- 获取连接池的方法
- 通过数据库连接池获取连接
- 释放资源
package JDBCUtils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JDBCUtils {
/**
* 1.定义成员变量 DateSource 连接池
*/
private static DataSource ds;
/**
* 2.加载配置文件
*/
static {
try{
Properties pro = new Properties();
pro.load(JDBCUtils.class.getClassLoader()
.getResourceAsStream("druid.properties"));
// 根据工厂类获取数据库连接池对象 SataSource
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); }
}
/**
* 获取连接池
*/
public static DataSource getDataSource() {
return ds;
}
/**
* 获取连接
*/
public static Connection getConnection() {
try { return ds.getConnection(); } catch (Exception e) { e.printStackTrace();return null; }
}
/**
* 释放资源
*/
public static void close(Statement stmt, Connection conn) {
if(stmt != null) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } }
if(conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } }
}
/**
* 释放资源; 重载
*/
public static void close(ResultSet rs, Statement stmt, Connection conn) {
if(rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } }
close(stmt, conn);
}
}
六、Spring JDBC
Spring 框架对JDBC的简单封装,提供了一个JdbcTemplate对象简化JDBC的开发
1.操作步骤【使用上方实现的JDBCUtils工具箱类】
- 导入jar包,例如:
-
commons-logging-1.2.jar
; -
spring-beans-5.0.0.RELEASE.jar
; -
spring-core-5.0.0.RELEASE.jar
; -
spring-jdbc-5.0.0.RELEASE.jar
; -
spring-tx-5.0.0.RELEASE.jar
;
-
- 创建JdbcTemplate对象。依赖于数据源 DataSource【从JDBCUtils获得】
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource())
- 调用JdbcTemplate的方法来完成CRUD的操作
2.JdbcTemplate类中的方法
-
int update(String sql, ...)
: 执行DML语句,增、删、改语句。 -
Map
: 查询结果将结果集封装成QueryForMap(String sql, ...) map
集合,将列名作为key
,将值作为value
,将这条记录封装为一个map
集合。- 注意:此方法查询的结果集长度只能是【1】,也就是只能是一条记录。
-
List
: 查询结果将结果集封装为list集合- 注意:将每一条记录封装为一个Map集合,再将Map集合装在到List集合中
- List> query(String sql, RowMapper> rm):查询结果,将结果封装为JavaBean对象。
- 参数:
RowMapper接口
:一般使用BeanPropertyRowMapper实现类
。当然可以重写内部的mapRow抽象方法.完成数据到JavaBean的自动封装
new BeanPropertyMapper
:【E必须是JavaBean规范类,内部的反射机制才好工作!】(E.class) - 参数:
-
E queryForObject(String sql, E.class)
: 查询结果,将结果封装为对象,一般为基本数据类型对象。- 注意: 一般用于聚合函数的查询
使用JdbcTemplate中的方法,得到JdbcTemplate对象后,直接进行SQL操作,不需要任何额外申请资源或者释放资源的操作!资源用完了就释放,结果集也是Map,List或者基本数据类型的包装类
3.案例展示
代码中使用JDBCUtils工具类是上面所描述的,Student类包含属性【int id,String name,int age,String gender】,JavaBean规范类,代码略!
package jdbcTemplate;
import JDBCUtils.JDBCUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
public class JDBCTemplate {
// 获取JDBCTemplate对象
private static JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
// 创建一张表格
public static void create() {
String sql = "create table student(" +
"id int primary key auto_increment," +
"name varchar(10)," +
"age int," +
"gender varchar(6))";
int count = template.update(sql);
System.out.println(count);
}
// 添加一些记录
public static void insert() {
String sql = "insert into student values " +
"(null,?,?,?)," +
"(null,?,?,?);";
int count = template.update(sql, "晓庆",18,"女","洪祥",20,"男");
System.out.println(count);
}
// 修改记录
public static void update() {
String sql = "update student set age = ? where name = ?";
int res = template.update(sql, 22, "小竹");
System.out.println(res);
}
// 删除一些记录
public static void delect() {
String sql = "delete from student where name in (?, ?)";
int res = template.update(sql,"晓庆", "洪祥");
System.out.println(res);
}
/**
* 查询操作
*/
// queryForMap - 查询的结果记录值允许一条!
public static void queryForMap() {
String sql = "select * from student where name=?";
Map map = template.queryForMap(sql, "晓庆");
System.out.println(map);
}
// 5.查询所有记录,将其封装为List
public static void queryForList() {
String sql = "select * from student";
List