Java學習路線-44:JDBC數據庫開發進階

第1 章 : 事務處理

課時1 事務的四大特性(ACID)

原子性 Atomicity 操作不可再分割,要麼成功,要麼失敗
一致性 Consistency 數據狀態與業務規則保持一致
隔離性 Isolation 併發事務不會相互干擾
持久性 Durability 數據操作必須被持久化到數據庫中

課時2:MySQL中開啓和關閉事務

默認情況下,MySQL沒執行一條SQL語句,都是單獨的事務
如果要在一個事務中包含多條SQL語句,那麼需要開啓事務和結束事務

-- 開啓事務
start transaction

-- 結束事務
commit 
-- 或者
rollback

課時3 JDBC中完成事務處理

// 開啓事務,設置不自動提交, 默認true
conn.setAutoCommit(false);

// 提交事務
conn.commit()

// 回滾事務
conn.rollback()

代碼格式

try{
    conn.setAutoCommit(false);
    ...
    conn.commit()
}catch(){
    conn.rollback()
}

轉賬示例

import util.JdbcUtils;

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

/**
 * create table account(
 *  id int primary key auto_increment,
 *  username varchar(50),
 *  balance int
 * )
 *
 * insert into account(username, balance) values ('張三', 1000), ('王五', 1000)
 */
class Demo {
    public static void transferMoney(int fromId, int toId, int money) throws SQLException {
        Connection conn = JdbcUtils.getConnection();
        conn.setAutoCommit(false);
        try {
            updateBalance(conn, fromId, -money);
            
            if(true){
                throw new RuntimeException("斷網了");
            }

            updateBalance(conn, toId, money);
            conn.commit();
        } catch (Exception e) {
            conn.rollback();
            throw new RuntimeException(e);
        } finally {
            conn.close();
        }

    }

    public static void updateBalance(Connection conn, int id, int money) throws SQLException {
        String sql = "update account set balance = balance + ? where id = ?";
        PreparedStatement statement = conn.prepareStatement(sql);
        statement.setInt(1, money);
        statement.setInt(2, id);
        statement.executeUpdate();
    }

    public static void main(String[] args) throws SQLException {
        transferMoney(1, 2, 100);
    }
}

課時4 事務的隔離級別

事務併發問題
髒讀:讀取到另一個事務未提交數據
不可重複讀:兩次讀取不一致
幻讀:讀到另一個事務已提交數據

四大隔離級別
串行化 不會出現併發,性能最差(堅決不用)
可重複度 防止髒讀和不可重複讀,不能處理幻讀(MySQL默認)
讀已提交 防止髒讀
讀未提交 性能最好

-- 查看隔離級別
select @@tx_isolation

-- 設置隔離級別
set transaction isolationlevel [1, 2, 3, 4]

第2 章 : 連接池

課時5 dbcp連接池

1、池參數
初始大小:10個
最小空閒連接數:3個
增量:一次創建最小單位5個
最大空閒連接數:12個
最大連接數:20個
最大等待時間:1000毫秒

2、四大連接參數
連接池也是使用4個連接參數來完成創建連接對象

3、連接池必須實現接口:
javax.sql.DataSource

連接池的close() 方法不是關閉,而是歸還

依賴

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
    <version>2.7.0</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.8.0</version>
</dependency>
import org.apache.commons.dbcp2.BasicDataSource;

import java.sql.Connection;
import java.sql.SQLException;

class Demo {

    public static void main(String[] args) throws SQLException {
        // 配置4個必要參數
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/data");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");

        // 配置連接池參數
        dataSource.setMaxWaitMillis(1000);

        // 獲取連接對象
        Connection conn = dataSource.getConnection();
        System.out.println(conn.getClass().getName());

        // 歸還連接
        conn.close();
    }
}

課時6 裝飾者模式

對象增強的手段
(1)繼承
(2)裝飾者模式
(3)動態代理

1、繼承:
會使得類增多
增強的內容是固定的
被增強的對象也是固定的

2、裝飾者模式
增強的對象是不能修改的
被增強的對象可以是任意的

