JDBC学习总结

  一、概述JDBC 
    JDBC从物理结构上说就是Java语言访问数据库的一套接口集合。 
    从本质上来说就是调用者(程序员)和实现者(数据库厂商)之间的协议。 

    JDBC API 使得开发人员可以使用纯Java的方式来连接数据库,并进行操作。 
    ODBC:基于C语言的数据库访问接口。 
    JDBC:是Java版的ODBC。 
    JDBC 特性:高度的一致性、简单性(常用的接口只有4、5个)。 

驱动程序按照工作方式分为四类: 
    1、JDBC-ODBC bridge + ODBC 驱动 
       JDBC-ODBC bridge桥驱动将JDBC调用翻译成ODBC调用,再由ODBC驱动翻译成访问数据库命令。 
       优点:可以利用现存的ODBC数据源来访问数据库。 
       缺点:从效率和安全性的角度来说的比较差。不适合用于实际项目。 
    2、基于本地API的部分Java驱动 
       我们应用程序通过本地协议跟数据库打交道。然后将数据库执行的结果通过驱动程序中的Java部分返回给客户端程序。 
       优点:效率较高。 
       缺点:安全性较差。 
    3、纯Java的网络驱动 
       (中间协议)            (本地协议) 
       app    JDBC     纯Java                 中间服务器               DB 
       缺点:两段通信,效率比较差 
       优点:安全信较好 
    4、纯Java本地协议:通过本地协议用纯Java直接访问数据库。 
       特点:效率高,安全性好。 

二、JDBC 编程的步骤 
        import java.sql.*; 
    0.参数化 
        String driverName = "com.mysql.jdbc.Driver"; 
        String url = "jdbc:mysql://localhost:3306/test"; //协议;库或服务器名称;服务器IP,端口 
        String username = "root"; 
        String password=""; 
            /* Oracle的连接 
            String driverName = "oracle.jdbc.driver.OracleDriver"; 
            String url = "jdbc:oracle:thin:@192.168.0.23:1521:ora10g"; 
            String username = "openlab"; 
            String password="open123";*/ 
        //以下这些都需要写在有异常的代码块里,所以需要提取出来。 
        Connection conn = null; 
        Statement stmt = null; //建议用PreparedStatement 
        ResultSet rs = null; 
    1.加载和注册数据库驱动 
        Class.forName(driverName);//自动注册;需要把驱动的jar包导进来;需处理异常 
            /*方法二:实例化具体的Driver驱动,这写法一般不用(不能参数化驱动名,不够灵活) 
            Driver driver = new com.mysql.jdbc.Driver(); 
            DriverManager.registerDriver(driver); //将驱动交于DriverManager托管*/ 
            /*方法三:Dos运行时,java -Djdbc.drives = oracle.jdbc.driver.OracleDriver; --可多个 */ 
    2.连接数据库 
        conn = DriverManager.getConnection(url, username, password);//需处理异常 
        //Connection返回数据库连接,如:“com.mysql.jdbc.Connection@1ffb8dc”;连接不成功则返回 null 
    3.创建Statement对象 //为了类型安全和批量更新的效率,改用PreparedStatement 
        stmt = conn.createStatement();//需处理异常 
        //返回其生成结果的对象"oracle.jdbc.driver.OracleStatement@198dfaf" 
    4.操作数据库,执行SQL语句 
        String sql = "select * from tableName";//SQL语句里不需要写分号 
        rs = stmt.executeQuery(sql); //executeQuery(sqlString) 查询 返回查询结果集 
            /* String sql = "insert into tableName values(?,?)"; // ?占位符 
            int number = stmt.executeUpdate(sql);//更新,再返回int(更新、修改影响的条数) */ 
    5.处理数据(游标) 
        StringBuffer sb = new StringBuffer(); //缓存;用它可提高读取速度。当然,不用也可以。 
        ResultSetMetaData md = rs.getMetaData(); //ResultSetMetaData可获取列的类型和属性信息 
        int col = md.getColumnCount(); //获取列的数目 
        while(rs.next()){ //rs.next()使游标下移一位,返回boolean,没有下一个结果则返回false 
            for(int i=1; i<=col;i++){ // index(JDBC 的下标从1开始) 
                sb.append(md.getColumnName(i)+"="+rs.getString(i)+"  "); 
            } sb.append("\n"); 
        }System.out.println(sb); 
            //1.游标的初始位置在第一条记录的前面,使第一次调用next()后,刚好拿到第一个结果。 
            //2.游标的最终位置在最后一条记录的后面(结果集的前面和后面留空,真正存在) 
    6.释放资源,断开与数据库的连接 
        //先判断是否有引用资源,再释放(释放空资源会抛异常);注意顺序 
        if(rs!=null)try{rs.close();}catch(Exception e){e.printStackTrace();} 
        if(stmt!=null)try{stmt.close();}catch(Exception e){e.printStackTrace();} 
        if(conn!=null)try{conn.close();}catch(Exception e){e.printStackTrace();} 
        //这些异常没法处理,处理只为方便调试。所以这些异常处理也只是打印。 
        /*要按先ResultSet结果集,后Statement,最后Connection的顺序关闭资源, 
        因为ResultSet需要Statement和Connection连接时才可以用的;Statement也需要Connection才可用; 
        结束Statement之后有可能其它的Statement还需要连接,因此不能先关闭Connection。ResultSet同理。*/ 

    步骤 1、2、6 每次都一样,可以重构。 
       因为加载驱动是个一次性工作,所以可以采用静态初始化块来加载驱动; 
       连接数据库的方法应该自己负责,获取数据库连接信息和驱动的信息,并处理相关异常; 
       释放数据库资源的方法要考虑到ResultSet、Statement、Connection的不同情况,并处理相关异常。 

