Web筆記-MySQL

MySQL遠程登錄
修改數據表:將Host的localhost值改為%,%代表所有主機均允許
->mysql use mysql;
->mysql update user set Host = '%' where User = 'root';
授權:允許所有主機以root用戶密碼登錄
->mysql grant all privileges on *.* to 'root'@'%' identified by '密碼' with grant option;
刷新授權
->mysql flush privileges;
MySQL MAC5.7.17及以上版本中文顯示亂碼問題
使用命令查看編碼信息
show variables like "char%"
編碼信息

若編碼信息如圖据块,則無需設置益缎。若database及server等編碼不為utf8則按如下方式配置:

  1. 前往/usr/local/mysql/support-files/目錄下
  2. 執(zhí)行copy命令:gaopengfeideMacBook-Pro:~ gaopengfei$ cp my-default.cnf /etc/ 將my-default.cnf拷貝到/etc目錄下
  3. 修改etc下my-default.cnf為my.cnf并在my.cnf文件末尾添加如下代碼:
[client]
default-character-set=utf8
[mysqld]
default-storage-engine=INNODB
character-set-server=utf8
collation-server=utf8_general_ci

完整my.cnf內容:

# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html
# *** DO NOT EDIT THIS FILE. It's a template which will be copied to the
# *** default location during install, and will be replaced if you
# *** upgrade to a newer version of MySQL.
[mysqld]
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
# These are commonly set, remove the # and set as required.
# basedir = .....
# datadir = .....
# port = .....
# server_id = .....
# socket = .....
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M 
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
[client]
default-character-set=utf8
[mysqld]
default-storage-engine=INNODB
character-set-server=utf8
collation-server=utf8_general_ci

數據類型
數據類型
字符串型 VARCHAR CHAR
大數據類型 BLOB TEXT
數值型 TINYINT SMALLINT INT BIGINT FLOAT DOUBLE
邏輯型 BIT
日期型 DATE TIME DATETIME TIMESTAMP
數據庫語言
  • DDL語言:數據定義語言
  • DML語言:數據操作語言(插入付秕、更新象踊、刪除)
  • DCL語言:數據控制語言
  • DQL語言:數據查詢語言
聚集函數
  • COUNT:總數
  • SUM:求和
  • AVG:平均值
  • MAX/MIN:最大/最小值

分組查詢:
關鍵字:group by
添加條件:使用having關鍵字 后可使用聚集函數励负,而where條件不能使用聚集函數

排序:
關鍵字:order by
排序方式:后加關鍵字ASC(升序) DESC(倒序)

Select語句小結:
S-F-W-G-H-O:SELECT...FROM...WHERE...GROUP BY...HAVING...ORDER BY...
having和where均可實現過濾藕溅,但在having后可以使用聚集函數,where后則不能使用继榆。having通常跟在group by后蜈垮,它作用于分組


多表操作

多表設計:外鍵約束
作用:保證數據的完整性
語法:alter table 表名 add foreign key 表名(外鍵) references 關聯表名(主鍵);

表與表之間的關系(數據庫設計):

一對多:一個員工只能屬于一個部門,一個部門下可以有多個員工
【注】:建表原則裕照,都是看多方表(在多方表添加字段攒发,作為外鍵指向一方表的主鍵)

多對多:一門課程可以由多個學生選擇,一個學生也可以選擇多門課程
【注】:建表原則晋南,建立一張第三方表惠猿,該表中至少有倆個字段,這個倆個字段负间,作為外鍵偶妖,分別指向倆個表的主鍵

一對一:一個公司只有一個具體地址,而一個地址只能對應一個公司(用的最少)
【注】:建表原則政溃,可以將其寫入一張表趾访,但如果因公司業(yè)務需要,要拆分成兩張表董虱,那么就會有兩種建表方式扼鞋。
a)主鍵對應:公司信息表的主鍵和公司地址表主鍵值必須一致
b)唯一外鍵對應:給公司表添加一個單獨字段作為外鍵指向公司信息表,但必須給公司表的外鍵添加唯一約束(unique)保證它的值是唯一的

栗子??
多表查詢

笛卡爾積(乘積):select * from A,B;

內連接(查詢出的一定是最準確的數據):
a)普通內連接:
關鍵字:inner join...on
select * from A inner join B on A.aname = B.bname;
b)隱式內連接:
關鍵字:去除inner join...on
select * from A a,B b where a.name = b.name;

+-----+--------+-----+-------+------+---------+------+
| did | dname  | eid | ename | esex | esalary | did  |
+-----+--------+-----+-------+------+---------+------+
|   1 |  行政部 |   4 |  萌萌  |    1 |   5000  |   1  |
|   2 |  財務部 |   5 |  敏敏  |    1 |   8000  |   2  |
|   3 |  技術部 |   1 |  飛飛  |    0 |  15000  |   3  |
|   3 |  技術部 |   2 |  亮亮  |    0 |  18000  |   3  |
|   3 |  技術部 |   3 |  丁丁  |    0 |  12000  |   3  |
+-----+--------+-----+-------+------+---------+------+

外連接(會將多余無用數據查詢出來愤诱,若數據不全):
a)左外連接:(看左表云头,把左表的數據全部查詢出來):
關鍵字:left [outer] join...on 條件
select * from A left outer join B on A.aname = B.bname;

 +-----+--------+------+-------+------+---------+-----+
