1. 程式人生 > >JDBC和異常總結及常見使用

JDBC和異常總結及常見使用

java


JDBC

-一、JDBC連接過程

01.註冊驅動

Class.forName("oracle.jdbc.driver.OracleDriver");

02.獲取連接

Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@10.0.19.252:1521:orcl","itxy","itxy");


-二、JDBC 常用接口

JDBC : sun提供的訪問數據庫的規範

這套規範用於高速數據庫廠商,通過何種方式訪問他們的數據庫

01.java.sql 接口 Connection

sun的JDBC是一套接口規範,沒有提供實現 (JDBC的接口實現,只能由各個數據庫廠商自己實現)

02.java.sql

接口 Statement 用於執行靜態 SQL 語句並返回它所生成結果的對象。

java.sql

接口 PreparedStatement 表示預編譯的 SQL 語句的對象。


註意:開發的時候首先 PreparedStatement

原因: 1. 預編譯的 SQL 語句的對象運行速度快

2. 安全 (可以防止SQL註入攻擊)


03.java.sql 接口 ResultSet

表示數據庫結果集的數據表,通常通過執行查詢數據庫的語句生成。

ResultSet 對象具有指向其當前數據行的光標。最初,光標被置於第一行之前。next

方法將光標移動到下一行;因為該方法在 ResultSet 對象沒有下一行時返回 false,所以可以在 while 循環中使用它來叠代結果集。

默認的 ResultSet 對象不可更新,僅有一個向前移動的光標。因此,只能叠代它一次,並且只能按從第一行到最後一行的順序進行。


-三、JDBC使用常見異常

java.lang

類 Class<T>

java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver2

數據庫驅動未加載成功


java.sql.SQLException: The Network Adapter could not establish the connection

數據庫連接串配置錯誤


java.sql.SQLException: ORA-01017: invalid username/password; logon denied

訪問數據庫的用戶名或密碼錯誤


異常總結

1. 異常的處理順序,一定是子類異常處理在前,父類異常處理在後

try {
	biz.deleteStudent("s002");	
	System.out.println("刪除完畢!");
} catch (SQLIntegrityConstraintViolationException e) {
			
} catch (Exception e) {
	e.printStackTrace();
	System.out.println("系統異常,請檢查");
}	

2. 在三層架構中,每層都可能出現異常,但是只有UI層采用最終的異常顯示的決定權。

其它層可以捕獲異常,但是處理後需要再次拋出!


3. 非托管資源(不受GC管理的資源),一定要在finally中釋放,放在資源泄漏;

不受GC管理的資源:如數據連接Connection , 必須要用close()方法釋放

還有IO流的釋放,也必須使用close()

 try {
				
}finally{
	dao.closeConnection();
}

4. 自定義異常

public class HavaSonRecordsException extends Exception{
	
    public HavaSonRecordsException(String msg){
    	super(msg);
    }
}

5. java.lang 類 Throwable

直接已知子類:

Error, Exception

Error 是 Throwable 的子類,用於指示合理的應用程序不應該試圖捕獲的嚴重問題。

註意: Error無需用try catch

Error異常舉例: 如內存越界、內存溢出


6. try catch 是可以嵌套使用的


7.只有try,沒有catch

  try {
	dao.updateStuState(0, sno);				
}finally{
	//釋放IO流的句柄
	System.out.println("io資源釋放");
}	

8. checked Exception 與 unChecked Exception(Runtime Exception)


checked Exception(特點:在編譯期可以明確異常的可能發生的位置,而且必須要捕獲它):

ClassNotFoundException

SQLException


Runtime Excepiton (編譯期無法檢查到這個異常,只有在程序運行期間才能知道):

NullExcepiton , 10/0 , format("")

public class InputNullExcepiton extends RuntimeException{}   //RuntimeException無需強制處理

public class InputNullExcepiton extends Exception{}         //自定義異常,建議extends Exception

//數據庫Connection是一種寶貴的資源,很容易稱為業務系統的性能瓶頸

使用原則:

晚打開,早關閉 ----- 使用時間越短越好

Connection盡量可以重用

//數據庫Connection的數量不是無限的,它受限於硬件(CPU)

補:

java.util 類 Date //除了dao層之外,都盡量使用java.util.Date