三、JDBC几个重要接口重点讲解 
    在JDBC 中包括了两个包:java.sql和javax.sql。 
        ① java.sql   基本功能。 
           这个包中的类和接口主要针对基本的数据库编程服务,如生成连接、执行语句以及准备语句和运行批处理查询等。 
           同时也有一些高级的处理,比如批处理更新、事务隔离和可滚动结果集等。 
        ② javax.sql  扩展功能。 
           它主要为数据库方面的高级操作提供了接口和类。 
           如为连接管理、分布式事务和旧有的连接提供了更好的抽象,它引入了容器管理的连接池、分布式事务和行集等。 

        API                        说明 
    Connection            与特定数据库的连接(会话)。能够通过getMetaData方法获得数据库提供的信息、 
                          所支持的SQL语法、存储过程和此连接的功能等信息。代表了数据库。 
    Driver                每个驱动程序类必需实现的接口,每个数据库驱动程序也都应该提供一个实现Driver接口的类。 
    DriverManager(Class)  管理一组JDBC驱动程序的基本服务。作为初始化的一部分,此接口会尝试加载 
                          在”jdbc.drivers”系统属性中引用的驱动程序。只是一个辅助类,是工具。 
    Statement             用于执行静态SQL语句并返回其生成结果的对象。 
    PreparedStatement     继承Statement接口,表示预编译的SQL语句的对象,SQL语句被预编译并且存储 
                          在PreparedStatement对象中。然后可以使用此对象高效地多次执行该语句。 
    CallableStatement     用来访问数据库中的存储过程。它提供了一些方法来指定语句所使用的输入/输出参数。 
    ResultSet             指的是查询返回的数据库结果集。 
    ResultSetMetaData     可用于获取关于ResultSet对象中列的类型和属性信息的对象。 
    注:除了标出的Class,其它均为接口。每个都是“java.sql.”包下的。 


    1. Statement  —— SQL语句执行接口 
       代表了一个数据库的状态,在向数据库发送相应的SQL语句时,都需要创建Statement接口或PreparedStatement接口。 
       在具体应用中,Statement主要用于操作不带参数(可以直接运行)的SQL语句,比如删除语句、添加或更新。 

    2. PreparedStatement:预编译的Statement 
        第一步:通过连接获得PreparedStatement对象,用带占位符(?)的sql语句构造。 
            PreparedStatement  pstm = con.preparedStatement(“select * from test where id=?”); 
        第二步:设置参数 
            pstm.setString(1,“ganbin”);//第一个字段是“ganbin”;需一个个字段写 
        第三步:执行sql语句 
            Rs  =  pstm.excuteQuery(); 
        statement发送完整的Sql语句到数据库不是直接执行而是由数据库先编译,再运行。每次都需要编译。 
        而PreparedStatement是先发送带参数的Sql语句,由数据库先编译,再发送一组组参数值。(同构时不需重复编译) 
        如果是同构的sql语句,PreparedStatement的效率要比statement高。而对于异构的sql则两者效率差不多。 
        一般都用PreparedStatement代替Statement,因为它是类型安全的。Statement对参数类型不作检查,故不够安全。 
            同构:两个Sql语句可编译部分是相同的,只有参数值不同。 
            异构:整个sql语句的格式是不同的 
        注意点:1、使用预编译的Statement编译多条Sql语句一次执行 
              2、可以跨数据库使用,编写通用程序 
              3、能用预编译时尽量用预编译 
              4、如果第二个SQL语句与前一个是异构的,需要再次编译“ps = con.prepareStatement(sql);“ 

    3. ResultSet —— 结果集操作接口 
       ResultSet接口是查询结果集接口,它对返回的结果集进行处理。ResultSet是程序员进行JDBC操作的必需接口。 

    4. ResultSetMetaData —— 元数据操作接口 
       ResultSetMetaData是对元数据进行操作的接口,可以实现很多高级功能。 
       Hibernate运行数据库的操作,大部分都是通过此接口。可以认为,此接口是SQL查询语言的一种反射机制。 
       ResultSetMetaData接口可以通过数组的形式,遍历数据库的各个字段的属性,对于开发者来说,此机制的意义重大。 

       JDBC通过元数据(MetaData)来获得具体的表的相关信息,例如,可以查询数据库中有哪些表,表有哪些字段,以及字段的 
       属性等。MetaData中通过一系列getXXX将这些信息返回给我们。     
       数据库元数据 Database MetaData 用connection.getMetaData()获得;包含了关于数据库整体元数据信息。 
       结果集元数据 ResultSet MetaData 用resultSet.getMetaData()获得;比较重要的是获得表的列名,列数等信息。 
                结果集元数据对象:ResultSetMetaData meta = rs.getMetaData(); 
                字段个数:meta.getColomnCount(); 
                字段名字:meta.getColumnName(); 
                字段JDBC类型:meta.getColumnType(); 
                字段数据库类型:meta.getColumnTypeName(); 

       数据库元数据对象:DatabaseMetaData dbmd = con.getMetaData(); 
                数据库名:dbmd.getDatabaseProductName(); 
                数据库版本号:dbmd.getDatabaseProductVersion(); 
                数据库驱动名:dbmd.getDriverName(); 
                数据库驱动版本号:dbmd.getDriverVersion(); 
                数据库Url:dbmd.getURL(); 
                该连接的登陆名:dbmd.getUserName(); 

四、JDBC 中使用Transaction编程(事务编程) 
     1. 事务是具备以下特征(ACID)的工作单元: 
        原子性(Atomicity)—— 如果因故障而中断,则所有结果均被撤消; 
        一致性(Consistency)—— 事务的结果保留不变; 
        孤立性(Isolation)—— 中间状态对其它事务是不可见的; 
        持久性(Durability)—— 已完成的事务结果上持久的。 
        原子操作,也就是不可分割的操作,必须一起成功一起失败。 

     2. 事务处理三步曲:(事务是一个边界) 
        ① connection.setAutoCommit(false); //把自动提交关闭;在创建Statement对象之前。 
        ② 正常的DB操作                       //若有一条SQL语句失败了,自动回滚 
        ③ connection.commit()              //主动提交 
        和 connection.rollback()            //主动回滚,一般写在catch语句里,而前三个都写在try语句里 

/*********事务的代码片段:*************/ 
try{ 
    con.setAutoCommit(false);   //step① 把自动提交关闭 
    Statement stm = con.createStatement();    //step② 正常的DB操作 
    stm.executeUpdate("insert into person(id, name, age) values(520, 'X-Man', 18)"); 
    stm.executeUpdate("insert into Person(id, name, age) values(521, 'Super', 19)"); 
    con.commit();               //step③ 成功主动提交 
} catch(SQLException e){ 
    try{con.rollback();        //如果中途发生异常,则roolback;这语句也会抛异常 
    }catch(Exception e){e.printStackTrace();}    //step③ 失败则主动回滚 
/************************************/ 

     3.JDBC事务并发产生的问题和事务隔离级别(难,建议用例子学习) 
     JDBC事务并发产生的问题: 
        ① 脏读(Dirty Reads) 一个事务读取了另一个并行事务还未提交的数据。(产生原因:读-写) 
        ② 不可重复读(UnPrpeatable Read)一个事务前后两次读取数据时,得到的数据不一致,被另一个已提交的事务修改。 
        ③ 幻读(Phantom Read) 一个事务再次查询,记录中的量变化了。(仅对统计有影响) 
     为了避免以上三种情况的出现,则采用事务隔离级别: 
        TRANSACTION_NONE                不使用事务(不可能用,只是理论的) 
        TRANSACTION_READ_UNCOMMITTED    可以读取未提交数据(允许脏读,也不可能) 
        TRANSACTION_READ_COMMITTED      只读提交的数据:可防止脏读;大部分数据库的默认隔离级别 
        TRANSACTION_REPEATABLE_READ     重复读取;只可以避免脏读 
        TRANSACTION_SERIALIZABLE        事务串行化:可以避免脏读,重复读取和幻读,但会降低数据库效率(最常用) 
     以上的五个事务隔离级别都是在Connection类中定义的静态常量。隔离级别越高,数据越安全,并发能力越差。 
     使用setTransactionIsolation(int level) 方法可以设置事务隔离级别。 
        比如:con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); 