| did | dname  | eid  | ename | esex | esalary | did  |
+-----+--------+------+-------+------+---------+------+
|   1 |  行政部 |    4 |  萌萌   |  1  |   5000  |   1  |
|   2 |  財務部 |    5 |  敏敏   |  1  |   8000  |   2  |
|   3 |  技術部 |    1 |  飛飛   |  0  |   15000 |   3  |
|   3 |  技術部 |    2 |  亮亮   |  0  |   18000 |   3  |
|   3 |  技術部 |    3 |  丁丁   |  0  |   12000 |   3  |
|   4 |  NULL  | NULL |  NULL  | NULL |   NULL |  NULL|
|   5 |  NULL  | NULL |  NULL  | NULL |   NULL |  NULL|
+-----+--------+------+-------+------+---------+------+

b)右外連接:(看右表,把右表的數據全部查詢出來):
關鍵字:right [outer] join...on 條件
select * from A right outer join B on A.aname = B.bname;

+------+-------+-------+-------+------+---------+------+
| did  | dname  | eid  | ename | esex | esalary | did  |
+------+-------+-------+-------+------+---------+------+
|   3  | 技術部 |   1   |  飛飛  |  0   |   15000 |    3 |
|   3  | 技術部 |   2   |  亮亮  |  0   |   18000 |    3 |
|   3  | 技術部 |   3   |  丁丁  |  0   |   12000 |    3 |
|   1  | 行政部 |   4   |  萌萌  |  1   |    5000 |    1 |
|   2  | 財務部 |   5   |  敏敏  |  1   |    8000 |    2 |
| NULL | NULL  |   6   |  妞妞  |  1   |    4000 | NULL |
| NULL | NULL  |   7   |  彤彤  |  1   |    4000 | NULL |
+------+--------+-----+-------+------+---------+-------+ 
子查詢

SQL語句中淫半,select...from...語句為一個查詢塊溃槐,將一個查詢塊兒嵌套在另一個查詢塊兒中作為條件稱為嵌套查詢,也稱作子查詢科吭。
外層的查詢塊兒稱為父查詢昏滴,內層查詢稱塊稱作子查詢
語法:select * from table where 條件 > (select 字段 from table where 條件);
子查詢運算符:

  • <小于
  • &gt大于
  • <=小于等于
  • &gt=大于等于
  • =等于
  • <>或
  • !=不等于
  • in范圍any或all
    >any:大于子查詢中的最小值
    >all:大于子查詢中的最大值
    語法:select * from table where 條件 >any (select 字段 from table where 條件);

JDBC
  1. JDBC(Java DataBase Connectivity)Java數據庫連接猴鲫,它是由SUN公司為了簡化Java對數據庫操作而定義的一套規(guī)范
  2. 用法
//注冊驅動
Class.forName("com.mysql.jdbc.Driver");
//獲取連接對象
Connection conn = DriverManager.getConnection(url, username, password);
//執(zhí)行Statement對象
Statement stmt = conn.createStatement(sql);
//執(zhí)行SQL語句
ResultSet rs = stmt.executeQuery(sql);
//解析獲取到的數據
...
//關閉資源
rs.close();
stmt.close();
conn.close(); 
  1. DriverManager詳解
  • 注冊驅動
    registerDriver(Driver driver)
    而這種方式注冊驅動有倆個弊端:不方便切換數據庫;這樣會注冊倆次驅動
    正確寫法:Class.forName("com.mysql.jdbc.Driver");通過反射注冊驅動
  • 獲取連接對象
getConnection(String url, String user, String password)
url:數據庫連接地址
jdbc:mysql://localhost:3306/test
jdbc:數據庫連接的協議
mysql:數據庫連接的協議的子協議
localhost:數據庫服務器地址
3306:MySQL服務器默認端口
test:數據庫名稱
user:數據庫用戶名
password:數據庫密碼
如果是MySQL數據庫谣殊,連接的是自己本地的數據庫拂共,簡寫條件:jdbc:mysql:///數據庫名
  1. Connection詳解:
  • 創(chuàng)建執(zhí)行SQL語句的對象
Statement createStatement()//執(zhí)行SQL語句的對象
PreparedStatement prepareStatement(String sql)//執(zhí)行SQL語句對象,支持SQL預編譯(防止SQL注入漏洞)
CallableStatement prepareCall(String slq)//執(zhí)行數據庫存儲過程
  • 管理事物
void setAutoCommit(boolean autoConmmit)//設置是否自動提交事物
void commit()//提交事物
void rollback()//回滾

事物:是一組邏輯的操作蟹倾,要么全都成功匣缘,要么全部失敗,事物支持回滾

  1. Statement詳解:
  • 執(zhí)行SQL語句
ResultSet executeQuery(String sql)//執(zhí)行查詢語句的時候使用該方法
int executeUpdate(String sql)//執(zhí)行insert update delete語句時調用該方法鲜棠,返回int為受影響行數
boolean execute(String sql)//執(zhí)行select insert update delete語句調用該方法肌厨,如果返回Result,則返回true豁陆,返回影響行數或者無結果則返回false
  • 執(zhí)行批處理
void addBatch(String sql)//添加批處理
int[] executeBatch()//執(zhí)行批處理
void clearBatch()//清除批處理
  1. ResultSet詳解:
    表示數據庫結果集的數據表柑爸,通常通過執(zhí)行查詢數據庫的語句生成。它也可以標識數據庫中的游標盒音,默認指定到第一行數據的上一行(表頭)
    ResultSet它維護了一個指向表格行的游標cursor表鳍,可以使用它進行數據的獲取
  • API
boolean next()//將游標向下移動一行,判斷是否有下一條數據
boolean absolute(int row)//將光標移動到此 ResultSet 對象的給定行編號
void afterLast()//將光標移動到此 ResultSet 對象的末尾祥诽,正好位于最后一行之后
boolean previous()//將光標移動到此 ResultSet 對象的上一行譬圣。 
void beforeFirst()//將光標移動到此 ResultSet 對象的開頭,正好位于第一行之前雄坪。 
void updateRow()//用此 ResultSet 對象的當前行的新內容更新底層數據庫厘熟。 
  • 設置滾動結果集:
Statement stmt = con.createStatement(int resultSetType, int resultSetConcurrency);
resultSetType:結果集的類型
resultSetConcurrency:結果集并發(fā)策略
  • 結果集類型:
ResultSet.TYPE_FORWARD_ONLY:只能向下
ResultSet.TYPE_SCROLL_INSENSITIVE:可以滾動,但不能修改數據
ResultSet.TYPE_SCROLL_SENSITIVE:可以滾動维哈,也可以修改數據
  • 結果集并發(fā)策略取值
ResultSet.CONCUR_READ_ONLY:只讀(不能修改)                      
ResultSet.CONCUR_UPDATABLE:可讀可寫
  • 組合到一起绳姨,不能滾動策略:
ResultSet.TYPE_FORWARD_ONLY            ResultSet.CONCUR_READ_ONLY:只能向下,不能修改(默認結果集)
 ResultSet.TYPE_SCROLL_INSENSITIVE    ResultSet.CONCUR_READ_ONLY:可以滾動阔挠,數據不能修改
ResultSet.TYPE_SCROLL_SENSITIVE        ResultSet.CONCUR_UPDATABLE:可以滾動飘庄,也可以修改數據
  • 示例代碼
