SQL語句執行流程
JDBC執行數據庫操作語句,首先需要將sql語句打包成爲網絡字節流,傳遞給數據庫,數據庫經過解包,然後編譯sql語句,最後執行,然後將結果通過字節流的形式返回給JDBC API
簡單的來說大致分爲以下幾點:
-
JDBC打包sql語句
-
發送字節流至數據庫
-
數據庫解包
-
檢查sql語法,編譯sql
-
執行sql語句
- 將sql語句返回給JDBC 接口
<br/>數據庫的鏈接步驟
<br/>
-
註冊驅動 (Driver)
-
建立連接(創建Connection)
-
創建執行sql語句(通常是創建Statement或者其子類)
-
執行語句
-
處理執行結果(在非查詢語句中,該步驟是可以省略的)
- 釋放相關資源
案例
@Test
public void wholeExample(){
try {
//1.註冊驅動
Class.forName("com.mysql.jdbc.Driver");
//2.獲取數據庫連接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root","123456");
//3.創建執行句柄
Statement stmt = conn.createStatement();
//4.執行sql語句
ResultSet rs = stmt.executeQuery("select * from user");
//5.處理執行結果
while(rs.next()){
System.out.println("id:"+rs.getInt(1)+"\tname:"+rs.getString(2)+"\tbirthday:"+rs.getDate(3)+"\tmoney:"+rs.getFloat(4));
}
//6.釋放資源
rs.close();
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
數據類型
<br/>
CLOB
當我們存放大量的文本信息時,數據庫中的varchar或者varchar2肯定是不能滿足的,varchar2好像最多只能有4000個長度,存放一篇很長的文章或者一個文本信息,我們採用CLOB類型
BLOB
針對二進制文件進行的存取,比如圖片,音頻等信息
//stream文件流
PreparedStatement.setBlob(index, stream)
SQL數據類型與Java數據類型
<br/>
事務
數據庫的事務是保證數據完整性的一種機制,簡而言之,就是怎樣確保數據的執行過程要麼都成功,要麼都失敗
ACID機制
<br/>
-
原子性(atomicity):組成事務處理的語句形成了一個邏輯單元,不能只執行其中的一部分
-
一致性(consistency):在事務處理執行前後,數據庫是一致的(兩個賬戶要麼都變,或者都不變)
-
隔離性(isolcation):一個事務處理對另一個事務處理沒有影響
- 持續性(durability):事務處理的效果能夠被永久保存下來
Jdbc的事務默認是打開的,也就是說執行每一步操作的話,事務都會隱式的進行提交,在拋出異常之前,我們的更改操作已經同步到了數據庫中去
事務控制函數
//提交事務
- connection.commit();
//回滾事務
- connection.rollback();
分佈式事務
通常所說的跨庫事務,要求幾個數據庫的事務在一個應用中保持一致,JTA就是爲了解決這個問題而誕生的
PreparedStatement接口
在數據庫操作中PreparedStatement會帶來很大的方便,減少拼寫sql字符串帶來的麻煩,防止SQL注入的發生.
-
PreparedStatement是Statement的子類
- PreparedStatement是一個預處理命令的Statement實現
CallableStatement接口
在數據庫操作中調用數據庫中的存儲過程
案例:執行有參數有返回值的存儲過程
- 創建一個存儲過程
create or replace procedure test1(in id integer,in name varchar(20),in money float,out counter integer)
as
begin
insert into user values(id,name,now(),money);
select count(1) into counter from user;
commit;
end test1;
- 編寫測試代碼,在需要將值返回時,需要對其進行註冊
@Test
public void callProcedureWithParamWithResult() throws SQLException{
Connection conn = null;
CallableStatement stmt = null;
ResultSet rs = null;
try {
conn = ConnCreate.getConnection("jdbc:mysql://localhost:3306/test",
"root", "123456");
String sql = "{call test1(?,?,?,?)}";
stmt = conn.prepareCall(sql);
stmt.setInt(1, 17);
stmt.setString(2, "test");
stmt.setFloat(3, 6000);
stmt.registerOutParameter(1, Types.INTEGER);
stmt.executeUpdate();
int counter = stmt.getInt(4);
System.out.println(counter);
} finally {
ConnCreate.close(conn, stmt, rs);
}
}
批處理
<br/>
//添加一條條的sql
- stmt.addBatch(sql)
// 執行批處理
- stmt.executeBatch()
<br/>分頁技術
利用sql語句進行分頁(eg: mysql的limit ? ?, 一個offsize偏移量,另一個pagesize頁面數量)
@Test
public void page() throws SQLException{
page(100,20);
}
static void page(int start,int total) throws SQLException{
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
conn = ConnCreate.getConnection("jdbc:mysql://localhost:3306/test",
"root", "123456");
String sql = "select * from user limit ?,?";
stmt = conn.prepareStatement(sql);
stmt.setInt(1, start);
stmt.setInt(2, total);
rs = stmt.executeQuery();
while(rs.next()) //向下滾動
{
System.out.println("name:"+rs.getString(2)+"id:"+rs.getInt(1));
}
} finally {
ConnCreate.close(conn, stmt, null);
}
}
連接池
使用jdbc最大的開銷之一就是創建數據庫,當我們頻繁的創建數據庫時,勢必影響應用的效率,或者在數據庫關閉出現問題時,我們不能馬上釋放,時間長一些,整個數據庫的 資源將會被我們的應用耗盡
-
C3P0
- DBCP
ResultSetMetaData
如果我們不知道我們的一個sql語句查詢了幾列結果集,並且每列的列名,類型等信息,這個時候我們應該使用ResultSetMetaData
<br/>
案例
@Test
public void resultMeta() throws SQLException{
String sql="select * from user";
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
conn = ConnFactory.getConnection();
stmt = conn.prepareStatement(sql);
rs = stmt.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
for(int i=1;i<=count;++i){
System.out.println("Type:"+rsmd.getColumnType(i));
System.out.println("ColumnName:"+rsmd.getColumnName(i));
System.out.println("ColumnLable:"+rsmd.getColumnLabel(i));
}
} finally{
ConnFactory.close(conn, stmt, rs);
}
}