五、JDBC 2.0新特性: 
    1、 Scrollability 结果集可滚动 
        滚动:可双向支持绝对与相对滚动,对结果集可进行多次迭代。 
            Con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); 
            //上句的 SCROLL 再到 CONCUR;不可以写反,编译器无法检测到,因为他们都是int类型的。 
        TYPE_FORWARD_ONLY:(单向,一般不用)该常量指示指针只能向前移动的 ResultSet 对象的类型。 
        TYPE_SCROOL_INSENSITIVE:(双向、不敏感)可滚动但不受其他更改影响的 ResultSet 对象的类型。 
        TYPE_SCROLL_SENSITIVE:(双向、敏感)该常量指示可滚动并且通常受其他的更改影响的 ResultSet 对象的类型。 
        CONCUR_READ_ONLY:(只读)该常量指示只可以读取的 ResultSet 对象的并发模式。 
        CONCUR_UPDATABLE:(可更新)该常量指示可以更新的 ResultSet 对象的并发模式。 

        绝对定位:boolean absolute(int row)将游标移动到指定位置。(row指记录的序号,没有这位置则返回false) 
                void afterLast() 将游标指向最后一条记录的后一位(有这位置,但记录为空)。 
                void beforeFirst()将游标指向最前一条记录的前一位。 
                boolean first()将游标移动到结果集最前。 
                boolean last()将游标移动到结果集末尾。 
        相对定位:boolean next()指向下一个。 
                boolean previous()指向前一个。 
                boolean relative(int) 向next()方向移动 int 位(int 可负)。 
        判位函数:boolean isAfterLast() 是否在最后一条的后一位。 
                boolean isBeforeFirst() 是否最前一条记录的前一位。 
                boolean isFirst() 是否最前位置。 
                boolean isLast() 是否最后位置。 

    2、 Updatability 结果集可更新。(主要应用于桌面应用) 
        更新:rs.updateString(“name”,”Tony”);//前面一个是字段的名字或者序号 
        rs.updateInt(1,”122323”);修改 
        rs.deleteRow();删除 
        rs.updateRow(); 
     注:只有在必要的时候(如桌面应用)才用结果集更新数据库,因为使用结果集更新数据库效率低下。 
        可更新结果集还要看数据库驱动程序是否支持,如Oracle就支持,MySql不支持。 
        并且只能针对一张表做结果集更新(不能子查询)。而且不能有join操作。 
        必须有主健,必须把所有非空没有默认值的字段查出。 
        处理可更新结果集时不能用select *来查询语句,必须指出具体要查询的字段。(不能使用通配符) 

    3、 Batch updates 可批量更新。 
        将多组对数据库的更新操作发送到数据库统一执行(数据库支持并发执行操作),以提高效率。 
        主要是通过减少数据(Sql语句或参数)在网络上传输的次数来节省时间。//数据有两组以上都应该用这批量更新 

        (1)对于Statement的批量更新处理: 
            stm.addBatch(Sql); 
            int[] ResultSet=stm.executeBatch();   

        (2)对于PreparedStatement的批量跟新处理 
             pstm.setInt(1,12);pstm.setString(2,”gaga”);…….. 
             pstm.addBatch(); 
             if(i%100==0) int[] ResultSet=pstm.executeBatch();//每个包50~200组数据,包太大也影响速度 

        注:int[] 中每一个数表示该Sql语句影响到的记录条数。 
        PreparedStatement的更新操作比Statement的更新操作多了一个设置参数的过程。 

六、SQL 3.0规范中的新类型: 
        Blob,大的二进制数据文件,最多存储2G。 
        Clob,大文本文件对象,最多存储2G。 
    在使用上述大对象的时候,在使用JDBC插入记录时要先插入一个空的占位对象, 
        "insert into tableName valuse(?,?,empty_blob())"//在数据库制造一个空的blob对象字段值 
        然后使用"select blobdata from t_blob where id = ? for update"对获得的大对象进行实际的写入操作 
        Blod通过getBinaryOutputStream()方法获取流进行写入。 
        getBinaryStream()方法获得流来获取Blob中存储的数据。 
    Clob的操作也和、Blob相同。 
        getAsciiStream()用于读取存储的文本对象,getAsciiOutputStream()方法之获得流用来向文件对象写入的。 

    BLOB与CLOB的异同点: 
        ① 都可以存储大量超长的数据; 
        ② BLOB (Binary Large Object) 以二进制格式保存,特别适合保存图片、视频文件、音频文件、程序文件等; 
        ③ CLOB (Character Large Object) 以Character格式保存于数据库中,适合保存比较长的文本文件。 

