一.JDBC原理概述
1,JDBC是一套协议,是JAVA开发人员和数据库厂商达成的协议,也就是由Sun定义一组接口,由数据库厂商来实现,并规定了JAVA开发人员访问数据库所使用的方法的调用规范。
2,JDBC的实现是由数据库厂商提供,以驱动程序形式提供。
3,JDBC在使用前要先加载驱动。
JDBC对于使用者要有一致性,对不同的数据库其使用方法都是相同的。
driver开发必须要实现Driver接口。
四种数据库驱动的实现方式
JDBC-ODBC桥接式
JDBC网络驱动,这种方式是通过中间服务器的协议转换来实现的
JDBC+本地驱动,这种方式的安全性比较差
JDBC驱动,由数据库厂商实现。
二.JDBC的API
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结果ResultSet(select语句)
6,关闭sql结果ResultSet (如果有)
7,关闭Statement
8,关闭连接Connection
注意:6,7,8两个步骤必须要做的,因为这些资源是不会自动释放的,必须要自己关闭
1,注册加载驱动driver,也就是强制类加载
一般来说我们使用方法1
方法1) Class.forName(Driver包名.Driver类名)。
eg:加载oracle
Class.forName("oracle.jdbc.driver.OracleDriver");
方法2)Driver d=new oracle.jdbc.driver.OracleDriver();
DriverManager.registerDriver(d);
方法3)java -Djdbc.drivers=驱动全名 类名
Oracle的Driver的全名:oracle.jdbc.driver.OracleDriver
mysql的Driver的全名:com.mysql.jdbc.Driver 或 org.gjt.mm.mysql.Driver
SQLServer的Driver的全名:com.microsoft.jdbc.sqlserver.SQLServerDriver
2,创建连接
DriverManager.getConnection(String url,String username,String
password);
Connection连接是通过DriverManager的静态方法getConnection(.....)来得到
的,这个方法的实质是把参数传到实际的Driver中的connect()方法中来获得数
据库连接的。
Oracle的URL值是由连接数据库的协议和数据库的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地址用localhost和127.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”);
2)executeUpdate(String sql) 方法用于执行DDL和DML语句,可以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”);
3)execute(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();
}
4)getUpdateCount() 返回更新的记录条数
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");
4)updateXXX() XXX代表的是相应的类型,无返回值
5) isXXXX() XXXX代表的是游标的位置First,Last。。。返回布尔值
5.资源的关闭顺序:
要按先ResultSet结果集,然后Statement,最后Connection的顺序关闭资源。
因为Statement和ResultSet是需要连接是才可以使用的,所以在使用结束之后
有可能起他的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 对象的id,sequence只有Oracle才可用,对象id(OID)使用高低位算法先生成高位,在生成低位,通过运算获得对象id。
类应当对象到表,属性对应字段,对象对应记录。
类继承关系对应表,
1,每个类建一个表,为父子类每个类都对应的创建表,这种方法类关系清晰,但是如果类比较多就不适合了
2,只有具体类才建表,也就是把父类中的属性均匀分配到子类的表中,也就是父类不建表,这种表关系不能使用多态
3,所有类对应一张表,这种方法是在表中加上一个字段来区分父子类,但是只能用于类属性较少的情况下,而且数据会有冗余。
类关联关系对应表
1,一对一关联,类关系对应成表时有两种做法,一是引用主键,也就是一方引用另一方的主键既作为外键又作为自身的主键。
二是外键引用,一方引用另一方的主键作为自身的外键,并且自己拥有主键。
2,一对多关联,也就是多端引用一端的主键当作外键,多端自身拥有主键。
3,多对多关系,多对多关系是通过中间表来实现的,中间表引用两表的主键当作联合主键,就可以实现多对多关联。
posted on 2009-03-31 19:41
faye 阅读(700)
评论(0) 编辑 收藏