java.sql 類 Date //只能在dao層使用


練習(Java項目):

自定義異常

public class InputNullException extends Exception {
	public InputNullException(String msg){
		super(msg);
	}
}

web層

public class StuUI {
	
	/**
	 * 刪除學生
	 */
	public static void deleteStuTest(){
		StuBiz biz = new StuBiz();
		try {
			biz.deleteStudent("s003234");	
			System.out.println("刪除完畢!");
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("系統異常,請檢查");
		}		
	}
	
	/**
	 * 添加學生
	 */
	public static void addStuTest(){
		StuBiz biz = new StuBiz();
		TStudent ts = new TStudent();
		
		ts.setSname("jack");
		ts.setSno("s002244");
		ts.setCno("c0124");
		ts.setSex("f");
		ts.setAddress("taiyuan");
		ts.setTel("155345263");
		
		
		String s = "2012-06-21";
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		java.util.Date d1 = null;
		try {
			d1 = sdf.parse(s);
		} catch (ParseException e1) {
			e1.printStackTrace();
		} //先把字符串轉為util.Date對象
		java.sql.Date d2 = new java.sql.Date(d1.getTime()); 
		ts.setBirthday(d2);
		
		ts.setHeight(54);
		ts.setState(1);
		
		try {
			biz.addStu(ts);
			System.out.println("添加學生成功!");
		} catch(InputNullException e){
			System.out.println("入參為空!");
		}catch (Exception e) {
			e.printStackTrace();
			System.out.println("插入失敗!");
		}
		
	}
	
	/**
	 * 查詢所有學生信息
	 */
	public static void showStu(){
		StuBiz biz = new StuBiz();
		try {
			List<TStudent> stus = biz.findAllStu();
			Iterator<TStudent> it = stus.iterator();
		    while(it.hasNext()){
		    	TStudent t = it.next();
		    	System.out.println(t.getSname() + "--" + t.getSno() + "--" + t.getBirthday());
		    }
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("查詢失敗!");
		}
	}

		
	public static void main(String[] args) {
		StuUI.showStu();
	}
}


業務邏輯層:

public class StuBiz {
	
	/**
	 * 刪除學生
	 *    註意: 1. 當學生沒有產生業務數據時,直接刪除物理記錄
	 *        2.  當學生產生了業務數據時,只能做邏輯刪除
	 * @param sno
	 * @throws Exception
	 */
	public void deleteStudent(String sno) throws Exception{
		if(sno != null){
			StuDao dao = new StuDao();
			try {
				dao.deleteStudent(sno);	
			}catch(java.sql.SQLIntegrityConstraintViolationException e){
			  if(e.getSQLState().equals("23000")){
				  //找到了子記錄
				  try {
					  dao.updateStuState(0, sno);
				  } catch (Exception e2) {
					  e2.printStackTrace();
					  throw e2;
				  }finally{
					  dao.closeConnection();
				  }				  
			  }
			} catch (Exception e) {				
				throw e;
			}finally{
				dao.closeConnection();
			}
						
		}else{
			throw new Exception("入參錯誤,sno=null");
		}
		
	}

	/**
	 * 添加學生
	 * @param ts
	 * @throws Exception
	 */
	public void addStu(TStudent ts) throws Exception{
		if(ts!=null){
			StuDao dao = new StuDao();
			try {
				boolean bet = dao.findClass(ts.getCno());
				if(!bet){
					throw new Exception("班級不存在");
				}else{
					dao.addStu(ts);
				}
			} catch (Exception e) {
				throw e;
			}finally {
				dao.closeConnection();
			}		
		}else{
			throw new Exception("入參錯誤!");
		}
	}

	/**
	 * 查詢所有學生信息
	 * @return
	 * @throws Exception
	 */
	public List<TStudent> findAllStu() throws Exception {
	 //註意:面向接口編程不能是實現類返回
		List<TStudent> stus;
		StuDao dao = new StuDao();
		try {
			stus = dao.findAllStu();
		} catch (Exception e) {
			throw e;
		}finally {
			dao.closeConnection();
		}
		
		return stus;
	}
}

數據層:

public class StuDao extends BaseDao{
	/**
	 * 刪除學生
	 *    註意: 1. 當學生沒有產生業務數據時,直接刪除物理記錄
	 *        2.  當學生產生了業務數據時,只能做邏輯刪除
	 * @param sno
	 * @throws Exception
	 */
	public void deleteStudent(String sno) throws Exception{		
		String sql = "delete from tstudent where sno=?";
		this.openConnection();
		PreparedStatement ps = this.conn.prepareStatement(sql);
		ps.setString(1, sno);
		ps.executeUpdate();
		ps.close();		
	}
	
	/**
	 * 修改學生的狀態值
	 * @param state
	 * @throws Exception
	 */
	public void updateStuState(int state,String sno) throws Exception{
		String sql = "update tstudent set state=? where sno=?";
		this.openConnection();
		PreparedStatement ps = this.conn.prepareStatement(sql);
		ps.setInt(1, state);
		ps.setString(2, sno);
		ps.executeUpdate();
		ps.close();
		
	}

	/**
	 * 添加學生
	 * @param ts
	 * @throws Exception
	 */
	public void addStu(TStudent ts) throws Exception {
		String sql = "insert into tstudent values(?,?,?,?,?,?,?,?,?)";
		//數據庫打開
		this.openConnection();
		PreparedStatement ps = this.conn.prepareStatement(sql);
		ps.setString(1, ts.getSname());
		ps.setString(2, ts.getSno());
		ps.setString(3, ts.getCno());
		ps.setString(4, ts.getSex());
		ps.setString(5, ts.getAddress());
		ps.setString(6, ts.getTel());
		ps.setDate(7, ts.getBirthday());
		ps.setInt(8, ts.getHeight());
		ps.setInt(9, ts.getState());
					
		ps.executeUpdate();
		ps.close();	
	}

	/**
	 * 添加學生的時候,檢查班級是否存在
	 * @param cno
	 * @return
	 * @throws Exception
	 */
	public boolean findClass(String cno) throws Exception {
		boolean bRet = false;
		
		String sql = "select * from tclass where cno=?";
		this.openConnection();
		PreparedStatement ps = this.conn.prepareStatement(sql);
		ps.setString(1, cno);
		ResultSet rs = ps.executeQuery();
		while(rs.next()){
			bRet = true;
		}
		rs.close();
		ps.close();
		
		return bRet;
	}

	/**
	 * 查詢所有學生信息
	 * @return
	 * @throws Exception
	 */
	public List<TStudent> findAllStu() throws Exception {
		List<TStudent> stuList;//寫成兩行
		String sql = "select * from tstudent";//寫在openConnection之前
		this.openConnection();
		PreparedStatement ps = this.conn.prepareStatement(sql);
		ResultSet rs = ps.executeQuery();
		
		stuList = new ArrayList<TStudent>();//這樣如果前面有錯就不用產生內存分配
		while(rs.next()){
			TStudent ts = new TStudent();//new TStudent()是新建一個內存,這個不會被釋放掉,只不過每次會建立對象引用
			ts.setSname(rs.getString("sname"));
			ts.setCno(rs.getString("cno"));
			ts.setSno(rs.getString("sno"));
			ts.setAddress(rs.getString("address"));
			ts.setSex(rs.getString("sex"));
			ts.setTel(rs.getString("tel"));
			ts.setBirthday(rs.getDate("birthday"));
			ts.setHeight(rs.getInt("height"));
			ts.setState(rs.getInt("state"));
			stuList.add(ts);//集合裏面放的是引用,向集合中添加,就是復制對象地址,然後釋放這個對象地址
		}
		rs.close();
		ps.close();
		
		return stuList;
	}

}

basedao

public class BaseDao {
	protected Connection conn;		

	public void openConnection() throws Exception{
		
		//通過反射技術,對oracel的驅動對象進行類的加載 (其實是在做類型檢查)
		//在類的加載時,會調用OracleDriver中的靜態代碼塊和靜態變量初始化
		Class.forName("oracle.jdbc.driver.OracleDriver");  
		conn = DriverManager.getConnection("jdbc:oracle:thin:@10.0.19.252:1521:orcl","itxy","itxy");
	}
	
	public void closeConnection() {
		if(this.conn != null){
			try {
				this.conn.close();	
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

本文出自 “秦斌的博客” 博客,謝絕轉載!

JDBC和異常總結及常見使用