第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 分頁之查詢條件丟失問題
超鏈接中要保留參數