JavaEEDay37 C3P0連接池

JavaEEDay37C3P0連接池

四、連接池

不再使用 JDBC 連接數據庫,採用連接池的方式

  • 問題:發現在程序中,不斷的有連接數據庫的操作,但是也同時存在,每一次連接之後操作結束,立馬就會關閉 ,因爲涉及到數據庫的打開,關閉,這裏非常影響軟件的運行效率。
  • 解決方案:把數據庫連接對象,放到一個池子裏
  • 連接池功能如下:
    1.初始化連接的個數,最大連接數,當前連接數,池子用集合來表示 ,一般使用LinkedList ;因爲增刪多,基本上沒有查找
    2.構造方法:創建初始化連接
    3.創建連接的方法
    4.獲取連接的方法:
    —> 判斷:池子中有沒有可用的連接
    –> 有,直接拿走
    –> 沒有 判斷是否達到了最大連接數,
    –>到達則拋出異常
    –>沒有達到,創建新的連接
    5.釋放連接: 是將正在使用的數據庫連接對象,放回池子內
package connectionpool;

import metadata.JdbcUtil;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.LinkedList;

/**
 * @author GJXAIOU
 * @create 2019-08-02-20:37
 */
public class ConnectionPoolPractice {
    /*
    初始化連接數目,這裏默認爲3
     */
    private int initCount = 3;
    /*
    連接池最大連接數目,這裏定義爲6
     */
    private final int maxCount = 6;
    /*
     記錄當前的連接數目
     */
    private int currentCount = 0;

    // 新建連接池,使用linkedlist操作
    private  LinkedList<Connection> connectionPool = new LinkedList<Connection>();

    // 1.構造方法,按照指定初始化連接個數並且創建新的連接
    public ConnectionPoolPractice(){
        for (int i = 0; i < initCount; i++) {
            // 類內創建連接的方式
            Connection connection = createConnection();
            connectionPool.addLast(connection);
            currentCount++;
        }
    }

    public int getCurrentCount(){
        return currentCount;
    }

    // 2.創建一個新的連接
    private Connection createConnection(){
        // 2.1加載驅動
       final Connection connection = JdbcUtil.getConnection();

        Connection proxy = (Connection)Proxy.newProxyInstance(connection.getClass().getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 定義一個返回值
                Object result = null;
                // 獲取要執行方法的方法名
                String methodName = method.getName();
                // 這裏只是限制了close的操作,其他的方法按照原來的操作進行
                // 修改關閉close執行的任務
                if ("close".equals(methodName)) {
                    System.out.println("執行close方法");
                    // 放回連接池內
                    connectionPool.addLast(connection);
                    System.out.println("數據庫連接已經放回到連接池中");
                }else{
                    result = method.invoke(connection, args);
                }
                return result;
            }
        });
        return proxy;

    }

    // 3.從連接池中獲取連接的方法
    public Connection getConnection(){
        // 3.1判斷池子中有沒有連接
        if (connectionPool.size() > 0){
            return connectionPool.removeFirst();
        }

        // 3.2如果沒有連接,判斷當前連接數是否達到最大值限制
        if (currentCount < maxCount){
            currentCount++;
            return createConnection();
        }
        throw new RuntimeException("當前連接數已經達到最大值");
    }

    // 4.釋放連接
    public void realeaseConnection(Connection connection){
        // 4.1如果池子中讀取的數目小於初始化連接,放入池子
        if(connectionPool.size() < initCount){
            connectionPool.addLast(connection);
        }else {
            currentCount--;
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        ConnectionPoolPractice connectionPoolPractice = new ConnectionPoolPractice();
        System.out.println("當前連接數目爲:" + connectionPoolPractice.getCurrentCount());

        Connection connection = connectionPoolPractice.getConnection();
        Connection connection1 = connectionPoolPractice.getConnection();
        Connection connection2 = connectionPoolPractice.getConnection();
        System.out.println(connection);
        System.out.println(connection1);
        System.out.println(connection2);

        try {
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        Connection connection3 = connectionPoolPractice.getConnection();
        System.out.println(connection3);

    }

}


使用 C3P0 連接池

一共兩種連接方式:
方式一:硬編碼方式
方式二:使用 XML 文件

  • 方式一:使用硬編碼方式的代碼
package connectionpool;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * @author GJXAIOU
 * @create 2019-08-02-21:42
 */
public class C3P0ConnectionPool {
    /**
     * 使用硬連接的方式
     * @throws PropertyVetoException
     * @throws SQLException
     */
    public void HardcodeStyleTest() throws PropertyVetoException, SQLException {
        // 1.創建連接池的核心工具類
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();

        // 2.設置連接數據庫所需的參數
        comboPooledDataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
        comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/day34jdbc?serverTimezone = GMT%2B8 ");
        comboPooledDataSource.setUser("root");
        comboPooledDataSource.setPassword("GJXAIOU");

        // 3.設置C3P0連接池的屬性:初始化連接數、最大連接數、等待時間
        comboPooledDataSource.setInitialPoolSize(3);
        comboPooledDataSource.setMaxPoolSize(6);
        comboPooledDataSource.setMaxIdleTime(1000);

        // 4.從連接池中獲取數據庫連接對象
        Connection connection = comboPooledDataSource.getConnection();

        // 5.準備preparedStatement執行SQL語句
        connection.prepareStatement("delete from person where id = 3").executeUpdate();
    }
}


  • 方式二:使用 XML 文件的形式
package connectionpool;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * @author GJXAIOU
 * @create 2019-08-02-21:42
 */
public class C3P0ConnectionPool {
    /**
     * 通過配置XML文件,創建C3P0連接池
     * @throws SQLException
     */
    public void XmlStyleTest() throws SQLException {
        // 1.創建C3P0核心類,會自動的加載s目錄下的c3p0-config.xml文件
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();

        // 2.創建連接
        Connection connection = comboPooledDataSource.getConnection();

        // 3.準備preparedStatement以及SQL語句
        PreparedStatement preparedStatement = null;
        String sql = "insert into person(name, gender, score, home, hobby) value(?, ?, ?, ?, ?)";

        for (int i = 0; i < 10; i++) {
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,"錢十");
            preparedStatement.setString(2,"男");
            preparedStatement.setInt(3, 98);
            preparedStatement.setString(4, "江蘇");
            preparedStatement.setString(5, "游泳");
            preparedStatement.executeUpdate();
        }
        preparedStatement.close();
        connection.close();
    }
}



