JDBC 学习笔记3
在上次的学习笔记中主要说明了一下JDBC的是如何获取DIRVER的的工作原理,以及简单的介绍了一下六个步骤。今天的笔记主要内容是[JDBC Advanced Topics]异常处理、元数据以及事务。
1、异常 Exception
java.sql.SQLException 对底层数据库异常的封装,它是一个已检查异常。所以应用程序必须对它做处理。
.getErrorCode(); 获取特定于数据库供应商的错误代码。
java.sql.SQLWaring extends SQLExecption 提供关于数据库访问警告信息的异常。
例:
1
try
{
2//此处省略
3} catch (SQLException e) {
4 while(e != null){
5 e.printStackTrace();
6 e = e.getNextExecption();
7 }
8}
2//此处省略
3} catch (SQLException e) {
4 while(e != null){
5 e.printStackTrace();
6 e = e.getNextExecption();
7 }
8}
2、元数据:用来描述其他数据的数据
JDBC中的元数据:
ResultSetMetaDate: 结果集元数据,它用来描述结果集本身。
ResultSet.getMetaDate(); 获取当前结果集的元数据。
DatabaseMetaDate: 数据库元数据,用来描述数据库本身。
Connection.getMetaDate(); 获取当前数据库的元数据。
例:
//
利用元数据打印出结果集
public void executeSQL(String sqlcommand) {
Connection con = null;
Statement stm = null;
ResultSet rs = null;
try{
//这里的ConnectionFactory是写的一个连接工厂,这里就不做介绍了。
con = ConnectionFactory.getConnection();
stm = con.createStatement();
boolean flag = stm.execute(sqlcommand);
if(flag){
rs = stm.getResultSet();
ResultSetMetaDate rsmd = rs.getMetaDate();
int columns = rsmd.getColumnCount();
for(int i=1;i<columns;i++){
String columnName = rsmd.getColumnLabel(i);
System.out.print(columnName+"\t");
}
System.out.println();
while(rs.next()){
for(int i=1;i<columns;i++){
Object content = rs.getObject(i);
System.out.print(content+"\t");
}
System.out.print();
}else{
int results = stm.getUpdateCount();
System.out.println(results+" resultes was update ");
}
}
}catch(SQLExecption e){
//此处省略若干
}
}
public void executeSQL(String sqlcommand) {
Connection con = null;
Statement stm = null;
ResultSet rs = null;
try{
//这里的ConnectionFactory是写的一个连接工厂,这里就不做介绍了。
con = ConnectionFactory.getConnection();
stm = con.createStatement();
boolean flag = stm.execute(sqlcommand);
if(flag){
rs = stm.getResultSet();
ResultSetMetaDate rsmd = rs.getMetaDate();
int columns = rsmd.getColumnCount();
for(int i=1;i<columns;i++){
String columnName = rsmd.getColumnLabel(i);
System.out.print(columnName+"\t");
}
System.out.println();
while(rs.next()){
for(int i=1;i<columns;i++){
Object content = rs.getObject(i);
System.out.print(content+"\t");
}
System.out.print();
}else{
int results = stm.getUpdateCount();
System.out.println(results+" resultes was update ");
}
}
}catch(SQLExecption e){
//此处省略若干
}
}
3、DML的操作 [JDBC的事务] 以事务为单位
JDBC事务:
定义:一组相关的操作,不可分割,一起成功,一起失败。
相关操作:
Connection:
commit(); JDBC事务提交
rollback(); JDBC事务回滚
JDBC的事务默认情况下是自动提交的,每执行一次SQL命令,就提交commit一次。[AutoCommit]
如:
转帐(){
...
update t_account1 set balance = balance-100;
update t_account2 set balance = balance+100;
...
}
如何让以上两句SQL语句,一起执行,一起失败。所以就需要把他们放在一个事务中。
如:
转帐(){
...
con.setAutoCommit(false);//关闭自动事务提交
update t_account1 set balance = balance-100;
update t_account2 set balance = balance+100;
如果以上两句都成功,则:
con.commit();//提交事务
如果以上任意一个失败,则:
con.rollback();//事务回滚
}
获取主键方式(主键值生成策略)
主键值不应该由UI界面来收集,而应该由应用程序自动生成,常见的策略如下:
a. max(id)方法
select max(id) from table_name;
此方法当有多线程并发时,就会产生问题。
b. sequence 序列
select sequence.nextval from dual;
此方法只适用支持序列的数据库产品,所以不是很通用。
c. 维护单行单列得表
1
create
table
id_table(next_id
number
not
null
);
2 insert into id_table next_id values ( 1 );
3 commit ;
4 -- 使用以下SQL自动维护
5 select next_id from id_table for update ;
6 update id_table set next_id = next_id + 1 ;
7 commit ;
2 insert into id_table next_id values ( 1 );
3 commit ;
4 -- 使用以下SQL自动维护
5 select next_id from id_table for update ;
6 update id_table set next_id = next_id + 1 ;
7 commit ;
并发控制:多个事务同时操作同一个对象
有三种并发情况,如下:
1、脏读 Dirty reads 读到其他事务没有提交的数据。注:Oracle不支持
2、不可重复读 Repeatable reads 同一个事务在两个不同的时刻读取不同结果
如:
1
T1:
select
score
from
t_score
where
id
=
48
;
2 T2: update t_score set score = score + 10 where id = 48 ;
3 T1: select score from t_score where id = 48 ;
解决重复读问题:
2 T2: update t_score set score = score + 10 where id = 48 ;
3 T1: select score from t_score where id = 48 ;
让T1在查询语句中加入for update子句,从而把选定的记录加上排他锁;那么T1事务完成之前,其他事务是不能来获取锁资源的。
3、幻影读 Phanton reads 记录数量变化,而不是行记录的列值
1
T1:elcet
count
(
*
)
from
t_class
where
classname
=
'
******
'
;
2 T2:nsert into t_class values (.);
3 commit ();
4 T1:selcet count ( * ) from t_class where classname = ' ****** ' ;
5
解决幻影读问题:
2 T2:nsert into t_class values (.);
3 commit ();
4 T1:selcet count ( * ) from t_class where classname = ' ****** ' ;
5
锁表:lock table table_name in mode;
事务隔离级别:SUN在JDBC规范中制定了5个级别,分别用来满足不同的并发性。
Connection:
0 .TRANSACTION_NONE 无
1 .TRANSACTION_READ_UNCOMMITED 可以脏读
2 .TRANSACTION_READ_COMMITED 不可以脏读
4 .TRANSACTION_REPEATABLE 不可以重复读
8 .TRANSACTION_SERIALIZABLE 为每个事务都开辟一个空间
事务的隔离界别设置得越高,则并发性能越差
注:不同数据库,对隔离级别的支持也是不一样的。
如:oracle就不支持0和1两种。
如何设置隔离级别?
如:con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITED);
这个也是默认事务隔离级别。
My Java study notes.