posts - 5,  comments - 0,  trackbacks - 0
 

一.JDBC原理概述

1JDBC是一套协议,是JAVA开发人员和数据库厂商达成的协议,也就是由Sun定义一组接口,由数据库厂商来实现,并规定了JAVA开发人员访问数据库所使用的方法的调用规范。

      2JDBC的实现是由数据库厂商提供,以驱动程序形式提供。

      3JDBC在使用前要先加载驱动。

         JDBC对于使用者要有一致性,对不同的数据库其使用方法都是相同的。

         driver开发必须要实现Driver接口。

      四种数据库驱动的实现方式

      JDBC-ODBC桥接式

      JDBC网络驱动,这种方式是通过中间服务器的协议转换来实现的

      JDBC+本地驱动,这种方式的安全性比较差

      JDBC驱动,由数据库厂商实现。

 

二.JDBCAPI

      java.sql包和javax.sql

      1.Driver接口 代表驱动程序

2.DriverManager类(驱动管理器),它可以创建连接,它本身就是一个创建Connection的工厂(Factory)

      3.Connection接口,代表数据库连接,会根据不同的驱动产生不同的连接

      4.Statement接口,执行sql语句

      5. PreparedStatement接口执行sql语句(预编译)

      6.CallableStatement接口 发送sql语句

      7.ResultSet接口(结果集),是用来接收select语句返回的查寻结果的。其实质类似

于集合。

      8.DatabaseMetaData  数据库元数据

      9.ResultSetMetaData   结果集元数据

10.Types:特殊的类。只包含静态的常量,代表JDBC类型。JDBC类型是标准SQL类型的子集

三、事务

      1).原子性,一致性,隔离性,持久性

事务是一个数据操作单元,能够保证在该单元内执行的多个SQL语句,或者一起成

,或者一起失败.

      2).事务的并发控制:

          (dirty)脏读:一个事务能读到另外一个事务没有提交的数据

          不可重复读:在同一个事务的两次查询中,发现值不同,叫做不可重复读.这是因为在

两次查询之间,另外一个事务修改了数据并提交了.

          (phantom)幻影读:在同一个事务的两次查询中,发现记录的数目不同,叫做幻影读.

这是因为在两次查询之间,另外一个事务增加或者删除了数据并提交了.

      3).隔离级别

         Connection 类中的五个静态常量

         A.不使用事务 TRANSACTION_NONE

       B.允许脏读    TRANSACTION_READ_UNCOMMITTED

         C.不允许脏读  TRANSACTION_READ_COMMITTED

         D.防止不可重复读,脏读 TRANSACTION_REPEATABLE_READ

         F.事务串行化  TRANSACTION_SERIALIZABLE