七、JDBC 2.0扩展 
    (一)JNDI(命名目录服务器): 
        定义:是Java的命名目录服务器。而JDBC是Java的数据库访问接口。 
            跟JDBC是平级的关系,是两个独立的JNDI;JDBC存储的数据都是以二维表的接口来大规模存储数据。 
            而JNDI存储的是差异性比较大的Java对象。JDBC取数据时用Sql语言访问数据。JNDI只用lookup和bind读写 
            JDBC API依赖于驱动程序,而JNDI依赖于服务提供者。 
            JDBC一般把数据存储到关系型数据库,而JNDI一般把数据存储到小型数据库、文件、甚至是注册表中。 
            JNDI相当于一个电话本。允许程序将一个对象和一个命名绑定到目录树上。 
               (JNDI的方法是在javax.naming包下,接口是Context实现类是InitialContext) 

        bind(String name, Object obj) 将名称绑定到对象资源,建立指定的字符串和对象资源的关联 
        lookup(String name) ,通过指定的字符串获得先前绑定的资源 

        /*********以下是将资源和JNDI命名绑定的方法**************/ 
        public static void bind(String context, Object obj) throws NamingException{ 
            Properties pro = new Properties(); 
            //Weblogic的JNDI服务器参数 
        pro.put(InitialContext.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory"); 
            pro.put(InitialContext.PROVIDER_URL, "t3://localhost:7001"); 
            Context ctx = new InitialContext(pro);//连接服务器 
            ctx.bind(context, obj);//存储 
        } 

    (二)DataSourse(数据源) 
        1、包含了连接数据库所需的信息,可以通过数据源获得数据库连接, 
           有时由于某些连接数据库的信息会变更,所以经常使用包含数据库连接信息的数据源。 
        2、一个标准的数据库连接工厂,作为DriverManager的替代项,保存与数据库相关的信息, 
           可以将数据库的连接信息放在一个共享的空间进行提取,不用在本地安装。 
           支持JNDI的绑定,支持连接池,支持分布式服务,用getConnection方法可获得与数据库的连接。 
           数据源应该由管理员创建(目的是为了保证数据库的安全)。所以数据源对象一般放在JNDI服务器中。 

        /*********通过JNDI获得绑定的资源**************/ 
        public static Object lookup(String context) throws NamingException{ 
            Properties pro = new Properties(); 
            //Weblogic的JNDI服务器参数 
        pro.put(InitialContext.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory"); 
            pro.put(InitialContext.PROVIDER_URL, "t3://localhost:7001"); 
            Context ctx = new InitialContext(pro); 
            return ctx.lookup(context);//查找;通过指定的字符串获得先前绑定的资源。 
        } 

    (三)连接池: 
        在内存中用来保存一个个数据库连接的对象。 
        访问数据库时,建立连接和拆连接需要花费较长时间,通过以连接池直连的方式获取连接,不需要注册驱动程序,可以大量 
        的节省销毁和创建连接的资源消耗,提高访问数据库的效率。 
     注:通过连接池获得的Connection,当执行con.close()时,不是关闭连接,而是表示将连接释放回连接池。 
         连接池是一个很复杂的算法,由服务器厂商实现。 

    (四)分布式的事务管理器JTA 
        分布式事务是通过多个异地数据库执行一组相关的操作,要保证原子操作的不可分, 
        也不用再自己写commit,和rollback,全部都交给中间服务器(TM)来处理。 
        (两阶段提交),也就是在中间服务器发送sql语句等待数据库回应,都回应操作成功才提交,否则同时回滚。 
                         ----------------   commit 
            con1 ------->| TM(事务管理器) | -----------> DB1 
            con2 ------->|    commit    | -----------> DB2 
                         ----------------   commit 
        1、regester 
        2、TM->execute() 
        3、commit->TM 
        4、TM->commit->DB 

    (五)RowSet 
                行集,这是一个JavaBean(事件机制),它增强了ResultSet的功能,包装了Connection、Statement、 
        ResultSet、DriverManage。通过RowSet可以获得数据源,设置隔离级别,也可以发送查寻语句,也实现了离线的操 
        作遍历,RowSet也支持预编译的Statement。是结果集的子接口,为快速开发而设(目前还不够成熟,没人用)。 
        RowSet中的方法大致上和ResultSet相同,当需要使用时请查阅JAVA API参考文档。 

八、JDBC应用的分层(DAO) 
    分层就是对功能的隔离,降低层与层之间的耦合性。 

    软件的分层初步: 
        JSP          Struts 
      View(界面) --> Controlle --> Atio ---> Service/Biz --> DAO ---->  DB 
       重新封装        可复用       封装信息      懂业务逻辑    数据访问层    数据层 
                                  调业务       无技术难度    与业务无关 
    谁依赖谁就看谁调用谁。 
    软件的分层设计,便于任务的划分、降低层间的耦合。 
    结合PMS的设计方法,思考这样分层的好处。 
    并且,使代码尽量减少重复,可复用性好,扩展余地加大,而且尽量减少硬编码。 
    需求:实现对Person类的数据库持久化基本操作(CRUD)。 

    BS架构和CS架构: 
    C-S架构:两层体系结构,主要应用于局域网中。 
    B-S架构:三层体系结构,表现层+业务逻辑层+数据存储层 
         注:层面越多,软件越复杂,但更灵活。分层是必须的但是要有个度。 
            层次一但确定,数据必须按层访问,不能跨层访问。 
            层与层之间最好时单向依赖(单向调用)。 

    纵向划分:按功能划分。分成三层体系结构(也有两层的)。 
    横向划分:按抽象划分。分成抽象部分和实现部分。 

/***以下老师没讲的内容******/ 
一、JDBC异常处理: 
   JDBC中,和异常相关的两个类是SQLException和SQLWarning。 
      1.SQLException类:用来处理较为严重的异常情况。 
        比如:① 传输的SQL语句语法的错误; 
             ② JDBC程序连接断开; 
             ③ SQL语句中使用了错误的函数。 
        SQLException提供以下方法: 
          getNextException() —— 用来返回异常栈中的下一个相关异常; 
          getErrorCode() —— 用来返回代表异常的整数代码 (error code); 
          getMessage() —— 用来返回异常的描述信息 (error message)。 

      2.SQLWarning类:用来处理不太严重的异常情况,也就是一些警告性的异常。 
        其提供的方法和使用与SQLException基本相似。 

    结合异常的两种处理方式,明确何时采用哪种。 
      A. throws        处理不了,或者要让调用者知道; 
      B. try … catch   能自行处理,就进行异常处理。 

二、JavaBean的定义: 
    1、是一个普通的Java类 
    2、在结构上没有预先的规定,不需要容器,不需要继承类或实现接口 
    3、要求必须放在包中,要求实现Serializable接口 
    4、要求有一个无参的构造方法. 
    5、属性的类型必须保持唯一,get方法返回值必须和set方法参数类型一致 
    6、对每个属性要有对应的get和set方法。注:隐藏属性可以没有 
    7、可以有外观作为显示控制,事件机制。 

三、SQL数据类型及其相应的Java数据类型 
   SQL数据类型             Java数据类型              说明 
  --------------------------------------------------------------------------------------- 
   INTEGER或者INT            int               通常是个32位整数 
   SMALLINT                 short             通常是个16位整数 
   NUMBER(m,n)            Java.sql.Numeric    合计位数是m的定点十进制数,小数后面有n位数 
   DECIMAL(m,n)              同上 
   DEC(m,n)               Java.sql.Numeric    合计位数是m的定点十进制数,小数后面有n位数 
   FLOAT(n)                  double           运算精度为n位二进制数的浮点数 
   REAL                      float            通常是32位浮点数 
   DOUBLE                    double           通常是64位浮点数 
   CHAR(n)                   String           长度为n的固定长度字符串 
   CHARACTER(n)              同上 
   VARCHAR(n)                String           最大长度为n的可变长度字符串 
   BOOLEAN                   boolean          布尔值 
   DATE                   Java.sql.Date       根据具体设备而实现的日历日期 
   TIME                   Java.sql.Time       根据具体设备而实现的时戳 
   TIMESTAMP              Java.sql.Timestamp  根据具体设备而实现的当日日期和时间 
   BLOB                   Java.sql.Blob       二进制大型对象 
   CLOB                   Java.sql.Clob       字符大型对象 
   ARRAY                  Java.sql.Array 

四、 面向对象的数据库设计 
    类的关联,继承在数据库中的体现: 
      类定义―――>表定义 
      类属性―――>表字段 
      类关系―――>表关系 
      对  象―――>表记录 
    注: Oid(对象id)―――>业务无关 
        在数据库中每一条记录都对应一个唯一的id; 
        Id通常是用来表示记录的唯一性的,通常会使用业务无关的数字类型 
        字段的个数不会影响数据库的性能,表则越多性能越低。 

    (一)类继承关系对应表, 
        1、 为每一个类建一张表。通过父类的Oid来体现继承关系。 
            特点:在子类表中引用父类表的主建作为自己的外建。 
            优点:方便查询。属性没有冗余。支持多态。 
            缺点:表多,读写效率低。生成报表比较麻烦。 
        2、 为每一个具体实现类建一个表 
            特点:父类的属性被分配到每一个子类表中。 
            优点:报表比较容易 
            缺点:如果父类发生改变会引起所有子类表随之更改。并且不支持多态。数据有少量冗余。 
        3、 所有的类在一张表中体现,加一个类型辨别字段 
            特点:效率高,查询不方便,用于字段不多时。 
            优点:支持多态,生成报表很简单。 
            缺点:如果任何一个类发生变化,必须改表。字段多,难以维护。 

    (二)类关联关系对应表 
        1、 一对一关联,类关系对应成表时有两种做法: 
            一是引用主键,也就是一方引用另一方的主键既作为外键有作为自身的主键。 
            二是外键引用,一方引用另一方的主键作为自身的外键,并且自己拥有主键。 
        2、 一对多关联,也就是多端引用一端的主键当作外键,多端自身拥有主键。 
        3、 多对多关系,多对多关系是通过中间表来实现的,中间表引用两表的主键当作联合主键,就可以实现多对多关联。 

J2ee | 评论:0 | Trackbacks:0 | 阅读:68 
07. Xml note 

Submitted by cnetsa on 2009, July 29, 2:22 PM 


XML(eXtensible Markup Language)是万维网联盟(World Wide Web Consortium W3C)定义的一种可扩展标志语言。 
    可扩展性指允许用户按照XML规则自定义标记(tags 标签)。 
强项:轻松表达多层结构的数据;可扩展。 
优点:平台无关,语言无关。设计目标是描述数据并集中于数据的内容,与显示分离。 
提醒:不能用XML来直接写网页。即便是包含了XML数据,依然要转换成HTML格式才能在浏览器上显示。 

语法规则: 
    XML文件有且仅有一个根标记,其他标记必须封装在根标记中,文件的标记必须形成树状结构。 
    大小写敏感。 
    标记的属性必须用""或''括起来。 

XML细节: 
一、 声明 
    大多数XML文档以XML声明作为开始,它向解析器提供了关于文档的基本信息。 
    建议使用XML声明,但它不是必需的。如果有的话,那么它一定是文档的第一行内容。 
      如:<?xml  version="1.0"  encoding="UTF-8" standalone="no"?> 
    声明最多可以包含三个名称-值对(许多人称它们为属性,尽管在技术上它们并不是)。 
      <?xml 问号与xml之间不能有空格。 
    1)version 是使用的XML 版本:1.0, 1.1 
    2)encoding 是该文档所使用的字符集。该声明中引用的ISO-8859-1 字符集包括大多数西欧语言用到的所有字符。 
      默认字符在UTF-8字符集中,这是一个几乎支持世界上所有语言的字符和象形文字的Unicode 标准。 
    3)standalone(可以是yes 或no)定义了是否孤立处理该文档。 
      如果XML文档没有引用任何其它文件,则可以指定 standalone="yes"。 
      如果XML文档引用其它描述该文档可以包含什么的文件(如DTD),则 standalone="no"。默认值为"no" 

