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則按如下方式配置:
- 前往/usr/local/mysql/support-files/目錄下
- 執(zhí)行copy命令:gaopengfeideMacBook-Pro:~ gaopengfei$ cp my-default.cnf /etc/ 將my-default.cnf拷貝到/etc目錄下
- 修改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 條件);
子查詢運算符:
- <小于
- >大于
- <=小于等于
- >=大于等于
- =等于
- <>或
- !=不等于
- in范圍any或all
>any:大于子查詢中的最小值
>all:大于子查詢中的最大值
語法:select * from table where 條件 >any (select 字段 from table where 條件);
JDBC
- JDBC(Java DataBase Connectivity)Java數據庫連接猴鲫,它是由SUN公司為了簡化Java對數據庫操作而定義的一套規(guī)范
- 用法
//注冊驅動
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();
- 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:///數據庫名
- 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()//回滾
事物:是一組邏輯的操作蟹倾,要么全都成功匣缘,要么全部失敗,事物支持回滾
- 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()//清除批處理
- 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();
- 釋放資源
使用JDBC時购撼,執(zhí)行完畢后跪削,一定要釋放資源(ResultSet、Statement份招、Connection對象)切揭。
特別是Connection對象,它是非常稀有的資源锁摔,用完必須釋放,如果不及時正確關閉哼审,極容易導致系統(tǒng)宕機谐腰。
Connection對象的使用原則:盡量晚創(chuàng)建孕豹,盡量早釋放
為確保資源釋放代碼可以運行,資源釋放代碼一定寫在finally語句中 - 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)框架
- 數據庫事務
事務 指邏輯上的一組操作饱溢,組成這組操作的各個單元,要不全部成功走芋,要不全部失敗
數據庫開啟事務命令:
- start transaction 開啟事務
- rollback 回滾事務
- commit 提交事務
關閉MySQL事務自動提交(MySQL數據庫事物是默認提交的):
- 查詢是否默認提交:show variables like ‘%commit%’;
- 設置不默認提交:set autocommit=off或者0;如果設置autocommit為off绩郎,意味著以后每條SQL 都會處于一個事務中,相當于每條SQL執(zhí)行前 都執(zhí)行 start transaction
注: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):
- 原子性(Atomicity):原子性是指事物是一個不可分割的工作單位,事務中的操作要么都發(fā)生胧后,要么都不發(fā)生
- 一致性(Consistency):事務前后數據的完整性必須保持一致
- 隔離性(Isolation):事物的隔離性是指多個用戶并發(fā)訪問數據庫時芋浮,一個用戶的事務不能被其他用戶的事務所干擾,多個并發(fā)事務之間數據要相互隔離
- 持久性(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)勢:
- dbcp沒有自動回收空閑連接的功能容劳。
- c3p0有自動回收空閑連接功能。
- dbcp只能在配置文件中配置一個數據庫
- 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哎呀荆责,費時費力的不斷重復構建和析構這樣的對象
- DBUtils類:主要提供一系列close()方法滥比,commit()方法及rollback()方法
- 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();
}