四、JDBC编程步骤

      1,注册加载一个driver驱动

      2,创建数据库连接(Connection

      3,创建一个Statement(发送sql

      4,执行sql语句

      5,处理sql结果ResultSetselect语句)

      6,关闭sql结果ResultSet (如果有)

      7,关闭Statement

      8,关闭连接Connection

      注意:678两个步骤必须要做的,因为这些资源是不会自动释放的,必须要自己关闭

 

      1,注册加载驱动driver,也就是强制类加载

           一般来说我们使用方法1

           方法1 Class.forName(Driver包名.Driver类名)

                 eg:加载oracle

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

           方法2Driver d=new oracle.jdbc.driver.OracleDriver();

                 DriverManager.registerDriver(d);

           方法3java -Djdbc.drivers=驱动全名 类名

 

           OracleDriver的全名:oracle.jdbc.driver.OracleDriver

           mysqlDriver的全名:com.mysql.jdbc.Driver org.gjt.mm.mysql.Driver

           SQLServerDriver的全名:com.microsoft.jdbc.sqlserver.SQLServerDriver

      2,创建连接

           DriverManager.getConnection(String url,String username,String

password);

           Connection连接是通过DriverManager的静态方法getConnection(.....)来得到

的,这个方法的实质是把参数传到实际的Driver中的connect()方法中来获得数

据库连接的。

      OracleURL值是由连接数据库的协议和数据库的IP地址及端口号还有要连接的

库名(DatebaseName

           Oracle URL的格式

           jdbc:oracle:thin:@数据库IP地址:端口号:数据库名(sid)

           如:oracle所在服务器地址为192.168.0.254,而端口号为默认的1521,数据

库名为tarena,那么URL就应写成

           jdbc:oracle:thin:@192.168.0.254:1521:tarena       

           MySql URL的格式

           jdbc:mysql://数据库IP地址:端口号/数据库名

           例: jdbc:mysql://localhost:3306/test

           访问本机时IP地址用localhost127.0.0.1都可以         

           SQLServer URL的写法

           例:jdbc:microsoft:sqlserver://localhost:1433

      3、创建Statement

           使用Connection对象获得一个Statement

           Statement中的方法:

1) executeQuery(String sql) 方法可以使用select语句查询,并且返回一个结

果集ResultSet,通过遍历这个ResultSet,可以获得select语句的查寻结果。

           ResultSet rs = stmt.executeQuery(“select * from person”);

           2executeUpdate(String sql) 方法用于执行DDLDML语句,可以update

delete操作。

           此方法返回一个int类型的值,表示此条sql语句影响的记录条数

           Int count = stmt.executeUpdate(“delete from person where pid=1”);

           Int count = stmt.executeUpdate(“update person set name=’jack’,age=’20’

where pid=1”);

           3execute(String sql) 这个方法的返回值是boolean类型

           如果返回true就表示sql是一个select语句,然后通过getResultSet()获得结果

           如果返回false sql就是DML语句或者是DDL语句,即没有结果集,

           然后通过getUpdateCount()方法 获得更新的记录条数。

           在不能明确传入sql是何种类型的操作时使用此方法。

           if (stmt.execute(sql)) {

                 ResultSet rs = stmt.getResultSet();

           } else {

                 int count = stmt.getUpdateCount();

           }

           4getUpdateCount() 返回更新的记录条数

      4.处理结果集ResultSet(结果集里存储的是二维的结构,相当于一张表)

           ResultSet rs = stmt.executeQuery(“select pid, name, age from person”);

           Person person = null;

           while(rs.next) {

                 person = new Person();

                 person.setPid(rs.getInt(1));//jdbc下标是从1开始

                 person.setName(rs.getString(“name”));//也可使用列名来得到数据

                 person.setAge(rs.getInt(3));

           }

           1) next()方法会操作一个游标从第一条记录的前边开始读取,直到最后一条记录。

                 由于结果集返回来之后游标的位置在第一条记录的前面,所以调用next()

法不会丢失数据。

           2) getXXX(int index)其中XXX代表数据库中存储的数据类型相对应的java数据

类型,

                 此方法可以根据指定顺序获得字段值,注:顺序是从1开始的。

            eg: int cid = rs.getInt(1);

                 String cname = rs.getString(2);

           3) getXXX(String columnName):此方法可以根据指定字段的名字获取字段的值

                 eg: int cid = rs.getInt("cid");

                 String cname = rs.getString("cname");

           4updateXXX() XXX代表的是相应的类型,无返回值

           5)  isXXXX() XXXX代表的是游标的位置FirstLast。。。返回布尔值

      5.资源的关闭顺序:

           要按先ResultSet结果集,然后Statement,最后Connection的顺序关闭资源。

           因为StatementResultSet是需要连接是才可以使用的,所以在使用结束之后

有可能起他的Statement还需要连接,

           所以不能现关闭Connection

           //关闭结果集

           if (rs != null) try {rs.close()} catch (SQLException e) { e.printStackTrace();}

           //关闭Statement

           if (stmt != null) try { stmt.close()} catch (SQLException e) {

e.printStackTrace();}

           //关闭链接

           if (conn != null) try { conn.close()} catch (SQLException e) {

e.printStackTrace();}

      6.PreparedStatement(预编译的Statement)

           PreparedStatement 用来执行同构的SQL,它的创建方式:

           PreparedStatement pstmt = con.prepareStatement("insert into clazz values(?,?)");

           可以使用参数替代sql语句中的某些参数使用"?"代替,他先将带参数的sql语句发送到数据库,

           进行编译,然后PreparedStatement会将参数发送给数据库。

           在使用PreparedStatement时,设置相应参数要指明参数的位置和类型,以及给出参数值

           根据不同的参数类型使用不同的setXXX(参数的位置,参数值)来设置参数

           结构跟此方法类似:setInt(int parameterIndex, int x)

           pstmt.setInt(1,i);

           pstmt.setString(2,"xxx"+i)

      7.CallableStatement

           CallableStatement是可以用非sql语句来访问数据库,他是通过调用存储过程(PL/SQL)来访问数据