InputStream
FileInputStream 節點流
BufferedInputStream 裝飾流

is a
has a
use a

// MyConnection is Connection
class MyConnection implements Connection{
    // MyConnection has Connection
    private Connection conn; // 底層對象,被增強的對象

    // 通過構造器傳遞底層對象
    public MyConnection(Connection conn){
        this.conn = conn;
    }

    public Statement createStatement(){
        return this.conn.createStatement();
    }

    // 增強點
    public void close(){

    }
}

3、動態代理
被增強的對象可以切換
增強的內容也可以切換

課時7 c3p0連接池的基本使用方式

依賴

<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.5</version>
</dependency>
import com.mchange.v2.c3p0.ComboPooledDataSource;

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

class Demo {

    public static void main(String[] args) throws PropertyVetoException, SQLException {
        // 配置4個必要參數
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/data");
        dataSource.setUser("root");
        dataSource.setPassword("123456");

        // 配置連接池參數
        dataSource.setAcquireIncrement(5);
        dataSource.setInitialPoolSize(3);
        dataSource.setMinPoolSize(3);
        dataSource.setMaxPoolSize(20);

        // 獲取連接對象
        Connection conn = dataSource.getConnection();
        System.out.println(conn.getClass().getName());

        // 歸還連接
        conn.close();
    }
}

課時8 c3p0連接的配置文件使用

必須命名爲:c3p0-config.xml
必須放在src目錄下

<?xml version="1.0" encoding="utf-8"?>
<c3p0-config>
    <!-- 這是默認配置信息 -->
    <default-config>
        <!-- 連接四大參數配置 -->
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/data</property>
        <property name="user">root</property>
        <property name="password">123456</property>

        <!-- 池參數配置 -->
        <property name="acquireIncrement">3</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">2</property>
        <property name="maxPoolSize">10</property>
    </default-config>
</c3p0-config>

連接會報錯:java.sql.SQLException: No suitable driver

import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.sql.Connection;
import java.sql.SQLException;

class Demo {

    public static void main(String[] args) throws SQLException {
        
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
 
        // 獲取連接對象
        Connection conn = dataSource.getConnection();
        System.out.println(conn.getClass().getName());

        // 歸還連接
        conn.close();
    }
}

第3 章 : JDBC工具類

課時9-10 JdbcUtils小工具

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public class JdbcUtil {
    // 需要配置c3p0-config.xml
    private static ComboPooledDataSource dataSource = new  ComboPooledDataSource();

    // 返回連接對象
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    // 返回連接池對象
    public static DataSource getDataSource(){
        return dataSource;
    }

}

課時11 JNDI配置

JNDI(Java Naming and Directory Interface, Java命名和目錄接口)

課時12 ThreadLocal

解決多線程併發問題的工具類,它爲每個線程提供了一個本地的副本變量機制,
實現了和其它線程隔離,並且這種變量只在本線程的生命週期內起作用,
可以減少同一個線程內多個方法之間的公共變量傳遞的複雜度

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

class Demo {

    public static void main(String[] args) throws SQLException {
        ThreadLocal<String> tl = new ThreadLocal<String>();
        // 添加
        tl.set("Tom");

        // 獲取
        String name = tl.get();
        System.out.println(name);

        // 移除
        tl.remove();

    }
}

ThreadLocal的核心代碼

class TL<T>{
    private Map<Thread, T> map = new HashMap<Thread, T>();

    public void set(T value){
        this.map.put(Thread.currentThread(), value);
    }

    public T get(){
        return this.map.get(Thread.currentThread());
    }

    public void remove(){
        this.map.remove(Thread.currentThread());
    }
}

課時13 dbutils原理

依賴

<dependency>
    <groupId>commons-dbutils</groupId>
    <artifactId>commons-dbutils</artifactId>
    <version>1.7</version>
</dependency>

示例

Student.class

public class Student {
    private int sid;
    private String sname;

    public int getSid() {
        return sid;
    }