//加載驅動
Class.forName("com.mysql.jdbc.Driver");
//獲取連接
Connection conn = DriverManager.getConnection("jdbc:mysql:///test", "root", "root");
//獲取可以執(zhí)行SQL語句的對象
Statement stmt = conn.createStatement(Result.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
//編寫SQL語句
String sql = "SELECT * FROM user";
//設置可以滾動的結果集,修改數據
ResultSet rs = stmt.executeQuery(sql);
//定位到第3行
rs.absolute(3);
//修改數據
rs.updateString("username", "小飛");
//執(zhí)行
rs.updateRow();
//釋放資源
rs.close();
stmt.close();
conn.close();
  1. 釋放資源
    使用JDBC時购撼,執(zhí)行完畢后跪削,一定要釋放資源(ResultSet、Statement份招、Connection對象)切揭。
    特別是Connection對象,它是非常稀有的資源锁摔,用完必須釋放,如果不及時正確關閉哼审,極容易導致系統(tǒng)宕機谐腰。
    Connection對象的使用原則:盡量晚創(chuàng)建孕豹,盡量早釋放
    為確保資源釋放代碼可以運行,資源釋放代碼一定寫在finally語句中
  2. JavaEE-DAO(DataAccessObject)模式
    DAO模式:處理持久層十气,封裝數據源和單個操作励背。對外提供一組接口,供業(yè)務層訪問砸西。業(yè)務層調用持久層傳遞一個對象參數叶眉。
  • 數據源可能是文件、數據庫等任意存儲方式
  • 負責管理與數據源的連接
  • 負責數據的存惹奂稀(CRUD)

DAO模式創(chuàng)建:提供接口-->提供實現類

JavaEE體系:

  • 客戶端:HTML衅疙、CSS、JS
  • WEB層:Servlet JSP
  • 業(yè)務層:EJB
  • 持久層: JDBC

JavaEE經典三層結構:

  • WEB層:Servlet-接收請求 JSP-顯示結果 Struts SpringMVC
  • 業(yè)務層:JavaBean-封裝和處理數據 Spring
  • 持久層:JDBC-操作數據庫 Hibernate MyBatis
    早期采用:Servlet + JSP + JavaBean + JDBC框架鸳慈,偏于底層
    現在采用:SSH(Struts + Spring + Hibernate)框架
  1. 數據庫事務

事務 指邏輯上的一組操作饱溢,組成這組操作的各個單元,要不全部成功走芋,要不全部失敗

數據庫開啟事務命令:

  • start transaction 開啟事務
  • rollback 回滾事務
  • commit 提交事務

關閉MySQL事務自動提交(MySQL數據庫事物是默認提交的):

  1. 查詢是否默認提交:show variables like ‘%commit%’;
查詢數據庫是否默認提交事物
  1. 設置不默認提交:set autocommit=off或者0;如果設置autocommit為off绩郎,意味著以后每條SQL 都會處于一個事務中,相當于每條SQL執(zhí)行前 都執(zhí)行 start transaction
關閉mysql默認事物提交

注:Oracle中 autocommit 默認就是 off

代碼執(zhí)行事務:
當JDBC程序向數據庫獲得一個Connection對象時翁逞,默認情況下這個Connection對象會自動向數據庫提交SQL語句
若想關閉這種默認提交方式肋杖,讓多條SQL在一個事務中執(zhí)行,可使用下列語句:

void setAutoCommit(boolean autoCommit) //將此連接的自動提交模式設置為給定狀態(tài)挖函。 
void commit() //使所有上一次提交/回滾后進行的更改成為持久更改状植,并釋放此 Connection 對象當前持有的所有數據庫鎖    
void rollback() //取消在當前事務中進行的所有更改,并釋放此 Connection 對象當前持有的所有數據庫鎖   

設置事務回滾點:

Savepoint setSavepoint() //在當前事務中創(chuàng)建一個未命名的保存點 (savepoint)挪圾,并返回表示它的新 Savepoint 對象浅萧。 
void rollback(Savepoint savepoint) //取消所有設置給定 Savepoint 對象之后進行的更改。 
void commit() //使所有上一次提交/回滾后進行的更改成為持久更改哲思,并釋放此 Connection 對象當前持有的所有數據庫鎖洼畅。

事務的丟失更新問題(lost update)
倆個或多個事務同時更新同一行,但這些事務彼此之間都不知道其它事務進行修改棚赔,因此第二個更改會覆蓋第一個修改

  • 第一類丟失更新:A事務回滾時帝簇,把已提交的B事務數據覆蓋
  • 第二類丟失更新:A事務提交時,把已提交的B事務
    1. 解決方案一:悲觀鎖-假如丟失更新的問題一直存在靠益,使用數據庫鎖機制(排他鎖)
    2. 解決方案二:樂觀鎖-假如丟失更新的問題不一定存在丧肴,提供在表中添加一個字段

四大特性(ACID):

  1. 原子性(Atomicity):原子性是指事物是一個不可分割的工作單位,事務中的操作要么都發(fā)生胧后,要么都不發(fā)生
  2. 一致性(Consistency):事務前后數據的完整性必須保持一致
  3. 隔離性(Isolation):事物的隔離性是指多個用戶并發(fā)訪問數據庫時芋浮,一個用戶的事務不能被其他用戶的事務所干擾,多個并發(fā)事務之間數據要相互隔離
  4. 持久性(Durability):持久性是指一個事務一旦被提交壳快,它對數據庫中的數據改變就是永久性的纸巷,接下來即使數據庫發(fā)生故障也不應該對其有任何影響

隔離性的重要性:

忽略隔離性可能會導致如下問題:

  • 數據臟讀:在一個事務中讀取到了另一個事務未提交的數據
  • 不可重復讀:在一個事務內讀取表中的某一行數據镇草,多次讀取結果不同
  • 虛讀(幻讀):在一個事務中讀取到了別的事務插入的數據,導致前后讀取不一致(insert)

隔離性解決方案:
隔離級別:

  • read uncommitted(未提交讀):級別最低瘤旨。臟讀梯啤、不可重復讀、虛讀都有可能發(fā)生
  • read committed(提交讀):可避免臟讀存哲。不可重復讀因宇、虛讀都有可能發(fā)生
  • repeatable read(可重復讀):可避免臟讀、不可重復讀祟偷。虛度可能發(fā)生
  • serializable(串行化):可避免臟讀察滑、不可重復讀、虛讀的情況

設置事務隔離級別:
set session transaction isolation level XXX (XXX代表隔離級別)

查詢事務隔離級別:
select @@tx_isolatioin

安全性:read uncommitted < read committed < repeatable read < serializable
效率: read uncommited > read committed > repeatable read > serializable

數據庫設置這些隔離級別:考慮安全性和效率肩袍,一般不使用read uncommitted和serializable

MySQL的默認值:repeatable read Oracle的默認值:read committed

JDBC中設置隔離級別:

在Connection對象中有 void setTransactionIsolation(int level)設置隔離級別杭棵;level提供四種隔離級別的常量

模擬臟讀:
1、同時開啟倆個CMD窗口氛赐,第一個窗口設置事務隔離級別為最低魂爪。
2、倆個窗口各自開啟一個事務
3艰管、窗口1先查詢一次數據
4滓侍、窗口2update數據
5、窗口1再次執(zhí)行數據查詢
6牲芋、窗口2執(zhí)行事務回滾
7撩笆、窗口1再次執(zhí)行數據查詢

模擬臟讀

解決臟讀:設置窗口1的隔離級別為read committed;但是在窗口1再次執(zhí)行查詢會出現不可重復讀的情況
解決不可重復讀:設置窗口1的隔離級別為repeatable read;如果在窗口2中插入一條新的數據,則在窗口1中會出現虛讀情況
解決虛讀:設置窗口1的隔離級別為serializable;


數據庫連接池

連接池:為了解決高并發(fā)導致頻繁創(chuàng)建和銷毀線程缸浦,而提供的一種解決方案夕冲。原理:默認創(chuàng)建N個連接,存入內存裂逐,當用戶使用時則從池中取歹鱼,用完之后將連接歸還池中

DBCP連接池:
DBCP是Apache的開源連接池實現,使用DBCP數據源卜高,應用程序在系統(tǒng)中需要導入如下4個jar文件:
commons-dbcp2-2.1.1和commons-pool2-2.4.2(依賴包下載)以及commons-collections4-4.1jar(依賴包下載)和commons-logging-1.2.jar(依賴包下載

參數 缺省值 描述
username(用戶名) 用戶名
password(密碼) 密碼
url(JDBC連接串) 數據庫地址
driverClassName(JDBC驅動程序) 數據庫驅動
connectionProperties(連接屬性 )
defaultAutoCommit(自動提交) driver default 默認自動提交事務
defaultReadOnly(只讀設置) driver default 此池創(chuàng)建的連接的默認只讀狀態(tài)弥姻。如果沒有設置則setReadOnly方法不會被調用。
defaultTransactionIsolation(事務隔離級別) driver default NONE READ_COMMITTED READ_UNCOMMITTED REPEATABLE_READ SERIALIZABLE
defaultCatalog DATE 由該池創(chuàng)建的連接的默認目錄掺涛。
cacheState(緩存狀態(tài)) true
defaultQueryTimeout(查詢超時時間) null 查詢超時時間庭敦,值為int類型,“空”意味著將使用驅動程序默認值
enableAutocommitOnReturn(連接歸還到池時薪缆,設置為自動提交) true 如果設置為true秧廉,則連接被歸還到連接池時,會指定設置為autoCommit = true
rollbackOnReturn(連接歸還到池時,回滾所有操作) true 如果設置為true定血,則連接被歸還到連接池時赔癌,會自動執(zhí)行一次rollback()诞外;前提是自動提交 = true and 非只讀澜沟。
initialSize 0 這個池被啟動時初始化的創(chuàng)建的連接個數,起始生效版本:1.2
maxTotal(最大活動連接數) 8 可以在這個池中同一時刻被分配的有效連接數的最大值峡谊,如設置為負數茫虽,則不限制
maxIdle(最大空閑連接數) 8 如設置為負數,則不限制將被釋放既们,在歸還到連接池時在池中濒析,可以保持空閑狀態(tài)的最大連接數,超出設置值之外的空閑連接
minIdle(最小空閑連接數) 0 如設置為負數啥纸,則不限制將被釋放号杏,在歸還到連接池時在池中,可以保持空閑狀態(tài)的最大連接數斯棒,超出設置值之外的空閑連接
maxWaitMillis(從連接池獲取連接時盾致,最大等待時間) indefinitely 可以在池中保持空閑的最小連接數,低于設置值時荣暮,空閑連接將被創(chuàng)建庭惜,以努力保持最小空閑連接數>=minIdle,如設置為0穗酥,則不創(chuàng)建 這里設置的數值生效的前提是:timeBetweenEvictionRunsMillis(空閑對象驅逐線程運行時的休眠毫秒數)被設置為正數护赊。

使用:

Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
            
    //加載配置文件
    Properties properties = new Properties();
    InputStream in = DBCPTest.class.getClassLoader().getResourceAsStream("dbcp.properties");
    properties.load(in);
    //設置連接參數
    BasicDataSource dataSource = BasicDataSourceFactory.createDataSource(properties);
    //獲取連接
    conn = dataSource.getConnection();
    //執(zhí)行SQL語句
    String sql = "SELECT * FROM user";
    stmt = conn.prepareStatement(sql);
    rs = stmt.executeQuery();
    while (rs.next()) {
                
        System.out.println(rs.getInt("id") + "\t" + rs.getString("username") + "\t" + rs.getString("password"));
        }
} catch (Exception e) {
        e.printStackTrace();
}finally {
            
        JDBCUtils.close(rs, stmt, conn);
}

C3P0連接池:
C3P0是一個開源的JDBC連接池,它實現了數據源和JNDI綁定砾跃,支持JDBC3規(guī)范和JDBC2的標準擴展骏啰,目前使用它的開源項目有Hibernate,Spring等
C3P0使用:
使用過程如果出現異常,則還需依賴該庫mchange-commons-java-0.2.12.jar
首先在src目錄下創(chuàng)建名稱為:c3p0-config.xml的配置文件抽高,具體配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<!--當連接池中的連接耗盡的時候c3p0一次同時獲取的連接數判耕。Default: 3 -->
<property name="acquireIncrement">3</property>
<!--定義在從數據庫獲取新連接失敗后重復嘗試的次數。Default: 30 -->
<property name="acquireRetryAttempts">30</property>
<!--兩次連接中間隔時間厨内,單位毫秒祈秕。Default: 1000 -->
<property name="acquireRetryDelay">1000</property>
<!--連接關閉時默認將所有未提交的操作回滾。Default: false -->
<property name="autoCommitOnClose">false</property>
<!--c3p0將建一張名為Test的空表雏胃,并使用其自帶的查詢語句進行測試请毛。如果定義了這個參數那么
屬性preferredTestQuery將被忽略。你不能在這張Test表上進行任何操作瞭亮,它將只供c3p0測試
使用方仿。Default: null-->
<property name="automaticTestTable">Test</property>
<!--獲取連接失敗將會引起所有等待連接池來獲取連接的線程拋出異常。但是數據源仍有效
保留,并在下次調用getConnection()的時候繼續(xù)嘗試獲取連接仙蚜。如果設為true此洲,那么在嘗試
獲取連接失敗后該數據源將申明已斷開并永久關閉。Default: false-->
<property name="breakAfterAcquireFailure">false</property>
<!--當連接池用完時客戶端調用getConnection()后等待獲取新連接的時間委粉,超時后將拋出
SQLException,如設為0則無限期等待呜师。單位毫秒。Default: 0 -->
<property name="checkoutTimeout">100</property>
<!--通過實現ConnectionTester或QueryConnectionTester的類來測試連接贾节。類名需制定全路徑汁汗。
Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester-->
<property name="connectionTesterClassName"></property>
<!--指定c3p0 libraries的路徑,如果(通常都是這樣)在本地即可獲得那么無需設置栗涂,默認null即可
Default: null-->
<property name="factoryClassLocation">null</property>
<!--Strongly disrecommended. Setting this to true may lead to subtle and bizarre bugs.
(文檔原文)作者強烈建議不使用的一個屬性-->
<property name="forceIgnoreUnresolvedTransactions">false</property>
<!--每60秒檢查所有連接池中的空閑連接知牌。Default: 0 -->
<property name="idleConnectionTestPeriod">60</property>
<!--初始化時獲取三個連接,取值應在minPoolSize與maxPoolSize之間斤程。Default: 3 -->
<property name="initialPoolSize">3</property>
<!--最大空閑時間,60秒內未使用則連接被丟棄角寸。若為0則永不丟棄。Default: 0 -->
<property name="maxIdleTime">60</property>
<!--連接池中保留的最大連接數忿墅。Default: 15 -->
<property name="maxPoolSize">15</property>
<!--JDBC的標準參數扁藕,用以控制數據源內加載的PreparedStatements數量。但由于預緩存的statements
屬于單個connection而不是整個連接池球匕。所以設置這個參數需要考慮到多方面的因素纹磺。
如果maxStatements與maxStatementsPerConnection均為0,則緩存被關閉亮曹。Default: 0-->
<property name="maxStatements">100</property>
<!--maxStatementsPerConnection定義了連接池內單個連接所擁有的最大緩存statements數橄杨。Default: 0 -->
<property name="maxStatementsPerConnection"></property>
<!--c3p0是異步操作的,緩慢的JDBC操作通過幫助進程完成照卦。擴展這些操作可以有效的提升性能
通過多線程實現多個操作同時被執(zhí)行式矫。Default: 3-->
<property name="numHelperThreads">3</property>
<!--當用戶調用getConnection()時使root用戶成為去獲取連接的用戶金度。主要用于連接池連接非c3p0
的數據源時许起。Default: null-->
<property name="overrideDefaultUser">root</property>
<!--與overrideDefaultUser參數對應使用的一個參數允懂。Default: null-->
<property name="overrideDefaultPassword">password</property>
<!--密碼檩小。Default: null-->
<property name="password"></property>
<!--定義所有連接測試都執(zhí)行的測試語句。在使用連接測試的情況下這個一顯著提高測試速度斥难。注意:
測試的表必須在初始數據源的時候就存在烤镐。Default: null-->
<property name="preferredTestQuery">select id from test where id=1</property>
<!--用戶修改系統(tǒng)配置參數執(zhí)行前最多等待300秒阅酪。Default: 300 -->
<property name="propertyCycle">300</property>
<!--因性能消耗大請只在需要的時候使用它框全。如果設為true那么在每個connection提交的
時候都將校驗其有效性察绷。建議使用idleConnectionTestPeriod或automaticTestTable
等方法來提升連接測試的性能。Default: false -->
<property name="testConnectionOnCheckout">false</property>
<!--如果設為true那么在取得連接的同時將校驗連接的有效性津辩。Default: false -->
<property name="testConnectionOnCheckin">true</property>
<!--用戶名拆撼。Default: null-->
<property name="user">root</property>
</c3p0-config>
<!-- 常用配置-->
<c3p0-config>
    <!-- 默認連接數據庫的配置 -->
    <default-config>
        <!-- jdbcUrl:表示連接數據庫的URL -->
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc</property>
        <!-- driverClass:表示連接數據庫的驅動類 -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <!-- user:表示連接數據庫使用的用戶名 -->
        <property name="user">root</property>
        <!-- password:表示連接數據庫使用的密碼 -->
        <property name="password">1314</property>
        <!-- acquireIncrement:表示連接池中的連接數達到上限,每次增加幾個連接. -->
        <property name="acquireIncrement">3</property>
        <!-- initialPoolSize:表示初始化連接池中的連接數 -->
        <property name="initialPoolSize">10</property>
        <!-- minPoolSize:表示設置連接池中最小連接數 -->
        <property name="minPoolSize">4</property>
        <!-- maxPoolSize:表示設置連接池中最大連接數 -->
        <property name="maxPoolSize">10</property>
    </default-config>
</c3p0-config>
  • 使用
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
        
try {
    //獲取連接池對象
    ComboPooledDataSource cpds = new ComboPooledDataSource();
    /獲取連接
    conn = cpds.getConnection();
    String sql = "SELECT * FROM user";
    //執(zhí)行預編譯
    stmt = conn.prepareStatement(sql);
    //執(zhí)行SQL
    rs = stmt.executeQuery();
    while (rs.next()) {
                
        System.out.println(rs.getInt("id") + "\t" + rs.getString("username") + "\t" + rs.getString("password"));
            }
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
            
        JDBCUtils.close(rs, stmt, conn);
}
  • C3P0優(yōu)勢:
  1. dbcp沒有自動回收空閑連接的功能容劳。
  2. c3p0有自動回收空閑連接功能。
  3. dbcp只能在配置文件中配置一個數據庫
  4. c3p0可以在配置文件中配置多個數據庫

JNDI(Java Naming and Directory Interface)連接池:

JNDI連接池是SUN公司提供的一種標準的Java命名系統(tǒng)接口闸度,JNDI提供統(tǒng)一的客戶端API竭贩。它目前只能用于Web應用中,而不能應用在Java應用

JNDI連接池使用步驟:
配置使用Tomcat服務器內置的連接池JNDI莺禁,配置文件名為context的xml文件留量,該文件有三種常見配置位置:

  • Tomcat服務器安裝目錄的conf目錄中:表示Tomcat服務器下的所有Web工程都可以訪問該連接池
  • Tomcat服務器安裝目錄的conf目錄/Catalina目錄/loacalost目錄中:表示當前虛擬主機(localhost)下的所有Web工程都可以訪問該連接池
  • 當前Web工程根目錄/META-INF目錄中:表示只有當前Web工程可以訪問該連接池

1、context.xml文件具體配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <!-- 
        Resouce標簽:表示配置連接池相關信息
        name屬性:為當前連接池綁定一個名稱
        type屬性:指定當前連接池使用的類型
        driverClassName屬性:指定數據庫驅動類
        url屬性:指定數據庫連接
        username屬性:指定數據庫登錄用戶名
        password屬性:指定數據庫登錄密碼
        maxActive屬性:設置連接池最大活動連接數量
        maxIdle屬性:設置連接池最大空閑數量
    
     -->
    <Resource name="" 
        auth="Container" 
        type="javax.sql.DataSource"
        driverClassName="com.mysql.jdbc.Driver" 
        url="jdbc:mysql://localhost:3306/jdbc"
        username="root" 
        password="1314" 
        maxActive="8" 
        maxIdle="4" />
</Context>

2睁宰、將MySQL數據庫驅動jar包拷貝到Tomcat服務器的安裝目錄的lib目錄中肪获,是由Tomcat服務器內置連接池JNDI連接數據庫
3、通過運行在JNDI容器內部的程序(Servlet/JSP)訪問Tomcat服務器的內置連接池JNDI
ComboPooledDataSource dataSource = new ComboPolledDataSource("mysql");
4柒傻、代碼中使用JNDI數據庫連接池

//1、通過Context接口较木,讀取META-INF目錄下的contxt.xml配置文件
Context context = new InitialContext();
//2红符、java:comp/env路徑固定
Context envCtx = (Context) context.lookup("java:comp/env");
//3、通過綁定的連接池名稱查找對應的連接池對象
DataSource dataSource = (DataSource) envCtx.lookup("jdbc/jdbc");
//4伐债、通過連接池對象獲取連接對象
Connection conn = dataSource.getConnection();
InitialContext被配置為一個Web應用程序的最初部署预侯,并提供給Web應用組件(只讀訪問)。所有配置項和資源放在java的JNDI命名空間:java:comp/env部分
DBUtils工具類

DBUtils是操作數據庫的組件峰锁,對傳統(tǒng)操作數據庫的類進行二次封裝萎馅,可以把結果轉換成List。是Java編程中數據庫操作的實用工具虹蒋,小巧實用

DBUtils的特點:

  • 對于數據表的讀操作糜芳,它可以把結果轉換為List,Array魄衅,Set等Java集合峭竣,便于程序員操作
  • 對于數據表寫的操作晃虫,也變的簡單(只需寫SQL語句)
  • 可以使用數據源皆撩,使用JNDI,數據庫連接池等技術來優(yōu)化性能哲银,重用已經構建好的數據庫連接對象扛吞,而不像PHP,ASP哎呀荆责,費時費力的不斷重復構建和析構這樣的對象
  1. DBUtils類:主要提供一系列close()方法滥比,commit()方法及rollback()方法
  2. QueryRunner類:主要提供了兩組方法,一組是需要手動管理事務草巡,一種是工具管理事務

需要手動設置事務:

  • QueryRunner()
  • public int update(Connection conn, String sql, Object... params)
  • query(Connection conn, String sql, ResutlSetHandler<T> rsh, Object... params)

DBUtils工具管理事務:

  • QueryRunner(DataSource ds)
  • public int update(String sql, Object... params)
  • public Object query(Strin sql, ResultSetHandler<T> rsh, Object... params)

ResultSetHandler接口:
作用:將查詢數據庫的結果集封裝成集合
DBUtils提供眾多的實現類
實際開發(fā)中守呜,不需要實現該接口型酥,只需要繼承實現類即可
實現類:

  • AbstractKeyedHandler:
  • AbstractListHandler
  • BaseResultSetHandler
  • ArrayHandler:將結果集中的第一行數據轉成對象數組
  • ArrayListHandler:將結果集中的每一行數據都轉成一個對象數組,再存放到集合中
  • BeanHandler:將結果集單條記錄存放到JavaBean中
  • BeanListHandler:將結果集中的每一條記錄都轉換成JavaBean后再存放到集合中
  • BeanMapHandler:將結果集中的每一條記錄轉成JavaBeam查乒,再將JavaBean封裝到Map集合中
  • ColumnListHandler:將結果集的某一列數據存放到List集合中
  • KeyedHandler:將結果集中的每一行數據都封裝到一個Map里(List<Map>)弥喉,再把這些Map存放到一個Map里,外層Map的key為指定的列
  • MapHandler:將結果集中的第一行數據封裝到一個Map集合中玛迄,key為列名由境,value即為值
  • MapListHandler:將結果集中的每一行數據封裝到一個Map集合中,再將每個Map添加到List集合中
  • ScalarHandler:進行單行查詢

使用:

public static void main(String[] args) {
        QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource());
        String sql = "SELECT * FROM user";
        
        try {
            System.out.println("------------------------ArrayHandler------------------------");
            //ArrayHandler:將結果集中的第一行數據封裝到數組中
            Object[] arr = queryRunner.query(sql, new ArrayHandler());
            for (Object object : arr) {
                
                System.out.println(object);
            }
            
            System.out.println("------------------------ArrayListHandler------------------------");
            //ArrayListHandler:將結果集的每一行數據封裝到Array中蓖议,再將Array封裝到List中
            List<Object[]> arrList = queryRunner.query(sql, new ArrayListHandler());
            for (Object[] objects : arrList) {
                
                for (Object object : objects) {
                    
                    System.out.println(object);
                }
            }
            
            System.out.println("------------------------BeanHandler------------------------");
            //BeanHandler:將結果集的第一行數據封裝到JavaBean中
            User user = queryRunner.query(sql, new BeanHandler<>(User.class));
            System.out.println(user.toString());
            
            System.out.println("------------------------BeanListHandler------------------------");
            //BeanListHandler:將結果集的每一行數據封裝到JavaBean中虏杰,再將每個JavaBean封裝到List中
            List<User> userList = queryRunner.query(sql, new BeanListHandler<>(User.class));
            for (User user2 : userList) {
                
                System.out.println(user2.toString());
            }
            
            System.out.println("------------------------MapHandler------------------------");
            Map<String, Object> map = queryRunner.query(sql, new MapHandler());
            Set<String> keySet = map.keySet();
            Iterator<String> iterator = keySet.iterator();
            while (iterator.hasNext()) {
                String key = (String) iterator.next();
                System.out.println(key + "," + map.get(key));
            }
            
            System.out.println("------------------------MapListHandler------------------------");
            List<Map<String, Object>> mapList = queryRunner.query(sql, new MapListHandler());
            for (Map<String, Object> map2 : mapList) {
                
                Set<String> keySet2 = map2.keySet();
                Iterator<String> iterator2 = keySet2.iterator();
                while (iterator2.hasNext()) {
                    String key = (String) iterator2.next();
                    System.out.println(key + "," + map2.get(key));
                }
            }
            
            System.out.println("------------------------ColumnListHandler------------------------");
            //ColumnListHandler:將查詢的列名封裝到List集合中
            List<String> columnList = queryRunner.query(sql, new ColumnListHandler<String>("username"));
            for (String columnName : columnList) {
                
                System.out.println(columnName);
            }
            
            System.out.println("------------------------KeyedHandler------------------------");
            //KeyedHandler:將結果集的每一行數據封裝到一個Map集合中,再將這些Map集合統(tǒng)一封裝到另一個外層Map中勒虾,而外層的Map的鍵則是我們創(chuàng)建KeyedHandler時構造傳入的column的值
            Map<Object, Map<String, Object>> keyedMap = queryRunner.query(sql, new KeyedHandler<>("username"));
            System.out.println(keyedMap);
            
            System.out.println("------------------------ScalarHandler------------------------");
            String sql2 = "SELECT count(*) FROM user";
            long value = queryRunner.query(sql2, new ScalarHandler<Long>());
            System.out.println(value);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末纺阔,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子修然,更是在濱河造成了極大的恐慌笛钝,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件愕宋,死亡現場離奇詭異玻靡,居然都是意外死亡,警方通過查閱死者的電腦和手機中贝,發(fā)現死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門囤捻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人邻寿,你說我怎么就攤上這事蝎土。” “怎么了老厌?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵瘟则,是天一觀的道長。 經常有香客問我枝秤,道長醋拧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任淀弹,我火速辦了婚禮丹壕,結果婚禮上,老公的妹妹穿的比我還像新娘薇溃。我一直安慰自己菌赖,他們只是感情好,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布沐序。 她就那樣靜靜地躺著琉用,像睡著了一般堕绩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上邑时,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天奴紧,我揣著相機與錄音,去河邊找鬼晶丘。 笑死黍氮,一個胖子當著我的面吹牛,可吹牛的內容都是我干的浅浮。 我是一名探鬼主播沫浆,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼滚秩!你這毒婦竟也來了专执?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤叔遂,失蹤者是張志新(化名)和其女友劉穎他炊,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體已艰,經...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年蚕苇,在試婚紗的時候發(fā)現自己被綠了哩掺。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡涩笤,死狀恐怖嚼吞,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情蹬碧,我是刑警寧澤舱禽,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站恩沽,受9級特大地震影響誊稚,放射性物質發(fā)生泄漏。R本人自食惡果不足惜罗心,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一里伯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧渤闷,春花似錦疾瓮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜒灰。三九已至,卻和暖如春肩碟,著一層夾襖步出監(jiān)牢的瞬間强窖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工腾务, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留毕骡,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓岩瘦,卻偏偏與公主長得像未巫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子启昧,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內容