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(); } } } }