JDBC6.0最終版。
數據訪問層Dao
業務邏輯層service
我們在Dao層中封裝了對錶的常用操作,增刪改查。
我們在Util裏封裝了JDBCUtil工具類解決冗餘問題。
現在我們有一個銀行轉賬問題:
1.根據卡號,密碼,先查詢
2.轉出賬戶再餘額足夠的情況下,減去轉出資金。
3轉入賬戶添加轉入資金。
對於2,3步驟我們因當把他們看作是一個事務,事務的原子性,一致性,隔離性。要求
要麼一起成功,要麼一起不成功。當然從現實考慮,也確實應當這樣,如果在2,3步驟之間失敗了
就回退。
這整個轉賬邏輯,我們可以稱之爲業務。所以針對軟件的三層結構。我們把這部分稱爲-----業務層(service)
在service層調用Dao層的方法。
而在service層裏的連接對象和Dao層裏的連接對象不是同一個對象,這就會造成混亂,打破事務的一致性。
從而導致,轉出錢減去了,轉入賬戶沒加錢。
Service方法中的事務控制失敗。
原因:service控制事務時過的conn和DAO訪問數據庫使用的conn時兩個不同對象
解決:
保證service和Dao使用同一個conn對象
1:通過參數傳遞。
2:每個線程對象有一個Map屬性,可以存儲數據
在service獲得conn,將conn放入當前Thread對象,在DAO訪問數據庫時取時,從Thread取出conn
ThreadLocal簡介及使用:
操作當前線程對象中的一小塊空間。
1創建ThreadLocal對象 ThreadLocal<Connection> tdl = new ThreadLocal<Connection>();
2tdl.set(conn);將conn添加到當前線程。
3tdl.get();獲得當前線程中的數據
4tdl.remove()移除當前線程裏的數據
話不多說我們來看代碼有三個文件 JDBC_Util3.java JDBC_Dao3.java JDBC_Service.java
JDBC_Util3.java
public class JDBC_Util3 {
private static final Properties prop = new Properties();
private static final ThreadLocal<Connection> tdl = new ThreadLocal<Connection>();
static{
InputStream is = null;
try {
is = JDBC_Util3.class.getResourceAsStream("jdbc.properties");
prop.load(is);
String driverName = prop.getProperty("driverName");
Class.forName(driverName);
} catch (Exception e) {
e.printStackTrace();
}
}
//返回鏈接
public static Connection getConnection() throws Exception {
Connection conn = null;
conn = tdl.get();//獲得當前線程連接
if(conn == null){
//說明當前線程沒有conn
String user = prop.getProperty("user");
String password = prop.getProperty("password");
String url = prop.getProperty("url");
conn = DriverManager.getConnection(url,user,password);
//將當 conn存入線程
tdl.set(conn);
}
return conn;
}
/**
* 釋放資源
*/
public static void release(ResultSet rs,Statement stm,Connection conn){
try {
if(rs!=null){rs.close();}
if(stm!=null){stm.close();}
if(conn!=null){
conn.close();
tdl.remove();//移除當前線程對象中的conn
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
JDBC_Dao3.java
public class JDBC_Dao3 {
/ /更新賬戶
public void upDateAccount(Account toAcc) {
Connection conn = null;
PreparedStatement pstm = null;
try {
conn = JDBC_Util3.getConnection();
String sql = "update account set card_id=?,"
+ "password=?,balance=?,phone=? where card_id=?";
pstm = conn.prepareStatement(sql);
pstm.setString(1, toAcc.getCardId());
pstm.setString(2, toAcc.getPassword());
pstm.setDouble(3, toAcc.getBalance());
pstm.setString(4, toAcc.getPhone());
pstm.setString(5, toAcc.getCardId());
int i = pstm.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}finally{
JDBC_Util.release(null, pstm, null);
}
}
// 查詢賬戶
public Account queryAccount(Integer toCardId) {
Connection conn = null;
Statement stm = null;
ResultSet rs = null;
Account acc = null;
try {
conn = JDBC_Util3.getConnection();
stm = conn.createStatement();
String sql = "select * from account where card_id = "
+ toCardId;
System.out.println(sql);
rs = stm.executeQuery(sql);
while (rs.next()) {
acc = new Account();
acc.setCardId(rs.getString("card_id"));
acc.setPassword(rs.getString("password"));
acc.setBalance(rs.getDouble("balance"));
acc.setPhone(rs.getString("phone"));
}
} catch (Exception e) {
}finally{
JDBC_Util.release(rs, stm, null);
}
return acc;
}
}
JDBC_Service.java
public class JDBC_Service {
public void transfer(Integer fromCardId,String password,
Integer toCardId,Double money){
Connection conn = null;
try{
conn = JDBC_Util2.getConnection();
//事務自動提交關閉
conn.setAutoCommit(false);
JDBC_Dao3 dao = new JDBC_Dao3();
//驗證卡號是否存在
Account fromAcc = dao.queryAccount(fromCardId);
if(fromAcc == null){
throw new RuntimeException("卡號不存在");
}
//驗證密碼是否正確
if(null==password||!password.equals(fromAcc.getPassword())){
throw new RuntimeException("密碼錯誤");
}
//驗證餘額
if(fromAcc.getBalance()<money){
throw new RuntimeException("餘額不足");
}
//轉出賬戶更新
fromAcc.setBalance(fromAcc.getBalance()-money);
dao.upDateAccount(fromAcc);
Account toAcc = dao.queryAccount(toCardId);
//驗證到賬卡號
if(toAcc ==null){
throw new RuntimeException("到賬卡號不存在");
}
//轉入賬戶更新
toAcc.setBalance(toAcc.getBalance()+money);
dao.upDateAccount(toAcc);
//提交事務
conn.commit();
}catch(Exception e){
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally{
JDBC_Util.release(null, null, conn);
}
}
}
最後main函數測試
JDBC_Service sv = new JDBC_Service();
sv.transfer(10002, "123321", 10004, 30.00);
轉賬成功
10002 -30 10004 +30
=========================華麗麗的終結===========================
總結:雖然由於快節奏的開發,編程速度的追求,越愛越多的MVC框架出現,比如持久層的hibernate,
mybatis等等,他們對Dao層的支持都很強大,既 快速,又簡便。但是他們的底層同樣是使用了JDBC,
爲了追求高速簡便,我們可以不使用JDBC,但一定要了解JDBC。瞭解JDBC也有助於學習其他持久層框架。
以上就是我對JDBC全部心得。
限於文章篇幅原因,這裏僅僅介紹冰山一角。由於筆者的水平有限,編寫時間也很倉促,
文中難免會出現一些錯誤或者不準確的地方,不妥之處懇請讀者批評指正。