1.执行JDBC 执行SQL的整体流程:
① 加载驱动:Class.forName(“……”)//注意tty…catch
② 获取连接:DriverManager.getConnection(url,psw,psw);
③ 创建Statement/PreparedStatement:con.createStatement();或者con.prepareStatement(sql,…,…);
④ 执行SQL语句: (PreparedStatement )pret.setString(index,value);pret.executeQuery();pret.executeUpdate(); (Statement)stmt.executeUpdate(sql)/stmt.executeQuery(sql);
⑤ 如果是Query,返回结果集Result,对结果集进行处理,如果是Update,返回SQL语句影响数据条数。
⑥ 关闭连接释放资源。
2.对Connection的处理:
主要有三个:
① 设置自动提交:con.setAutoCommit(false);
② 提交:con.commit();
③ 回滚:con.rollback();
④ 关闭:con.close();
3.对Statement的处理:
主要有三种处理:查询、修改(增删改)、批处理:
查询:
stmt.executeQuery(sql);//sql为SQL语句
修改:
stmt.executeUpdate(sql);//sql为SQL语句
批处理:
stmt.addBatch(sql);//sql为单条SQL语句
stmt.executeBatch();
注意:Statement使用完后需要关闭:stmt.close();
4.对PreparedStatement的处理
PreparedStatement运行的速度比Statement快,使用方式也比Statement繁琐。网上有评论说稍微有点经验的程序员都应该不使用Statement而使用PreparedStatement。
首先从PreparedStatement的创建讲起:
PreparedStatement的创建主要有两种方式:
prepareStatement(String sql) sql通常是由占位符‘?’的sql语句
prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
resultSetType是结果集类型,
static int TYPE_FORWARD_ONLY
The constant indicating the type for a ResultSet object whose cursor may move only forward.
static int TYPE_SCROLL_INSENSITIVE
The constant indicating the type for a ResultSet object that is scrollable but generally not sensitive to changes to the data that underlies the ResultSet.
static int TYPE_SCROLL_SENSITIVE
The constant indicating the type for a ResultSet object that is scrollable and generally sensitive to changes to the data that underlies the ResultSet.
1.TYPE_FORWORD_ONLY,只可向前滚动;
2.TYPE_SCROLL_INSENSITIVE,双向滚动,但不及时更新,就是如果数据库里的数据修改过,并不在ResultSet中反应出来。
3.TYPE_SCROLL_SENSITIVE,双向滚动,并及时跟踪数据库的更新,以便更改ResultSet中的数据。
resultSetConcurrency:结果集并发性。
static int CONCUR_READ_ONLY
The constant indicating the concurrency mode for a ResultSet object that may NOT be updated.
static int CONCUR_UPDATABLE
The constant indicating the concurrency mode for a ResultSet object that may be updated.
设置对象:
设置普通对象:
在SQL语句中,一些对象都可以转化成字符串的形式,如 int(一类)、char(一类),处理这些数据的时候就可以笼统得写作:pret.setString(index,(String)value);
设置空值:
pret.setNull(index,type);//type为类型的Type,记录在java.sql.Types里面
设置大对象:
pret.setBlob(int parameterIndex, Blob x) ;//并不常用
pret.setBlob(int parameterIndex, InputStream inputStream, long length);//联系中使用的是这种方式具体情况: pret.setBlob(index,new FileInputStream(new file(filename)),new File(filename).length);
读取Blob:
Blob b = (Blob)rs.getBlob(index);
InputStream fin = b.getBinaryStream();
FileOutputStream fout = new FileOutputStream(f);
int by ;
while((by=fin.read())!=-1){
fout.write(by);
}
fout.close();
fin.close();
从上面的代码中可以看出,Blob是字节流对象,查看Blob时需要将Blob写到本地磁盘上,之后才能进行下一步处理
setClob(int parameterIndex, Clob x) ;
setClob(int parameterIndex, Reader reader, long length) ;
从形式上看,设置Clob对象的方式与设置Blob对象的方式基本相同,唯一不同的就是,Blob是字节流(Binary Large OBjects),Clob是字符流(Character Large OBjects),因为Clob是字符流,所以在查询的过程中也会将Clob当做字符串来处理。参考如下代码:(注: POSSTR(arg1,arg2)的含义是找出arg2在arg1中出现的位置)
public static void main(String[] args) throws Exception{
final String url = “jdbc:db2:sample”;
final String user = “db2admin”;
final String psw = “db2admin”;
Connection con = DriverManager.getConnection(url,user,psw);
String resume = null;
String empnum = “000130”;
int startper=0, startper1, startdpt = 0;
PreparedStatement stmt1, stmt2, stmt3 = null;
String sql1, sql2, sql3 = null;
String empno, resumefmt = null;
Clob resumelob = null;
ResultSet rs1, rs2, rs3 = null;
sql1 = "SELECT POSSTR(RESUME,'Personal') "
+ "FROM EMP_RESUME "
+ "WHERE EMPNO = ? AND RESUME_FORMAT = 'ascii' ";
stmt1 = con.prepareStatement (sql1);
stmt1.setString ( 1, empnum);
rs1 = stmt1.executeQuery();
while (rs1.next()) {
startper = rs1.getInt(1);
} // end while
sql2 = "SELECT POSSTR(RESUME,'Department') "
+ "FROM EMP_RESUME "
+ "WHERE EMPNO = ? AND RESUME_FORMAT = 'ascii' ";
stmt2 = con.prepareStatement (sql2);
stmt2.setString ( 1, empnum);
rs2 = stmt2.executeQuery();
while (rs2.next()) {
startdpt = rs2.getInt(1);
} // end while
startper1 = startper - 1;
sql3 = "SELECT EMPNO, RESUME_FORMAT, "
+ "SUBSTR(RESUME,1,?)|| SUBSTR(RESUME,?) AS RESUME "
+ "FROM EMP_RESUME "
+ "WHERE EMPNO = ? AND RESUME_FORMAT = 'ascii' "; //对字符进行截取,并组成新的Clob
stmt3 = con.prepareStatement (sql3);
stmt3.setInt (1, startper1);
stmt3.setInt (2, startdpt);
stmt3.setString ( 3, empnum);
rs3 = stmt3.executeQuery();
while (rs3.next()) {
empno = rs3.getString(1);
resumefmt = rs3.getString(2);
resumelob = rs3.getClob(3);
long len = resumelob.length();
int len1 = (int)len;
String resumeout = resumelob.getSubString(1, len1);
System.out.println(empno +"\t"+resumefmt +"\t"+resumeout );
} // end while
con.commit();
stmt1.close();
stmt2.close();
stmt3.close();
con.close();
}
显然,在处理Clob对象的过程中,我们把它当做字符串处理了。
最后,记得关闭pret.close();
5.对ResultSet的处理
① 获取:
ResultSet rs = pret.executeQuery();//PreparedStatement获取ResultSet对象PreparedStatement一般会预先设置好sql语句
ResultSet rs = stmt.executeQuery(sql);//Statement获取ResultSet对象Statement需要设置sql语句
② 访问(遍历):值得注意的是,从前往后遍历的时候,rs的游标指向数据开始的一条空行上;从前往后遍历的时候,rs的游标指向数据结束的一条空行上;
访问实例:
rs.first();//指向第一行数据
rs.previous();
while (rs.next()) {
startper = rs.getInt(1);
}
rs.last();//指向最后一行数据
rs.next();
while (rs.previous())) {
startper = rs.getInt(1);
}
其它:rs.get*()获得数据,比较懒的办法就是rs.getObject();将结果集中的对象都转成Object,处理交给之后的程序。
注意:访问空值方式如下:
Rs.get*(i);//先移动到要访问的列
Rs.wasNull();//返回Boolean,表示当前列是不是空值
③ 关闭:rs.close();
④ 对数据的操作:使用sql语句对数据经行操作的方式较为繁琐(繁琐在编写sql语句,效率也较低),rs对数据的操作还算简单,给人的感觉就是在修改一张表。
a. 移动:rs.absolute(index);//移动到index(从1开始)所指的那条数据。
b. 修改:
Rs.update*(index,value);//index为列的编号(从1开始)
或者rs.update*(label,value);//label为字符串,是列名,
最后落实更新:rs.updateRow();
取消更新:rs.cancelRowUpdates();
c. 添加:
移动到新加行:rs.moveToInsertRow() ;
然后对新加的行进行更新操作。
落实添加:rs.insertRow();
d. 删除:
移动到要删除的行(a);
执行删除rs.deleteRow();
6.对ResultSetMetaData的处理
ResultSetMetaData是一个很强大的类,可以通过它来获取列名、列的类型(Types),列对应的java中的类等等。
① 获取方式:
ResultSet rs = stmt.executeQuery(“SELECT a, b, c FROM TABLE2”);
ResultSetMetaData rsmd = rs.getMetaData();
② 使用:
a. getColumnCount() Returns the number of columns in this ResultSet object.
b. getColumnName(int column) Get the designated column’s name.
c. getColumnType(int column) Retrieves the designated column’s SQL type
d. getColumnClassName(int column) 获得这一列可能对应的java中的类型类名