針對第二種方式,一般使用 XML 配置文件,也可以使用.properties 文件,這裏使用 xml 文件,將其放置在上面代碼同一包下即可;命名爲:c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <default-config>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/day34jdbc?serverTimezone = GMT%2B8 </property>
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="user">root</property>
        <property name="password">GJXAIOU</property>
        <property name="initialPoolSize">3</property>
        <property name="maxPoolSize">6</property>
        <property name="maxIdleTime">1000</property>
    </default-config>
</c3p0-config>

– MySQL增強
create database day38;
use day38;

一、 數據約束

(一) 默認值

create table student(
	id int, 
	name varchar(20),
	country varchar(20) default '中國' -- 默認值
);

– 沒有設置默認值的字段,在沒有賦值的情況下都是NULL
insert into student(id, name) values(1, “孬蛋”);
insert into student(id, name, country) values(2, “金豆”, “China”);
insert into student(id) values(3);

(二)非空

create table student(
	id int, 
	name varchar(20),
	gender varchar(2) not null -- 非空
);
  • 如果存在非空字段,必須賦值,下面會報錯;
    insert into student(id, name) values(1, "孬蛋");
    ERROR 1364 (HY000): Field ‘gender’ doesn’t have a default value

  • 必須給非空字段賦值,下面語句正確;
    insert into student(id, name, gender) values(1, "狗蛋", "男");

  • 非空字段用在什麼地方?
    用戶名,密碼,郵箱,手機

(三)唯一

create table student(
	id int UNIQUE, -- 唯一
	name varchar(20)
);

insert into student(id, name) values(1, “孬蛋”);
insert into student(id, name) values(1, “狗剩”);
ERROR 1062(23000):Duplicate entry '1' for key 'id'
– 唯一值不能重複

(四)主鍵 (非空+唯一)

create table student(
	id int primary key,
	name varchar(20)
);

insert into student(id, name) values(1, “狗蛋”);
insert into student(id, name) values(2, “狗剩”);
insert into student(name) values(‘辣雞’);
– ERROR 1364 (HY000): Field ‘id’ doesn’t have a default value
– ID值不能爲空,必須有數據

insert into student(id, name) values(1, “炸雞”);
– ERROR 1062 (23000): Duplicate entry ‘1’ for key ‘PRIMARY’
– ID值是唯一索引,不能爲空,並且不能重複

(五)自增長

CREATE TABLE student(
	-- 自增長 ZEROFILL 零填充,從0開始
	id INT ZEROFILL PRIMARY KEY AUTO_INCREMENT, 
	name VARCHAR(20)
);

insert into student(name) values("張三");
insert into student(name) values("李四");
insert into student(name) values("王五");
insert into student(name) values("馬六");

(六)外鍵約束

