JDBC

-一、JDBC连接过程

01.注册驱动

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

02.获取连接

1
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

      访问数据库的用户名或密码错误


注:

JDBC 与 

     UPDATE 表名 SET 字段名1=表达式1, 字段名2=表达式2, ... WHERE 条件;

     重点: 返回值,int (update语句影响的记录条数) 


    但是如果jdbc与insert就不用看返回值,如果有异常,则表示插入失败。

异常总结

     

 1. 异常的处理顺序,一定是子类异常处理在前,父类异常处理在后

1
2
3
4
5
6
7
8
9
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()

1
2
3
4
5
  try  {
                 
} finally {
     dao.closeConnection();
}

  4. 自定义异常

1
2
3
4
5
6
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  

1
2
3
4
5
6
   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("")

1
2
3
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项目):

自定义异常

1
2
3
4
5
public  class  InputNullException  extends  Exception {
     public  InputNullException(String msg){
         super (msg);
     }
}

web层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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();
     }
}


业务逻辑层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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;
     }
}

数据层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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();
             }
         }
     }
}