二、 标记 
    左尖括号“<“和右尖括号“>“之间的文本 
      1. 在<  >中的称为开始标记;在</  >中的称为结束标记 
      2. 空标记:不包含元素的标记。空标签必须以“/>”结束。格式: <空标记的名称/> <空标记的名称 属性列表/> 
    注意: 
      除空标记外,标签必须成对:有始有终。所有的开始标签和结束标签必须匹配。 
      在标记符“<“和"标记的名称"之间不能含有空格。在标记符"/>"前面可以有空格或回行。 
      标签必须嵌套正确。 
    XML标记必须遵循下面的命名规则: 
     1.名字中可以包含字母、数字以及其它字母或文字;还可包含下划线(_)、点(.)、连字符(-) 
     2.名字不能以数字开头;可以用字母、文字或者下划线开头。 
     3.名字不能以字母xml (或XML 或Xml ..) 开头; 
     4.名字中不能包含空格。 

三、 元素 
    位于开始标记与结束标记间 
    一份文档有且只有一个根元素。 
    根元素下的所有元素叫“子元素”。 
    标签必须嵌套正确。 
    不包含自子元素的元素叫“叶子”;包含子元素的元素叫“分支”。 
    如: <eric>…… </eric> 

四、 属性 
    一个元素的开始标志中的名称-值对 
    所有的属性值必须位于单引号或双引号中。 
    每一个元素的属性不允许出现超过一次。 
    开始标志内,类似赋值语句 
    如:<eric age="80">……</eric> 

五、 注释 
    注释可以出现在文档的任何位置。(但不建议放在声明前面,部分浏览器会报错) 
    注释以 <!-- 开始,以 -->  结束。 
    注释内不能包含双连字符(--);除此之外,注释可以包含任何内容。 
    注释内的任何标记都被忽略 

六、 处理指令 
    处理指令是为使用一段特殊代码而设计的标记,简称为PI。 
    大多数XML 文档都是以XML 声明开始,该声明本身就是特殊的处理指令。 
    处理指令对应用程序特定的数据进行编码。一条处理指令包含一个目标,后跟数据。用<?和?>定界符将处理指令包起来。 
    目标确定应用程序,而对应用程序不能识别的目标,其会忽略这些处理指令。 

七、 实体 
    XML 规范预定义了五个实体。 
      &lt;   ==== < 
      &gt;   ==== > 
      &quot; ==== ” 
      &apos; ==== ‘ 
      &amp;  ==== & 
    自定义实体:在DTD中定义 <!ENTITY 实体标志 "实体内容"> 
      在xml中引用自定义实体,用  &实体标志;  代表实体内容。 
    另外,无法从键盘输入的字符可以使用字符引用,就是用字符的Unicode代码点来引用该字符。 
      以"&#x"开始字符引用,以分号结尾,x必须为小写,使用十六进制。如: &#x003D; 表示等于号。 
      也可以使用字符引用来引用 <,>,',",&  " 
      查看字符的代码点(附件-> 系统工具-> 字符映射表)。 

八、 CDATA 
    当一段文本中出现很多实体引用和字符引用时,会导致文本数据的读写困难,CDATA段就是为了解决这一问题引入的。 
    DATA区段开始于 "<![CDATA["  结束于  "]]>" 
    CDATA内部的所有东西都会被解析器忽略解析,不用检查它的格式。 
    但是CDATA段中不能嵌套另一个CDATA段。 

九、 属性 
    属性是标记的属性,可以为标记添加附加信息。 
    (1)属性的组成 
       属性是一个名值对,必须由名称和值组成,属性必须在标记的开始标记或空标记中声明,用"="为属性指定一个值。 
       语法如下: 
           <标记名称 属性列表/> 
           <标记名称 属性列表>XXX</标记名称> 
       例如: <桌子 width="40" height='100'/> 
    (2)使有属性的原则 
       属性不体现数据的结构,只是数据的附加信息; 
       一个信息是作为一个标记的属性或子标记,取决于具体问题,不要因为属性的频繁使用破坏XML的数据结构。 
       下面是一个结构清晰的XML文件: 
           <楼房 height="23m" width="12m"> 
               <结构>混凝土</结构> 
               <类别>商用</类别> 
           </楼房> 
      下面是一个结构不清晰的XML文件: 
          <楼房 height="23m" width="12m" 结构="混凝土" 建筑商="华海集团" 类别="商用"></楼房> 

十、 名称空间/包 
    XML文件允许自定义标记,所以可能出现同名字的标记,为了区分这些标记,就需要使用名称空间。 
    名称空间的目的是有效的区分相同的标记,其实并不真实存在。 
    语法: 声明有前缀的名称空间  xmlns:前缀名=名称空间的名字 
          声明无前缀的名称空间  xmlns=名称空间的名字  (缺省) 
    注意:当且仅当它们的名字相同时称二个名称空间相同,也就是说,对于有前缀的名称空间,如果二个名称空间的名字相同,即使前缀不相同,也是相同的名称空间,返之同然。前缀只是方便引用而已。 

基本术语 
    一、序言Prolog:包括XML声明(XML Declaration)和文档类型声明(Document Type Declaration)。 
    二、良构(well-formed 规范的):符合W3C定义的XML文档。 

验证 
    为什么需要验证? 
    对XML文件施加额外的约束,以便交流。 

一、DTD验证 
    文档类型定义(Document Type Definition) 
    DTD定义了XML文档内容的结构,保证XML以一致的格式存储数据。精确的定义词汇表,对XML的内容施加约束。 
    符合DTD的规范XML文档称为有效的文档。由DTD定义的词汇表以及文档语法,XML解析器可以检查XML文档内容的有效性。 
    规范的XML文件不一定是有效的;有效的一定是规范的。 

1、 DTD声明 
    1) DTD声明可以在单独的一个文件中 
    2) DTD声明可以内嵌在XML文件中 
    3) DTD声明可以一部分在单独的文件中,另一部分内嵌在XML文件中 

2、 引入外部DTD文件 
    <!DOCTYPE data SYSTEM "Client.dtd"> 
    Data:根节点名称 
    Client.dtd:dtd文件路径 

