前言
只有光頭才能變強。
文本已收錄至我的GitHub精選文章,歡迎Star:https://github.com/ZhongFuCheng3y/3y
不知道大家在工作中還有沒有寫過JDBC,我在大三去過一家小公司實習,里邊用的就是JDBC,只不過它封裝了幾個工具類。寫代碼的時候還是能感受到「這是真真實實的JDBC代碼」
現在開發一般都是Mybatis,也有公司用的Hibernate或者Spring Data JPA。很多時候,不同的項目由不同的程序員開發,在公司層面可能沒有將技術完全統一起來,一個項目用Mybatis,一個項目用Hibernate都是很有可能的。
不管用的是什么ORM
框架,都是在JDBC上封裝了一層嘛,所以JDBC還是需要好好學習的。
什么是ORM?
Object_Relative DateBase-Mapping,在Java對象與關系數據庫之間建立某種映射,以實現直接存取Java對象。
很多同學不知道JDBC要學到怎么樣的一種程度,這里我來講講JDBC的知識點有哪些,哪些應該是需要掌握的。
JDBC基礎知識
什么是JDBC?JDBC全稱為:Java Data Base Connectivity,它是可以執行SQL語句的Java API
每種數據庫都有自己的圖形界面呀,我都可以在里邊操作執行數據庫相關的事,為什么我們要用JDBC?
- 數據庫里的數據是給誰用的?給程序用的。我們用的是Java程序語言,所以需要用Java程序去鏈接數據庫來訪問數據。
- 市面上有非常多的數據庫,本來我們是需要根據不同的數據庫學習不同的API,sun公司為了簡化這個操作,定義了JDBC API【接口】。對於我們來說,操作數據庫都是在JDBC API【接口】上,使用不同的數據庫,只要用數據庫廠商提供的數據庫驅動程序即可。
其實可以好好細品一下JDBC,把接口定義出來,反正你給我實現就對了,無論數據庫怎么變,用的時候是同一套API
隨后我們簡單學習一下這幾個接口:Connection、Statement、ResultSet。寫出小白必學的Java連接數據庫的代碼:
- 導入MySQL或者Oracle驅動包
- 裝載數據庫驅動程序
- 獲取到與數據庫連接
- 獲取可以執行SQL語句的對象
- 執行SQL語句
- 關閉連接
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
/*
* 加載驅動有兩種方式
*
* 1:會導致驅動會注冊兩次,過度依賴於mysql的api,脫離的mysql的開發包,程序則無法編譯
* 2:驅動只會加載一次,不需要依賴具體的驅動,靈活性高
*
* 我們一般都是使用第二種方式
* */
//1.
//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//2.
Class.forName("com.mysql.jdbc.Driver");
//獲取與數據庫連接的對象-Connetcion
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/zhongfucheng", "root", "root");
//獲取執行sql語句的statement對象
statement = connection.createStatement();
//執行sql語句,拿到結果集
resultSet = statement.executeQuery("SELECT * FROM users");
//遍歷結果集,得到數據
while (resultSet.next()) {
System.out.println(resultSet.getString(1));
System.out.println(resultSet.getString(2));
}
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
/*
* 關閉資源,后調用的先關閉
*
* 關閉之前,要判斷對象是否存在
* */
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
基本流程完了以后,我們要重點學習一下PreparedStatement接口與Statement接口的區別,為什么要用PreparedStatement。
- Statement對象編譯SQL語句時,如果SQL語句有變量,就需要使用分隔符來隔開,如果變量非常多,就會使SQL變得非常復雜。PreparedStatement可以使用占位符,簡化sql的編寫
- Statement會頻繁編譯SQL。PreparedStatement可對SQL進行預編譯,提高效率,預編譯的SQL存儲在PreparedStatement對象中
- PreparedStatement防止SQL注入。(Statement通過分隔符
'++'
,編寫永等式,可以不需要密碼就進入數據庫)
數據庫連接池
為什么我們要使用數據庫連接池?數據庫的連接的建立和關閉是非常消耗資源的,頻繁地打開、關閉連接造成系統性能低下
常見的數據庫連接池有C3P0、DBCP、Druid。大家在學習的時候可以用Druid,我曾經用C3P0寫了個Demo被diss了(:
Druid是阿里開源的一個項目,有中文文檔,跟着學着連接數據庫,我相信不會太難。GitHub搜「Druid」就能搜到了
分頁
說到分頁,面試和工作都是非常常見的了,是必須要掌握的技術。下面來簡單說一下Oracle和MySQL是如何實現分頁的,以及對應的解釋:
Oracle分頁:
/*
Oracle分頁語法:
@lineSize---每頁顯示數據行數
@currentPage----當前所在頁
*/
SELECT *FROM (
SELECT 列名,列名,ROWNUM rn
FROM 表名
WHERE ROWNUM<=(currentPage*lineSize)) temp
WHERE temp.rn>(currentPage-1)*lineSize;
/*
Oracle分頁:
Oracle的分頁依賴於ROWNUM這個偽列,ROWNUM主要作用就是產生行號。
分頁原理:
1:子查詢查出前n行數據,ROWNUM產生前N行的行號
2:使用子查詢產生ROWNUM的行號,通過外部的篩選出想要的數據
例子:
我現在規定每頁顯示5行數據【lineSize=5】,我要查詢第2頁的數據【currentPage=2】
注:【對照着語法來看】
實現:
1:子查詢查出前10條數據【ROWNUM<=10】
2:外部篩選出后面5條數據【ROWNUM>5】
3:這樣我們就取到了后面5條的數據
*/
MySQL分頁:
/*
Mysql分頁語法:
@start---偏移量,不設置就是從0開始【也就是(currentPage-1)*lineSize】
@length---長度,取多少行數據
*/
SELECT *
FROM 表名
LIMIT [START], length;
/*
例子:
我現在規定每頁顯示5行數據,我要查詢第2頁的數據
分析:
1:第2頁的數據其實就是從第6條數據開始,取5條
實現:
1:start為5【偏移量從0開始】
2:length為5
*/
總結:
- Mysql從
(currentPage-1)*lineSize
開始取數據,取lineSize
條數據 - Oracle先獲取
currentPage*lineSize
條數據,從(currentPage-1)*lineSize
開始取數據
DBUtils
DBUtils我覺得還算是一個挺好用組件,在學習Hibernate,Mybatis這些ORM框架之前,可以學着用用。可以極大簡化我們的JDBC的代碼,用起來也很方便。
如果急忙着寫畢業設計,還沒時間來得及學ORM框架,用這個工具來寫DAO
數據訪問層,我覺得是一個不錯的選擇。
可以簡單看看代碼:
/*
* 使用DbUtils框架對數據庫的CRUD
* 批處理
*
* */
public class Test {
@org.junit.Test
public void add() throws SQLException {
//創建出QueryRunner對象
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "INSERT INTO student (id,name) VALUES(?,?)";
//我們發現query()方法有的需要傳入Connection對象,有的不需要傳入
//區別:你傳入Connection對象是需要你來銷毀該Connection,你不傳入,由程序幫你把Connection放回到連接池中
queryRunner.update(sql, new Object[]{"100", "zhongfucheng"});
}
@org.junit.Test
public void query()throws SQLException {
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "SELECT * FROM student";
List list = (List) queryRunner.query(sql, new BeanListHandler(Student.class));
System.out.println(list.size());
}
@org.junit.Test
public void delete() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "DELETE FROM student WHERE id='100'";
queryRunner.update(sql);
}
@org.junit.Test
public void update() throws SQLException {
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "UPDATE student SET name=? WHERE id=?";
queryRunner.update(sql, new Object[]{"zhongfuchengaaa", 1});
}
@org.junit.Test
public void batch() throws SQLException {
//創建出QueryRunner對象
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "INSERT INTO student (name,id) VALUES(?,?)";
Object[][] objects = new Object[10][];
for (int i = 0; i < 10; i++) {
objects[i] = new Object[]{"aaa", i + 300};
}
queryRunner.batch(sql, objects);
}
}
放干貨
現在已經工作有一段時間了,為什么還來寫JDBC
呢,原因有以下幾個:
- 我是一個對排版有追求的人,如果早期關注我的同學可能會發現,我的GitHub、文章導航的
read.me
會經常更換。現在的GitHub導航也不合我心意了(太長了),並且早期的文章,說實話排版也不太行,我決定重新搞一波。 - 我的文章會分發好幾個平台,但文章發完了可能就沒人看了,並且圖床很可能因為平台的防盜鏈就掛掉了。又因為有很多的讀者問我:”你能不能把你的文章轉成PDF啊?“
- 我寫過很多系列級的文章,這些文章就幾乎不會有太大的改動了,就非常適合把它們給”持久化“。
基於上面的原因,我決定把我的系列文章匯總成一個PDF/HTML/WORD
文檔。說實話,打造這么一個文檔花了我不少的時間。為了防止白嫖,關注我的公眾號回復「888」即可獲取。
文檔的內容均為手打,有任何的不懂都可以直接來問我(公眾號有我的聯系方式)。
涵蓋Java后端所有知識點的開源項目(已有6 K star):https://github.com/ZhongFuCheng3y/3y
如果大家想要實時關注我更新的文章以及分享的干貨的話,微信搜索Java3y。
PDF文檔的內容均為手打,有任何的不懂都可以直接來問我(公眾號有我的聯系方式)。