數(shù)據(jù)庫連接池
概念: 一個容器(集合),存放數(shù)據(jù)庫連接的容器。當(dāng)系統(tǒng)初始化好后,容器被創(chuàng)建,容器中會申請一些連接對象,當(dāng)用戶來訪問數(shù)據(jù)庫時,從容器中獲取連接對象,當(dāng)用戶訪問完之后,會將連接對象歸還給容器。
好處:
- 節(jié)約資源
- 用戶訪問高效
技術(shù)支持:
-
C3P0:數(shù)據(jù)庫連接池技術(shù) -
Druid:【很牛逼】數(shù)據(jù)庫連接池實(shí)現(xiàn)技術(shù),阿里巴巴提供
一、標(biāo)準(zhǔn)接口【javax.sql.DataSource】【具體實(shí)現(xiàn)由數(shù)據(jù)庫廠商去完成】
javax.sql.DataSource接口中的方法:
-
Connection getConnection():獲取連接 -
Connection.close():如果連接對象Connection是從連接池中獲取的,那么調(diào)用Connection.close()方法,則不再會關(guān)閉連接了。
二、C3P0數(shù)據(jù)庫連接池技術(shù)
1.使用步驟
- 導(dǎo)包jar:
-
數(shù)據(jù)庫驅(qū)動包【前提】 c3p0-0.9.5.2.jarmchange-commons-java-0.2.12.jar
-
- 定義配置文件
- 名稱:
c3p0.properties或者c3p0-config.xml - 路徑:src目錄下
- 名稱:
- 創(chuàng)建核心對象 數(shù)據(jù)庫連接池對象
ComboPooledDataSource - 獲取連接:
getConnection(),執(zhí)行業(yè)務(wù)邏輯 - 歸還連接:
Connection.close()
2.代碼實(shí)現(xiàn)
// 對應(yīng)的包
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
# ---------------------------------------- #
// 1.創(chuàng)建數(shù)據(jù)庫連接池對象【使用默認(rèn)配置,傳入?yún)?shù)則使用對應(yīng)的配置】
DataSource ds = new ComboPooledDataSource();
// 2.獲取連接對象
Connection conn = ds.getConnection();
// 3.業(yè)務(wù)邏輯
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數(shù)據(jù)庫連接池技術(shù),【阿里巴巴提供】
1.使用步驟
- 導(dǎo)入
druid-1.0.9.jar包【也得導(dǎo)入數(shù)據(jù)庫驅(qū)動包】 - 定義配置文件
- 可以是
properties形式 - 可以叫任意名稱,可以放在任意目錄下
- 可以是
- 加載配置文件:推薦
properties - 獲取數(shù)據(jù)庫連接池對象:通過工廠類來獲取
DruidDataSourceFactory
- 獲取連接:
getConnection
2. 代碼實(shí)現(xiàn)
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.執(zhí)行力業(yè)務(wù)邏輯
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
- 提供靜態(tài)代碼塊加載排至文件,初始化連接池對象
- 提供的方法:
- 獲取連接池的方法
- 通過數(shù)據(jù)庫連接池獲取連接
- 釋放資源
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"));
// 根據(jù)工廠類獲取數(shù)據(jù)庫連接池對象 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的開發(fā)
1.操作步驟【使用上方實(shí)現(xiàn)的JDBCUtils工具箱類】
- 導(dǎo)入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;
-
- 創(chuàng)建JdbcTemplate對象。依賴于數(shù)據(jù)源 DataSource【從JDBCUtils獲得】
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource())
- 調(diào)用JdbcTemplate的方法來完成CRUD的操作
2.JdbcTemplate類中的方法
-
int update(String sql, ...): 執(zhí)行DML語句,增、刪、改語句。 -
Map<String,Object> QueryForMap(String sql, ...): 查詢結(jié)果將結(jié)果集封裝成map集合,將列名作為key,將值作為value,將這條記錄封裝為一個map集合。- 注意:此方法查詢的結(jié)果集長度只能是【1】,也就是只能是一條記錄。
-
List<Map<String,Object>> queryForList(String sql, ...): 查詢結(jié)果將結(jié)果集封裝為list集合- 注意:將每一條記錄封裝為一個Map集合,再將Map集合裝在到List集合中
-
List<?> query(String sql, RowMapper<?> rm):查詢結(jié)果,將結(jié)果封裝為JavaBean對象。
-
參數(shù):
RowMapper接口:一般使用BeanPropertyRowMapper實(shí)現(xiàn)類。當(dāng)然可以重寫內(nèi)部的mapRow抽象方法.完成數(shù)據(jù)到JavaBean的自動封裝
new BeanPropertyMapper<E>(E.class):【E必須是JavaBean規(guī)范類,內(nèi)部的反射機(jī)制才好工作!】 -
參數(shù):
-
E queryForObject(String sql, E.class): 查詢結(jié)果,將結(jié)果封裝為對象,一般為基本數(shù)據(jù)類型對象。- 注意: 一般用于聚合函數(shù)的查詢
使用JdbcTemplate中的方法,得到JdbcTemplate對象后,直接進(jìn)行SQL操作,不需要任何額外申請資源或者釋放資源的操作!資源用完了就釋放,結(jié)果集也是Map,List或者基本數(shù)據(jù)類型的包裝類
3.案例展示
代碼中使用JDBCUtils工具類是上面所描述的,Student類包含屬性【int id,String name,int age,String gender】,JavaBean規(guī)范類,代碼略!
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());
// 創(chuàng)建一張表格
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 - 查詢的結(jié)果記錄值允許一條!
public static void queryForMap() {
String sql = "select * from student where name=?";
Map<String, Object> map = template.queryForMap(sql, "曉慶");
System.out.println(map);
}
// 5.查詢所有記錄,將其封裝為List
public static void queryForList() {
String sql = "select * from student";
List<Map<String, Object>> list = template.queryForList(sql);
for (Map<String, Object> map : list) {
System.out.println(map);
}
}
// 6.查詢所有記錄,將其封裝為Student對象的List集合【接口方法重寫】
public static void queryOne() {
String sql = "select * from student";
List<Student> list = template.query(sql,new RowMapper<Student>() {
/**
* mapRow的返回值是一個對象而不是List集合,
* 說明參數(shù)ResultSet是遍歷查詢的每個結(jié)果
* */
@Override
public Student mapRow(ResultSet rs, int i) throws SQLException {
Student student = new Student();
student.setId(rs.getInt("id"));
student.setName(rs.getString("name"));
student.setAge(rs.getInt("age"));
student.setGender(rs.getString("gender"));
return student;
}
});
for (Student student : list) {
System.out.println(student);
}
}
// 7.查詢所有記錄,將其封裝為Student對象的List集合
public static void queryTwo() {
String sql = "select * from student;";
List<Student> list = template.query(sql, new BeanPropertyRowMapper<>(Student.class));
for (Student student : list) {
System.out.println(student);
}
}
// 8.查詢總記錄數(shù)
public static void queryAgg() {
String sql = "select count(*) number from student";
Long total = template.queryForObject(sql,Long.class);
System.out.println(total);
}
public static void main(String[] args) {
// create();
// insert();
// update();
// delect();
/*查詢操作!*/
// queryForMap();
// queryForList();
// queryOne();
// queryTwo();
// queryAgg();
}
}