3、 DTD四种标记声明 
    元素(ELEMENT)、属性(ATTLIST)、实体(ENTITY)、符号(NOTATION) 

  1) 元素(ELEMENT) XML元素类型声明 
     声明元素: <!ELEMENT elementName (contentModel)> 
     元素的内容通过内容模式来描述。 
     DTD 内容模式的种类有: 
         EMPTY   元素不能包含任何数据,但可以有属性(前提是必须声明其属性)。 
                 不能有子元素。不能有文本数据(包括空白,换行符)。 
                 DTD中定义: <!ELEMENT elementName EMPTY> 
                 XML中:<elementName/>(推荐) 或者:<elementName></elementName> 
       (#PCDATA) 规定元素只包含已析的字符数据,而不包含任何类型的子元素的内容类型。 
                 DTD中定义: <!ELEMENT student (#PCDATA)> 
                 XML中合法内容: <student>watching TV</student> 
      (Elements) 元素由内容模式部件指定。 
                 <!ELEMENT  name  (child particles) > 
                 内容模式部件可以是下表列出的内容。 
                    <!ELEMENT name (a,b)>  子元素a、b必须出现,且按照列表的顺序 
                    <!ELEMENT name (a|b)>  选择;子元素a、b只能出现一个 
                    <!ELEMENT name (a)  >  子元素a只能且必须出现一次 
                    <!ELEMENT name (a)+ >  子元素a出现一次或多次 
                    <!ELEMENT name (a)* >  子元素a出现任意次(包括零次、一次及多次) 
                    <!ELEMENT name (a)? >  子元素a出现一次或不出现 
        Mixed    混合模式:子元素中既可有文本数据又可有下级子元素。 
                 <!ELEMENT rn (#PCDATA| an | en)*>“|”和“*”必须写。 
                 上句表示在 rn 内,字符数据 或 en及an 可以出现任意多次,顺序不限。 
                 优先写(#PCDATA)  如:(#PCDATA|name)* 正确   (name|#PCDATA)* 错误 
         ANY     元素可以包含任何类型的数据。子元素(必须在DTD中有定义) 和 文本数据(包括空白)。 
                 DTD中定义: <!ELEMENT a ANY> <!ELEMENT b ANY> 
                 XML中合法内容: <a>somngthing</a> 或者 <a/> 或者 <a><b>oo</b></a> 

   2) 属性(ATTLIST) 特定元素类型可设置的属性&属性的允许值声明 
        <!ATTLIST elementName 
        attributeName1 attributeType attributeDefault 
        ....... 
        attributeNameN attributeType attributeDefault> 
     属性类型 (Attribute Type): 
        CDATA该属性只能包含字符数据(注意与CDATA段、PCDATA的区别) 
        NMTOKEN  是CDATA的子集,它的字符只能是字母,数字,句点,破折号,下划线或冒号。 
        NMTOKENS 类似NMTOKEN,但这个可以包含多个值,每个值之间用空格隔开。 
        ID       该属性的取值在同一文档内是唯一的。一个元素只能有一个ID类型的属性。 
        IDREF    类似指针,指向文档中其他地方声明的ID值。如果该属性取值和指向的ID值不匹配,则返回错误。 
        IDREFS   类似IDREF,但它可以具有由空格分隔开的多个引用。 
        ENTITY   该属性的值必须对应一个在文档内部声明的但还没有分析过的实体。 
        ENTITYS  类似ENTITY,但它可以包含由空格分隔开的多个实体。 
        NOTATION 该属性的值必须引用在文档中其他地方声明的某个注释的名称。 
        (enumerated) 类似枚举的变量,该属性必须匹配所列的值。各值用“|”分隔开。 
                 如: (春|夏|秋|冬) 实际内容文档只能从中取一个。 
     属性特性 (Attribute Default) : 
        #REQUIRED   必须有且只能有一个属性。 
        #IMPLIED    可有可无。 
        #FIXED      在DTD中定义默认值,XML中可以不指定,指定则必须等于该默认值。 
        attribute-value 如果不指定则用DTD定义的默认值,指定则用指定的值。 

<![CDATA[############ 属性(ATTLIST)的举例 ############## ]]> 
例一(#REQUIRED) 
    DTD中: <!ELEMENT el (#PCDATA)> <!ATTLIST el at1 NMTOKENS #REQUIRED  at2 CDATA #REQUIRED> 
    XML中,正确: <el at1 = "10 20"   at2="10" >something</el> 
    XML中,错误: <el at="10">something</el>  (没有写另一个#REQUIRED的属性 at2 ) 

例二(#IMPLIED,#FIXED) 
    DTD中: <!ELEMENT el (#PCDATA)> <!ATTLIST el at CDATA #FIXED "10"  at2 CDATA #IMPLIED > 
    XML中,正确: <el   at2="20" >something</el> (at有默认值"10",at2 可写可不写) 
    XML中,错误: <el at="11" >something</el>(at要么不写,要写只能写成跟默认值相同的) 

例三(attribute-value) 
    DTD中:<!ELEMENT el (#PCDATA)> <!ATTLIST el at CDATA "10" at2 CDATA "20" > 
    XML中,正确: <el at="11" >something</el> 

例四(enumerated + attribute-value) 
    DTD中:<!ELEMENT el (#PCDATA)> <!ATTLIST el at (10|20|30) "10"> 
    XML中,正确: <el at="20">something</el>  (at要么不写,默认值 10;要么在(10|20|30)中选一个写) 
<![CDATA[############ 属性(ATTLIST)举例 完毕 ############## ]]> 

  3) 实体(ENTITY)   可重用的内容声明 
     在DTD中定义 <!ENTITY 实体标志 "实体内容"> 
     在xml中引用自定义的实体,用  &实体标志;  代表实体内容。 
      4) 符号(NOTATION) 不要解析的外部内容的格式声明。 
    

3、 内部实体:在xml文件里面写(少用) 
    外部实体:另外在xml同一文件夹下建立一个dtd文件(提倡) 
<!--**************** 内外部的实体举例 ***************** --> 
外部的: 
      <?xml  version="1.0"  encoding="UTF-8" standalone="no"?> 
      <!DOCTYPE root SYSTEM "goodsInfo.dtd"><!--用这句引用外部dtd--> 
      <root><goodsInfo> 
          <goodsName>goodsName</goodsName> 
          <goodsPrice>goodsPrice</goodsPrice> 
      </goodsInfo></root> 

      以下是名为"goodsInfo.dtd"文件 
      <!ELEMENT root   (goodsInfo)> 
      <!ELEMENT goodsInfo  (goodsName,goodsPrice)> 
      <!ELEMENT goodsName  (#PCDATA)> 
      <!ELEMENT goodsPrice (#PCDATA)> 

内部的: 
      <?xml  version="1.0"?> 
      <!DOCTYPE root [ 
          <!ELEMENT root(student)> 
          <!ELEMENT student (#PCDATA)> 
          <!ENTITY CCTV  "中央电视台"> 
      ]>  <!--把DTD文件写在体内--> 
      <root><student> 
          student watch &CCTV;<!--使用自定义实体 CCTV--> 
      </student></root> 
<!--***************** 内外部的实体举例 完毕 ********************** --> 


XML处理模式 
一、 DOM 文档对象模式 
    1.DOM特点: 
      以树型结构访问XML文档。 一棵DOM树包含全部元素节点和文本节点。可以前后遍历树中的每一个节点。 
      整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能。 
      将整个文档调入内存(包括无用的节点),浪费时间和空间。 
      一旦解析了文档还需多次访问这些数据;硬件资源充足(内存、CPU)情况下使用。 
    2.DOM树与节点 
      XML文档被解析成树型结构。 
      树由节点组成。共有12种不同的节点。 
      节点可以包含其他节点(依赖于节点的类型)。 
      父节点包含子节点。叶子节点没有子节点。 
    3.节点类型 
      Document node   包含:一个根Element节点。一个或多个处理指令节点。 
      Document Fragment node 
      Element node包含:其他Element节点。若干个Text节点。若干个Attribute节点。 
      Attribute node  包含:一个Text节点。 
      Text node 
      Comment node 
      Processing instruction node 
      Document type node 
      Entity node 
      Entity reference node 
      CDATA section node 
      Notation node 


二、 SAX 基于事件处理模式 
    解析器向一个事件处理程序发送事件,比如元素开始和元素结束,而事件处理器则处理该信息。 
    然后应用程序本身就能够处理该数据。原始的文档仍然保留完好无损。 

<![CDATA[################## SAX处理器(遍历XML) ###########################]]> 
import java.io.IOException; 

import javax.xml.parsers.ParserConfigurationException; 
import javax.xml.parsers.SAXParser; 
import javax.xml.parsers.SAXParserFactory; 

import org.xml.sax.Attributes; 
import org.xml.sax.SAXException; 
import org.xml.sax.SAXParseException; 
import org.xml.sax.helpers.DefaultHandler; 

public class TestSAXParser { 
    /** 基于SAX方式解析XML文档 */ 
    public static void main(String[] args) 
    throws SAXException,ParserConfigurationException,IOException{ 
        SAXParserFactory factory = SAXParserFactory.newInstance(); //创建SAX解析器工厂 
        factory.setValidating(true);                               //让error方法生效 
        SAXParser parser = factory.newSAXParser();                 //生成一个具体的SAX解析器 
        parser.parse("src/file/student.xml",new XMLreader());      //开始解析 
}} 

class XMLreader extends DefaultHandler { 
    // 只需覆盖我们感兴趣的方法 
    private int counter = 0;// 定义一个计数器,保存XML文档触发事件的次数 
  
    @Override   // 文档开始事件触发 
    public void startDocument() throws SAXException { 
        counter++; 
        System.out.println(counter + ".解析XML文件开始...");} 
   
    @Override  // 文档结束事件触发 
    public void endDocument() throws SAXException { 
    counter++; 
    System.out.println("\r\n"+counter + ".解析XML文件结束...");} 
   
    @Override  // 元素开始事件触发 
    public void startElement(String uri, String localName, String qName, 
    Attributes atts) throws SAXException { 
      counter++; 
      System.out.print(counter+".<"+qName); 
        for(int i=0; i<atts.getLength();i++){ //读取标志的所有属性 
          System.out.print(" "+atts.getLocalName(i)+"="+atts.getValue(i)); 
      }System.out.print(">"); } 
   
    @Override  // 元素结束事件触发 
    public void endElement(String uri, String localName, String qName) throws SAXException { 
        counter++; 
        System.out.print(counter +".</"+qName+">");} 
   
    @Override // 文本事件触发  打印时尽量不要换行,否则很难看 
    public void characters(char[] ch, int start, int length)throws SAXException { 
        counter++; 
        String text = new String(ch, start, length); // 当前元素的文本值 
        System.out.print(counter + ".Text=" + text);} 
   
    @Override //这是可恢复错误。需在SAXParserFactory设置有效性错误才能生效 
    public void error(SAXParseException e) throws SAXException { 
        System.out.println("xml文档有效性错误:"+e);} 
   
    @Override //严重错误 
    public void fatalError(SAXParseException e) throws SAXException { 
        System.out.println("xml文档严重的有效性错误:"+e);} 

<![CDATA[################## SAX处理器(遍历XML)结束 ###########################]]> 

三、 DOM 
<![CDATA[######################### DOM遍历方式 ###########################]]> 
import java.io.File; 
import java.io.IOException; 

import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.parsers.ParserConfigurationException; 

import org.w3c.dom.Attr; 
import org.w3c.dom.Document; 
import org.w3c.dom.Element; 
import org.w3c.dom.NamedNodeMap; 
import org.w3c.dom.Node; 
import org.w3c.dom.NodeList; 
import org.xml.sax.SAXException; 

/**基于DOM的解析XML文档*/ 
public class TestDOMParser { 
public static void main(String[] args) 
throws ParserConfigurationException,SAXException,IOException{ 
  //创建一个DOM解析器工厂 
  DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  
  //从工厂中生成一个DOM解析器; throws ParserConfigurationException 
  DocumentBuilder builder = factory.newDocumentBuilder();  
  //绑定需要解析的XML文件 
  File xmlFile = new File("src/file/student.xml");//相对地址,相对于这个工程  
  //开始解析 ;throws SAXException,IOException 
  Document document = builder.parse(xmlFile); 
  //取出唯一的根元素 
  Element rootElement = document.getDocumentElement(); 
        //调用业务方法: 遍历根元素 
  printElement(rootElement); 


/** 遍历元素,包含: 子元素、属性、文本内容 */ 
private static void printElement(Element e){ 
  //打印出元素的标签名 
  System.out.print("<"+e.getTagName()); 
  //获取开始标签的属性 
  NamedNodeMap attMap = e.getAttributes(); 
  //循环遍历所有的属性 
  for (int i=0;i<attMap.getLength();i++){ 
   Attr attr = (Attr)attMap.item(i); 
   System.out.print(" "+attr.getName()+"="+attr.getValue());} 
  System.out.print(">"); 
  
  //获取当前元素的所有子节点 
  NodeList nl = e.getChildNodes(); 
  for (int j=0;j<nl.getLength();j++){ 
   Node n = nl.item(j); 
   if (Node.ELEMENT_NODE==n.getNodeType()){ 
    printElement((Element)n);//递归调用,以遍历下一个元素 
   } else { 
    System.out.print(n.getTextContent()); 
   } 
  } 
  //打印结束标签 
  System.out.print("</"+e.getTagName()+">"); 
}} 
<![CDATA[ ###################### DOM遍历 完毕 ##########################]]> 

比较DOM与SAX: 
    DOM:处理大型文件时其性能下降的非常厉害。这个问题是由DOM的树结构所造成的,这种结构占用的内存较多,而且DOM必须在解析文件之前把整个文档装入内存,适合对XML的随机访问 
    优点:1.提供随机定义元素操作,来回移动指针 
         2.将整个XML文件一次性加载到内存,形成虚的内存树 
    缺点:1.如果XML文件较大,内存空间占用较大 
         2.强制将较大的XML文件加载到内存中,有可能损害文件 
         3.功能通用性 

    SAX:不同于DOM,SAX是事件驱动型的XML解析方式。它顺序逐行读取XML文件,不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束时,它会触发一个事件,用户通过在其回调事件中写入处理代码来处理XML文件,适合对XML的顺序访问 

J2ee | 评论:0 | Trackbacks:0 | 阅读:65 
06. OOAD & UML note 

Submitted by cnetsa on 2009, July 29, 2:21 PM 


day01: 
面向对象 
    通过封装、继承、多态,把程序的耦合度降低,使程序灵活、容易修改、容易复用。 
    面向对象=对象 + 类 + 消息 + 继承 + 多态 
    面向对象方法是一种把面向对象的思想运用于软件开发过程,指导开发活动的系统方法,包括分析、设计和实现等活动 

    软件开发组越大,组中每个成员的生产率就越低 
                    --Philippe Kahn, Borland 
       Ln = 15000/(n^-3)( LOC / year ) 
       构造大型软件不能靠堆人 

    敏捷开发: 
        1. 思路先行  //先用注释把思路记录下来 
        2. 实现随后 


  可维护性:预见需求(预见多年后的事) 
  可重用: 
          代码可重用(最低级别):粒度:方法(常用代码块),类,包,组件(类库) 
          设计的可重用:框架(半成品,如Hibernate);产品(开发软件);算法、设计模式 
          分析的可重用(最高级别,见不到代码):文档、规范、标准(ISO:CMM,CMMI) 
  可扩展性: 


UML图 
    类(class) 用矩形框表示,分三层 
        第一层:类名,抽象类用斜体字 
        第二层:类的特性:字段和属性 
        第三层:类的操作:方法或行为 
             方法前的符号:“+”表示public,“-”表示private,“#”表示protected 

    接口:右边的“飞翔” 
        顶端有<<interface>>,第一层是接口名字,第二层是方法 
    接口的另一种表示法:俗称棒棒糖表示法,就是类上面的一根棒棒糖(圆圈+实线) 
        圆圈旁为接口名称,接口方法在实现类中出现 

    继承:用空心三角+实线 
    实现接口:空心三角+虚线 


类与对象之间的关系(6种): 
    关联 Association:一个类受另一个类影响(实线) 
    聚合关联 Aggregation:弱'拥有'关系,A对象可以包含B对象,但B不是A的一部分(空心菱形+实线箭头)[DPE] 
        (DPE 表示这句话来自《设计模式》) 
    组合关联 Composition:(也叫合成,组成)是一种强的‘拥有’关系,体现严格的部分和整体的关系, 
        部分和整体的生命周期一样[DPE](实心菱形+实线箭头) 
      组合图形的基数:表明这一端的类可以有几个实例,(一只鸟有两个翅膀)如果有无数个实例,则用n表示 
        关联关系、聚合关系也可以有基数 
    依赖 Dependency :一个类需要另外一个类(X需要Y,则X的修改Y也要跟着修改) (虚线箭头) 
    泛化(继承) (实心菱形+实线) 
    实现  (实心菱形+虚线) 
   


UML 4+1 图 
    1:用例图    描述系统中有哪些用户可用的功能 
    4:逻辑图    将问题中的一些名词提取出来,形成系统中对应的类,表示之间的关系。 
       过程图    表示系统对象间的交互 
       实现图    系统中组件与组件之间交互 
       部署图    软件系统真实运行过程的物理描述 

静态(系统结构): 
        类图 
        对象图 
        构建图 
        部署图 
动态(系统行为): 
        顺序图    (时序图) 
        协作图 
        状态图 
        活动图 
        用例图 
   

day02: 
面向对象的7大基本设计原则 

程序设计:没有最好,只有最适合。寻找平衡点。 

1. LSP(The Liskov Substitution Principle ,替换原则) 
父类出现的地方,子类都可出现。 
子类或实现类与父类都是可以互换的。 
    子类不能添加任何父类没有的附加约束 
    子类对象必须可以替换父类对象 

2. OCP (The Open-Close Principle,开闭原则) 
要关联抽象,不要关联具体,抽象可扩展。 
    扩展是开放的,更改是封闭的 

3. SRP(The Single Responsibility Principle,单一职责原则) 
依赖不同的具体类,不要将不相关的方法放到一个具体类中,然后具体类再关联。 
    一个类,应该仅有一个引起它变化的原因 
    当需求变化时,该变化会反映为类的职责的变化(如果有多个职责,引起变化的原因就会有多个) 

4. ISP(The Interface Segregation Principle,接口隔离原则) 
具体类不要实现无关接口中的方法,应使用具体类实现多个接口。 
    避免肥接口,以一个类实现多个接口,而各客户仅仅获知必须的接口 
    本质: 
        使用多个专门的接口比使用单一的接口好 
        一个类对另一个类的依赖性应当最小化 
        避免接口污染(Interface Pollution)(使用不必要的功能) 

5. DIP(The Dependency Inversion Principle,依赖倒置原则) 
高层依赖于抽象,底层继承/实现于抽象。 
    高层模块不应该依赖于低层模块,二者都应该依赖于抽象 
    细节应该依赖于抽象,而抽象不应该依赖于细节 
    针对接口编程,不是针对实现编程 

6. CARP(Composite/Aggregate Reuse Principle,组合/聚合复用原则) 
尽量使用组合/聚合,而不是使用继承来达到复用目的 
    继承的缺点:会带来不必要的方法 
    组合/聚合的解决方案 
        组合:部分的更改会影响整体的生命 
        ***:部分的更改对整体的影响不大 

7. LoD(Law of Demeter,迪米特法则) 
类间最少通信原则,采用中间类。 
    也称最少知识原则。一个对象或模块应该和其它对象和模块尽量少的通信 

GoF(Gang of Fout) 23种经典设计模式 
        创建型                     结构型               行为型 
类   Factory Method 工厂方法     Adapter_Class       Interpreter 
                                                   Template Method 
对象 Abstract Factory 抽象工厂   Adapter_Object      Chain of Responsibility 
    Builder                    Bridge              Command 
    Prototype 原型              Composite           Iterator 
    Singleton 单例              Decorator 装饰       Mediator 
                               Facade              Memento 
                               Flyweight           Observer 
                               Proxy               State    状态 
                                                   Strategy 
                                                   Visitor 

单例模式: 
    当多个对象需要共享同一个对象时; 
原型模式: 
    对扩展开发,对修改关闭; 
工厂模式: 
    客户需要某个产品,能够根据客户要求取得产品给客户; 
状态模式: 
    当需要对某个对象内部状态改变时,使用; 
装饰模式: 
    当需要对某个对象动态添加新功能时,可以用; 
适配器模式: 
    只需要对接口中的一小部分方法重新定义,又不希望将接口中的所有方法实现, 
    这时可以使用; 
观察者模式: 
    当主题对象改变时,需要通知所有的观察者,这时可以使用; 
命令模式: 
    将用户发出命令以对象形式传递,通过参数可改变命令对象的状态; 

J2ee | 评论:0 | Trackbacks:0 | 阅读:66 
05. Core Java note 

Submitted by cnetsa on 2009, July 29, 2:21 PM 

sun考试:  SCJP:只考core java   SCJD:+jdbc+swing  
         SCWCD:+servlet+jsp(JAVA EE)   SCEA:+EJB+Webserver(架构师) 

必须养成优秀程序员的编写习惯:缩进(用空格)、注释、命名约定。 
大小写敏感。 
单独的“;”代表一条空语句。 
main函数是我们整个程序的执行入口所以必须是静态公开的。 
       必须写成这样:  public static void main(String[]args){...} 

生成jar包: 
    在eclipse里,选中要打包的几个文件,右键-Export-写文件名-Next-Next-选main方法的class-finish 
    在jar包的同一文件夹下,新建一个空文档,写“java -jar ./文件名.jar”,再把这文档改成“文件名.sh” 
    把这sh的属性-权限 改成“允许以程序执行文件”。以后双击这个sh即可运行 

文本注释 Comments: 
    注释必须写上,以便其他人阅读、引用和维护。 
    单行注释  //... 
    多行注释  /* ....*/ 
    文档注释  /** ... */ 
    文档注释,可以使用JDK的javadoc工具从原文件中抽取这种注释形成程序的帮助文档。 
    使用javadoc命令建立HTML格式的程序文档: 
     javadoc[options][packagenames][sourcefiles][@files] 

标示符: 
    用来给一个类、变量或方法命名的符号 
  标示符命名规则: 
    1. 以字母,“_”和“$”开头。可以包含字母、数字、“_”和“$”。 
    2. 大小写敏感 
    3. 不能与保留关键字冲突 
    4. 没有长度限制(暗示使用长的标示符,以便阅读。长名字可使用工具输入) 
    5. 建议使用JavaBeans规则命名,并根据方法的目的,以 set、get、is、add 或 remove 开头。 
  标示符命名约定: 
    1. 类名、接口名:每个单词的首字母应该大写,尤其第一个单词的首字母应该大写。(驼峰规则) 
        class  MyFirstClass 
        interface  Weapon 
    2. 字段、方法以及对象:第一个单词首字母应小写,其他单词首字母大写。(以便跟上面的有所区别) 
        boolean isWoman 
        void setName(String name) 
    3. 常量:全部用大写字母表示。如果由几个单词组成,则由下画线连接。 
        public final int  GREEN   
        public final int  HEAD_ COUNT 
    4. Java包(Package):全部用小写字母。 
        package  java.awt.event 


java.lang.System.gc();  /  java.lang.Runtime.gc(); 
    垃圾回收的建议语句,只能建议而不能强制回收 
    注意: System.gc(); 是静态方法,可直接调用。 
          java.lang.Runtime.gc(); 不是静态方法,不能直接在main方法里调用 

package 包 
    目的:命名冲突,便于管理类 
    运行时,先找到包所在目录,再执行“ 包名.类名” 
import 导入。导入包内的类 
    定义包之后,执行时:javac  -d 包的路径  类名.java 
                    java  包名.类名 
    import java.util.*; //表示导入java.util里面的所有类;但 import java.*; 则什么类都导不进 
    用“*”表示导入当前包的类,不包括子包的类(可把包看作目录)。 

声明规则 
    * 一个源代码文件最多只能有一个公共(public)类。 
    * 如果源文件包含公共类,则该文件名称应该与公共类名称相同。 
    * 一个文件只能有一个包语句,但是,可以有多个导入语句。 
    * 包语句(如果有的话)必须位于源文件的第一行。 
    * 导入语句(如果有的话)必须位于包之后,并且在类声明之前。 
    * 如果没有包语句,则导入语句必须是源文件最前面的语句。 
    * 包和导入语句应用于该文件中的所有类。 
    * 一个文件能够拥有多个非公共类。 
    * 没有公共类的文件没有任何命名限制。 

输入:使用Scanner 获取输入 
    在J2SE 5.0中
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值