    public void setSid(int sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public Student() {

    }

    @Override
    public String toString() {
        return "Student{" +
                "sid=" + sid +
                ", sname='" + sname + '\'' +
                '}';
    }
}

Demo.class
1、查詢操作

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import java.sql.SQLException;


class Demo {

    public static void main(String[] args) throws SQLException {
        // 提供數據庫連接池
        QueryRunner qr = new QueryRunner(JdbcUtil.getDataSource());

        // 查詢操作
        // sql模板
        String sql = "select * from student where sid = ?";

        // 參數
        Object[] params = {3};

        // 提供結果集處理器
        Student student = qr.query(sql, new BeanHandler<Student>(Student.class), params);
        System.out.println(student);
        // Student{sid=3, sname='楊不悔'}

    }
}

2、更新操作

String sql = "update student set sname=? where sid = ?";
Object[] params = {"楊不悔", 3};
qr.update(sql, params);

課時14 dbUtils結果集處理器介紹

common-dbutils.jar
QueryRunner

// update執行增,刪,改
int update(String sql, Object... params)
int update(Connection conn, String sql, Object... params)

// query執行查詢
T query(String sql, ResultSetHandler rsh, Object... params)
T query(Connection conn, String sql, ResultSetHandler rsh, Object... params)

ResultSetHandler接口
BeanHandler(單行) 一行轉換成指定類型的javaBean對象
BeanListHandler(多行) 多行轉爲list對象
MapHandler(單行) 一行結果轉爲Map對象
MapListHandler(多行) 多行結果轉爲Map對象列表
ScalarHandler 單行單列 通常用於select count(*) from table

1、BeanListHandler

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.sql.SQLException;
import java.util.List;


class Demo {

    public static void main(String[] args) throws SQLException {
        // 提供數據庫連接池
        QueryRunner qr = new QueryRunner(JdbcUtil.getDataSource());

        String sql = "select * from student";

        List<Student> students = qr.query(sql, new BeanListHandler<Student>(Student.class));
        System.out.println(students);
        
    }
}

2、MapListHandler

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.MapListHandler;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;


class Demo {

    public static void main(String[] args) throws SQLException {

        QueryRunner qr = new QueryRunner(JdbcUtil.getDataSource());

        String sql = "select * from student";
        
        List<Map<String, Object>> students = qr.query(sql, new MapListHandler());
        System.out.println(students);


    }
}

3、ScalarHandler

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.SQLException;


class Demo {

    public static void main(String[] args) throws SQLException {

        QueryRunner qr = new QueryRunner(JdbcUtil.getDataSource());

        String sql = "select count(*) from student";

        Number cnt = (Number)qr.query(sql, new ScalarHandler());
        long count = cnt.longValue();
        System.out.println(count);

    }
}

課時15 編寫TxQueryRunner配合JdbcUtils來處理事務

class TxQueryRunner extends QueryRunner{
    // 重寫部分方法
}

課時16 JdbcUtils處理多線程併發訪問問題

使用 ThreadLocal

第4 章 : 分頁

課時17 分頁準備工作

分頁優點:只查詢一頁,不用查詢所有頁

class pageBean<T>{
    // 當前頁碼
    private int currentPage;

    // 總頁數
    private int totalPage;

    // 總記錄數
    private int totalRecord;

    // 頁面大小
    private int pageSize;

    // 頁面數據
    private List<T> beanList;

}

課時18:處理分頁各層分工

第n頁/共N頁 首頁 上一頁 1 2 3 4 5 6 下一頁 尾頁

課時19 分頁處理第一階段完成

課時20 分頁之頁面頁碼列表計算

計算公式
pageSize = 10
begin = currentPage - 5
end = currentPage + 4
如果總頁數<=10, 那麼bedin=1, end=總頁數
頭溢出:當begin<1, 那麼begin=1
尾溢出:當end>總頁數, 那麼end>總頁數

課時21 分頁之查詢條件丟失問題

超鏈接中要保留參數

課時22 分頁之查詢條件保存到PageBean的url中

發佈了1418 篇原創文章 · 獲贊 370 · 訪問量 130萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章