數(shù)據(jù)庫(kù)連接池
概念: 一個(gè)容器(集合),存放數(shù)據(jù)庫(kù)連接的容器口柳。當(dāng)系統(tǒng)初始化好后苹粟,容器被創(chuàng)建,容器中會(huì)申請(qǐng)一些連接對(duì)象跃闹,當(dāng)用戶來訪問數(shù)據(jù)庫(kù)時(shí)嵌削,從容器中獲取連接對(duì)象毛好,當(dāng)用戶訪問完之后,會(huì)將連接對(duì)象歸還給容器苛秕。
好處:
- 節(jié)約資源
- 用戶訪問高效
技術(shù)支持:
-
C3P0
:數(shù)據(jù)庫(kù)連接池技術(shù) -
Druid
:【很牛逼】數(shù)據(jù)庫(kù)連接池實(shí)現(xiàn)技術(shù)肌访,阿里巴巴提供
一、標(biāo)準(zhǔn)接口【javax.sql.DataSource】【具體實(shí)現(xiàn)由數(shù)據(jù)庫(kù)廠商去完成】
javax.sql.DataSource接口中的方法:
-
Connection getConnection()
:獲取連接 -
Connection.close()
:如果連接對(duì)象Connection是從連接池中獲取的艇劫,那么調(diào)用Connection.close()方法吼驶,則不再會(huì)關(guān)閉連接了。
二店煞、C3P0數(shù)據(jù)庫(kù)連接池技術(shù)
1.使用步驟
- 導(dǎo)包jar:
-
數(shù)據(jù)庫(kù)驅(qū)動(dòng)包
【前提】 c3p0-0.9.5.2.jar
mchange-commons-java-0.2.12.jar
-
- 定義配置文件
- 名稱:
c3p0.properties
或者c3p0-config.xml
- 路徑:src目錄下
- 名稱:
- 創(chuàng)建核心對(duì)象 數(shù)據(jù)庫(kù)連接池對(duì)象
ComboPooledDataSource
- 獲取連接:
getConnection()
,執(zhí)行業(yè)務(wù)邏輯 - 歸還連接:
Connection.close()
2.代碼實(shí)現(xiàn)
// 對(duì)應(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ù)庫(kù)連接池對(duì)象【使用默認(rèn)配置蟹演,傳入?yún)?shù)則使用對(duì)應(yīng)的配置】
DataSource ds = new ComboPooledDataSource();
// 2.獲取連接對(duì)象
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. 歸還連接對(duì)象
conn.close();
四、Druid數(shù)據(jù)庫(kù)連接池技術(shù)顷蟀,【阿里巴巴提供】
1.使用步驟
- 導(dǎo)入
druid-1.0.9.jar
包【也得導(dǎo)入數(shù)據(jù)庫(kù)驅(qū)動(dòng)包】 - 定義配置文件
- 可以是
properties
形式 - 可以叫任意名稱酒请,可以放在任意目錄下
- 可以是
- 加載配置文件:推薦
properties
- 獲取數(shù)據(jù)庫(kù)連接池對(duì)象:通過工廠類來獲取
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.獲取連接池對(duì)象
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("編號(hào):" + id + " 姓名:" + name + " 密碼:" + password); }
// 5.釋放資源
rs.close();
ps.close();
// 6.歸還資源
conn.close();
}
}
五、封裝一個(gè)Druid工具類JDBCUtils
- 提供靜態(tài)代碼塊加載排至文件衩椒,初始化連接池對(duì)象
- 提供的方法:
- 獲取連接池的方法
- 通過數(shù)據(jù)庫(kù)連接池獲取連接
- 釋放資源
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ù)庫(kù)連接池對(duì)象 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 框架對(duì)JDBC的簡(jiǎn)單封裝毛萌,提供了一個(gè)JdbcTemplate對(duì)象簡(jiǎn)化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對(duì)象。依賴于數(shù)據(jù)源 DataSource【從JDBCUtils獲得】
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource())
- 調(diào)用JdbcTemplate的方法來完成CRUD的操作
2.JdbcTemplate類中的方法
-
int update(String sql, ...)
: 執(zhí)行DML語(yǔ)句阁将,增膏秫、刪、改語(yǔ)句做盅。 -
Map<String,Object> QueryForMap(String sql, ...)
: 查詢結(jié)果將結(jié)果集封裝成map
集合缤削,將列名作為key
,將值作為value
,將這條記錄封裝為一個(gè)map
集合。- 注意:此方法查詢的結(jié)果集長(zhǎng)度只能是【1】吹榴,也就是只能是一條記錄亭敢。
-
List<Map<String,Object>> queryForList(String sql, ...)
: 查詢結(jié)果將結(jié)果集封裝為list集合- 注意:將每一條記錄封裝為一個(gè)Map集合,再將Map集合裝在到List集合中
-
List<?> query(String sql, RowMapper<?> rm):查詢結(jié)果图筹,將結(jié)果封裝為JavaBean對(duì)象帅刀。
-
參數(shù):
RowMapper接口
:一般使用BeanPropertyRowMapper實(shí)現(xiàn)類
。當(dāng)然可以重寫內(nèi)部的mapRow抽象方法.完成數(shù)據(jù)到JavaBean的自動(dòng)封裝
new BeanPropertyMapper<E>(E.class)
:【E必須是JavaBean規(guī)范類远剩,內(nèi)部的反射機(jī)制才好工作扣溺!】 -
參數(shù):
-
E queryForObject(String sql, E.class)
: 查詢結(jié)果,將結(jié)果封裝為對(duì)象,一般為基本數(shù)據(jù)類型對(duì)象瓜晤。- 注意: 一般用于聚合函數(shù)的查詢
使用JdbcTemplate中的方法锥余,得到JdbcTemplate對(duì)象后,直接進(jìn)行SQL操作痢掠,不需要任何額外申請(qǐng)資源或者釋放資源的操作驱犹!資源用完了就釋放嘲恍,結(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對(duì)象
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.查詢所有記錄荠医,將其封裝為L(zhǎng)ist
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對(duì)象的List集合【接口方法重寫】
public static void queryOne() {
String sql = "select * from student";
List<Student> list = template.query(sql,new RowMapper<Student>() {
/**
* mapRow的返回值是一個(gè)對(duì)象而不是List集合,
* 說明參數(shù)ResultSet是遍歷查詢的每個(gè)結(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對(duì)象的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();
}
}