下面表的設計中:每一個人都是JavaEE教學部,這裏每一個數據行中,都有JavaEE教學部,導致了數據的冗餘,是否可以把部門做成一張表

create table employee(
	id int primary key, -- 員工ID
	empName varchar(20), -- 員工名
	deptName varchar(20) -- 部門名
);

insert into employee values(1, "老劉", "JavaEE教學部");
insert into employee values(2, "我黨", "JavaEE教學部");
insert into employee values(3, "大飛", "JavaEE教學部");
insert into employee values(4, "瑞哥", "JavaEE教學部");
insert into employee values(5, "賦賦", "JavaEE教學部");

– 設計一個獨立的部門表

create table dept(
	id int primary key,
	deptName varchar(20)
);

– 設計一個新的員工表,帶有部門ID

create table employee(
	id int primary key,
	empName varchar(20),
	deptID int, -- 用部門的ID來表示當前員工的部門是哪一個
	-- 建立一個外鍵約束
	CONSTRAINT emp_dept_fk foreign key(deptID) references dept(id) on update cascade on delete cascade -- 級聯修改
	--emp_dept_fk :外鍵名稱     deptID:外鍵   dept(id):連接的參考字段
);

insert into dept(id, deptName) values(1, "JavaEE教學部");
insert into dept(id, deptName) values(2, "PHP教學部");
insert into dept(id, deptName) values(3, "iOS教學部");


insert into employee values(1, "張三", 1);
insert into employee values(2, "李四", 2);
insert into employee values(3, "王五", 3);
insert into employee values(4, "趙六", 1);

insert into employee values(5, "喜峯", 4);
– 存在問題,因爲在部門中並沒有部門ID爲4的部門,這裏數據無法添加
– ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (day38.employee, CONSTRAINT emp_dept_fk FOREIGN KEY (deptID) REFERE
NCES dept (id) ON DELETE CASCADE ON UPDATE CASCADE)

– 級聯修改因爲後面的這句話: on update cascade on delete cascade

  • 如果修改部門,這裏會隨之修改主表裏面的數據
    update dept set id=4 where id=3;

  • 刪除部門表 同時會幫助我們刪除員工信息
    delete from dept where id=2;

  • 修改員工表信息
    update employee set deptID=2 where id=4;

  • 如果沒有級聯修改

      1. 當存在外鍵約束,添加數據的順序:先添加主表,在添加副表
      1. 當存在外鍵約束,修改數據的順序:先修改副表,在修改主表
      1. 當存在外鍵約束,刪除數據的順序:先刪除副表,在刪除主表

二、關聯查詢

交叉查詢

select empName,deptName from employee, dept;
這個結果是有問題的 笛卡爾乘積 存在重複數據,不推薦使用

– 需求:查詢員工及其所在部門,顯示員工姓名和部門名稱
將上面的表格進行重新新建;

多表查詢

  • 規則:
      1. 確定查詢那些表格 2. 確定要查詢的字段 3. 表和表之間的關係

內連接查詢。

只有滿足條件的結果纔會展示(使用最多的多表查詢)
select empName,deptName from employee, dept where employee.deptID = dept.id;
select empName,deptName – 要查詢的字段
from employee, dept – 要查詢的表格
where employee.deptID = dept.id; – 表和表之間的關係

  • inner join 內連接的另一種語法
    select empName, deptName from employee inner join dept on employee.deptID = dept.id;
    select empName, deptName
    from employee – 主表
    inner join dept – 連接的是哪一張表
    on employee.deptID = dept.id; – 表示條件

  • 或者 使用別名
    select e.empName, d.deptName from employee e inner join dept d on e.deptID = d.id;

左右外連接

  • 需求,查看每一個部門的員工
    – 預期結果
    – JavaEE 張三
    – JavaEE 趙六
    – iOS 王五
    – PHP 李四

  • 左[外]連接查詢:使用左邊表中的數據來匹配右邊表的數據,如果符合條件,展示數據
    – 如果沒有符合條件的連接數據,顯示null
    select d.deptName, e.empName from dept d left outer join employee e on d.id = e.deptID;

– 右[外]連接查詢:使用右邊表中的數據來匹配左邊表的數據,如果符合條件,展示數據
– 如果沒有符合條件的連接數據,顯示null
select d.deptName, e.empName from employee e right outer join dept d on d.id = e.deptID;

自連接查詢

– 修改員工表結構,添加上司

alter table employee add bossId int;

update employee set bossId=1 where id=2;
update employee set bossId=2 where id=3;
update employee set bossId=3 where id=4;

– 預期結果
– 張三 null
– 李四 張三
– 王五 李四
– 趙六 王五
select e.empName, b.empName from employee e left outer join employee b on e.bossId = b.id;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章