库的。

           可以直接使用连接来调用 prepareCall(...)方法,来执行这个存储过程,"..."是存储过程的名字。

      8.SQLException是检查异常必须处理,要么throws ,要么try{}catch(){}

         getErrorCode()可以获得错误码,可以对错误进行查询。

五、元数据

      元数据就是描述数据库或其组成部分的数据。(区别于存储在数据库中的实际数据)

      它用来辅助我们更好的处理数据库的用户数据[通俗的讲就是指容器的结果的信息]

JDBC中有两种元数据,一种是数据库元数据(DatabaseMetaData,另一种是结果集元数据(ResultSetMetaData

      1.数据库元数据

           如果要想了解数据库的更多信息。可以从数据库连接中获取一个DatabaseMetaData

           DatabaseMetaData  dmd=conn.getMetaData();

           然后可以调用如下的方法获得数据库相关的信息

           getURL(),获得连接数据库的URL

           getDatabaseProductName() 获得数据库产品的名称

           getDriverVersion() 获得JDBC驱动程序的String形式的版本号

           getTables()获得数据库中该用户的所有表

           getUserName() 获得数据库用户名。

      2.结果集元数据

           ResultSet rs=ps.executeQuery();

           ResultSetMetaData m=rs.getMetaData();

           getColumnCount(),获得实际列数

           getColumnName(int colnum),获得指定列的列名

           getColumnType(int colnum),获得指定列的数据类型

           getColumnTypeName(int colnum),获得指定列的数据类型名

      例如:ResultSetMetaData md = rs.getMetaData();

                      // 得到字段个数

                      int cols = md.getColumnCount();

                      // 根据字段个数遍历和打印结果集

                      StringBuffer sb = new StringBuffer();

                      for (int i = 0; i < cols; i++) {

                            sb.append(md.getColumnName(i + 1) + " ");

                      }

           动态获得表结构

 

六、JDBC2.0新特性

      默认方式获得的结果集都是1.0的结果集

      能否使用JDBC2.0 ResultSet的新特性要看数据库驱动程序是否支持。

      1.可滚动结果集(可双向滚动),(了解 能说出结果集滚动的方法即可)

           这种结果集不但可以双向滚动,相对定位,绝对定位,并且可以修改数据信息。

           要使用可滚动结果集时,要在Statement创建时指定参数,才可以使用

           Statement st=null;int,int(可滚动特性,可更新特性)

           st=con.createStatement(ReusltSet.TYPE_SCROLL_INSENSITIVE,ResuleSet.CONCUR_UPDATABLE) 

           PreparedStatement

ps=con.createPrepareStatement(sql,ReusltSet.TYPE_SCROLL_INSENSITIVE,ResuleSet.CONCUR_

UPDATABLE);

           ResultSet rs=ps.executeQuery(sql);

      滚动特性

           next(),此方法是使游标向下一条记录移动。

            previous() ,此方法可以使游标向上一条记录移动,前提前面还有记录。

           absolute(int row),绝对定位函数可以使用此方法跳到指定的记录位置。定位成功返回true,不成功返

false,返回值为false,则游标不会移动。

           afterLast() ,游标跳到最后一条记录 之后,(结果集一回来时就有的位置)。无返回值。

           beforeFirst() ,游标跳到第一条记录 之前,(结果集一回来时就有的位置)。(跳到游标初始位)无返回

           first(),游标指向第一条记录。

           last(),有彪指向最后一条记录。

           relative(int rows),相对定位方法,参数值可正可负,参数为正,

           游标从当前位置向下移动指定值,参数为负,游标从当前位置向上移动指定值。

      ResultSet可滚动性的属性值:

           TYPE_FORWARD_ONLY ,单向,该常量指示指针只能向前移动的 ResultSet 对象的类型。不可滚动。

           TYPE_SCROLL_INSENSITIVE ,双向,对数据库的变化不敏感

           TYPE_SCROLL_SENSITIVE ,双向,对数据库的变化敏感

           ResultSet 对象的类型。该特性某些数据库不支持。

      ResultSet可更新性的属性值: 

           CUNCUR_READ_ONLY,不可更新的结果集

           CUNCUR_UPDATEABLE,可更新的结果集

      2.可更新的结果集:(不常用,也不推荐使用)(了解)

           如果你想能够编辑结果集中的数据,并且将结果集上的数据自动反应到数据库中,

           那么就必须使用可更新的结果集,可更新结果集不一定是可滚动的,获得可更新结果集的方法:

      Statement  

stat=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATE

ABLE);

           这样,调用executeQuery()方法返回的结果集就是可更新的结果集。

      例如:

           String  query="SELECT *  FROM  books";

           ResultSet  rs=stat.executeQuery(query);

           While(rs.next){

                 If(.......){

                          Double inscrease=.......;

                          Double  price=rs.getDouble("Price");

                           rs.updateDouble("Price",price+inscrease);

                           rs.updateRow();

               }

           }

所有的对应于SQL类型的数据类型都配有updateXXX方法。与getXXX方法类似。使用updateXXX方法是必须指定列的名称或序列号。

      然后,可以给 该字段设置新的值。

      updateXXX方法改变的只是结果集中的行值,而非数据库中的值。当更新完行中的字段值后,必须调用

updateRow方法,这个方法将当前的行中所有更新信息发送给数据库。如果没有调用updateRow方法就将

游标移动到其他行上。那么所以的更新信息就将被丢弃,而且永远不会被传递给数据库。还可以调用cancelRowUpates方法来取消对当前行的更新。

      以上是更新数据库中的一行记录,如果想在数据库中添加一条新的记录,首先需要使用moveToInsertRow

()方法将游标移动到特定的位置。然后调用updateXXX()方法在插入行的位置上创建一个新的行。然后调用

insertRow()方法将新建的行发送给数据库。完成插入操作后在调用moveToCurrentRow()方法讲游标移回到调用moveToInsertRow方法之前的位置:

      例子:

           rs.moveToInsertRow();

           rs.updateString("Title",title);

           rs.updateString("Price",price);

           ..........

           rs.insertRow();

           rs.moveToCurrentRow();

      如果要删除一行调用rs.deleteRow()即可删除结果集和数据库中的一行

      能否使用可更新结果集,要看使用的数据库驱动是否支持,还有只能用于单表且表中有主键字段(可能会是

联合主键),不能够有表连接,会取所有非空字段且没有默认值。结果集用select * from t也不行,不能用

*,不能排序

      3,批处理更新 (熟记于心)

           Statement.

           addBatch(String sql) 方法会在批处理缓存中加入一条sql语句

           executeBatch() ,执行批处理缓存中的所有sql语句。

           PreparedStatement.   先准备一组参数

           addBatch() 将一组参数添加到此 PreparedStatement 对象的批处理命令中。

           executeBatch() 将一批命令提交给数据库来执行,如果全部命令执行成功,则返回更新计数组成的数组。

           PreparedStatement中使用批量更新时,要先设置好参数后使用addBatch()方法加入缓存。

           注意:批量更新中用更新或插入语句

面向对象的数据库设计

 

Id通常是用来表示记录的唯一性的,通常会使用业务无关的数字类型

Object id 对象的idsequence只有Oracle才可用,对象idOID)使用高低位算法先生成高位,在生成低位,通过运算获得对象id

类应当对象到表,属性对应字段,对象对应记录。

 

类继承关系对应表,

1,每个类建一个表,为父子类每个类都对应的创建表,这种方法类关系清晰,但是如果类比较多就不适合了

2,只有具体类才建表,也就是把父类中的属性均匀分配到子类的表中,也就是父类不建表,这种表关系不能使用多态

3,所有类对应一张表,这种方法是在表中加上一个字段来区分父子类,但是只能用于类属性较少的情况下,而且数据会有冗余。

 

类关联关系对应表

1,一对一关联,类关系对应成表时有两种做法,一是引用主键,也就是一方引用另一方的主键既作为外键又作为自身的主键。

      二是外键引用,一方引用另一方的主键作为自身的外键,并且自己拥有主键。

2,一对多关联,也就是多端引用一端的主键当作外键,多端自身拥有主键。

3,多对多关系,多对多关系是通过中间表来实现的,中间表引用两表的主键当作联合主键,就可以实现多对多关联。

 

 

posted on 2009-03-31 19:41 faye 阅读(700) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航: