前言
以下主要是吉林大学软件工程数据库应用db2课程的复习资料,希望能够帮到找到这里的学弟学妹们。
不过需要注意的是:
- ①所有罗列出的代码因为不要求具体编译环境,所以可能跟实际运行会有出入,在此只是给大家一个基本的参照和思路,请不要以这个为标答。
- ②请注意你们的考试范围,我们这届老师画的范围如下:
- 全部来自报告内容
- 只有五道题(每道题都是代码题)
- 会给一个数据库表
- 要求掌握需要导入哪些包,有哪些公共方法
- 去年考的批处理、查询并更新、clog、blog
- 今年不考GUI
- ③最后鸣谢我的学长学姐们,因为我也是靠他们传下来的资料和学校奔腾的考题去抱的佛脚。
然后整篇博客,我是按照“复习总结报告涉及的知识点——真题演练”的脉络进行的。本门课程的考核实验报告占一半,笔试占一半,而笔试其实也就是考察对相关语句的记忆和理解(主要还是背,背了才会用)。
考完了我靠记忆复原一下我们考的内容(我是2019级,今天是2021/12/31):
表给的是员工表(姓名、年龄、性别、工资、简历、照片)
- 单行插入、多行插入、子查询插入
- 用for update和where current of进行修改,好像是把名字为xxx的改为yyy
- 将员工原有工资增加5%,并写出溢出的异常处理
- 用setNULL和wasNULL对员工某个属性栏进行判空处理
- CLOB(简历)的读取并按要求输出指定内容
emmmmmm一整个大无语的状态,抱佛脚的内容从来记不住,记住的从来也从来不是临时抱佛脚背下来的,别指望两天速成,还是平时花时间多用吧
一. 报告知识点复习
1 任务1-3(Java连接数据库基本步骤)
1.1 加载jdbc驱动程序
Class.forName("COM.ibm.db2.jdbc.app.DB2Driver");
1.2 创建数据库的连接
String url = "jdbc:db2:sample";//欲连接的数据库路径
String userid=”db2admin”;//用户名
String passwd=”db2admin”;//密码
Connection sample=DriverManager.getConnection(url,userid,passwd);
1.3 ①写sql语句并创建一个 PreparedStatement/Statement语句;②并执行存入ResultSet结果集。
1.3.1 ①写sql语句并创建一个 PreparedStatement/Statement语句;
用到的sql语句分两类:
- 查询
- 删除,插入,更新
因为Sql语句如果是select查询类型的,查询之后的行数列数内容就用ResultSet存储。
而Sql如果是插删改的话,返回值是插入/修改/删除的行数int型。
//执行查询数据库的SQL语句,返回一个结果集(ResultSet)对象。
ResultSet executeQuery(String sqlString)
//用于执行INSERT、UPDATE或DELETE语句以及SQL DDL语句,如:CREATE TABLE和DROP TABLE等
int executeUpdate(String sqlString)
//一般用于sql语句中没有?的、可以直接执行的语句
//(1)Statement:
String sql ="select NAME, JOB, SALARY from staff Where ID = 10";//sql语句
Statement stmt = sample.createStatement();//创建statement语句
ResultSet rs = stmt.executeQuery( sql);//执行,并存入结果集
//一般用于sql语句中有?需要赋值的、不可以直接执行的语句。
//(2)PreparedStatement:
String sql="insert into templ(empno,firstnme,lastname,edlevel) values (?,?,?,?)";//sql语句
PreparedStatement pstmt = sample.prepareStatement(sql);//创建 PreparedStatement语句
pstmt.setString(1,deptno);//记住,从1开始,不是从0开始set,规定。deptno是一个字符串,自己定义即可,意思是将定义好的deptno赋值给第一个问号出现的地方。
pstmt.setString(2,deptno);//同理,给第二个问号赋值
pstmt.setString(3,deptno);
pstmt.setString(4,deptno);
int rows=pstmt.executeUpdate();//返回更新过的行数。
//而这一步,我们上面提到过如果是插删改的话,rows的值可以直接传回,但是如果是查询语句的话,那么就要遍历结果集得到一个ResultSet对象才行。
1.3.2 ②并执行存入ResultSet结果集。
while(rs.next()){
String data1 = rs.getString(1) ; //从1开始
String data2 = rs.getString(2) ;
String data3 = rs.getString(3) ;
String data4= rs.getString(4) ;
}
结果集有很多库函数,getString最常用,指取出的那一列属性的是字符串类型,
如果那一列属性是整数类型,就用getInt
1.4 处理异常,关闭jdbc对象资源
操作完成以后要把所有使用的JDBC对象全都关闭,以释放JDBC资源,关闭顺序和声明顺序相反,正常的声明顺序是“建立连接——获取当前状态——根据操作返回结果集”,所以反过来,我们的关闭顺序为:
1、先关闭ResultSet
2、再关闭preparedStatement
3、最后关闭连接对象connection
if(rs != null){ // 关闭结果记录集
try{
rs.close() ;
}catch(SQLException e){
e.printStackTrace() ;
}
}
if(stmt != null){ // 关闭状态声明对象
try{
stmt.close() ;
}catch(SQLException e){
e.printStackTrace() ;
}
}
if(conn != null){ // 关闭连接对象
try{
conn.close() ;
}catch(SQLException e){
e.printStackTrace() ;
}
}
2 任务4:窗口交互
涉及到一点交互,就是先不指定sql的判定语句中的值,通过弹出一个窗口,获得用户输入再赋值查询。
String inputValue = JOptionPane.showInputDialog("Please input a value");//输入的东西保存在inputValue
JOptionPane.showMessageDialog(null, "\nNumber of rows updated: " + updateCount);//弹出一个输出框显示更新行数
3 任务5:表格的相关操作,创建表格
String[] Names = { "编号", "名字", "姓氏", "职位"};//表头
Object[][] Info = new Object[4][4];//表格内容,几行几列
JTable table = new JTable(Info, Names);//创建表格
表格主要的库函数
//1.获取单元格数据
String cellValue=(String) tableModel.getValueAt(row, column);// 取单元格数据,row是行号,column是列号
//2.给单元格数据赋值,即给二维数组赋值,一般用ResultSet结果集赋值定义的表格Info
for(int i=0;i<4;i++)
for(int j=0;j<4;j++){
System.out.println(j+"ci");
info[i][j]=rs.getString(j+1);
}
}
//3.单行插入
String single_insert="insert into templ(empno,firstnme,lastname,edlevel)values (?,?,?,?)";
//4.多行插入
int count =4;//用户想插入四行
String sql="insert into templ(empno,firstnme,lastname,edlevel) values (?,?,?,?)";
for(int i=0;i<3;i++){
sql=sql+",(?,?,?,?)";
}
//5.通过子查询插入
String find_insert="insert into templ(empno,firstnme,lastname,edlevel)"+
"select empno,firstnme,lastname,edlevel from employee "+
"where empno=? "+
"and firstnme=? "+
"and lastname=? "+
"and edlevel=?";
4 任务6:ResultSet的wasNull()方法
//用于读取结果集下一行的语句判断是否为空
rs.next();
while(rs.next()){
......
}
rs.wasNull();
5 任务8:实现对结果集的任意行,任意列的修改
5.1 第一种方法
String finalstr="";
String selectforupdate="select empno,firstnme,lastname,edlevel,job from employee" +" for update";
//sql语句,不要忘记加上for update!!
int finalrow=0;
int finalcolmn=0;
int r= table.getSelectedRow();//得到表格被选中的行数,与结果集对应 finalrow=r;
int c=table.getSelectedColumn();//得到表格被选中的列数,与结果集对应 finalcolmn=c;
stmt=sample.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE); //创建可滚动,可更新的结果集
ResultSet select_rs=stmt.executeQuery(selectforupdate);
for(int i=0;i<finalrow;i++){
select_rs.next();//结果集移动到第finalrow行
}
if(select_rs.next()){
select_rs.updateObject(finalcolmn,finalstr);//更新结果集的第finalcolumn列,更新为finalstr
}
select_rs.updateRow();//将结果集落实到数据库
5.2 第二种方法
String finalstr="";
String selectforupdate="select empno,firstnme,lastname,edlevel,job from employee"+" for update";
//sql语句,不要忘记加上for update!!
int finalrow=0;
int finalcolmn=0;
int r= table.getSelectedRow();//得到表格被选中的行数,与结果集对应
finalrow=r;
int c=table.getSelectedColumn();//得到表格被选中的列数,与结果集对应
finalcolmn=c;
stmt=sample.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.
CONCUR_UPDATABLE);
ResultSet select_rs=stmt.executeQuery(selectforupdate);
select_rs.absolute(finalrow+1);//直接定位到第finalrow+1行
select_rs.updateObject(finalcolmn+1,finalstr);
select_rs.updateRow();
6 任务9:
6.1 创建可滚动的结果集,使用last,previous,first函数遍历
String sql="select NAME,JOB,SALARY from staff";
PreparedStatement stmt=sample.prepareStatement(sql,rs.TYPE_SCROLL_INSENSITIVE,rs.CONCUR_READ_ONLY); //为了创建可滚动,只读的结果集
ResultSet rs = stmt.executeQuery( );
rs.last();
rs.previous();
rs.first();
知识
rs.absolute()//绝对位置,负数表示从后面数
rs.first()第一条
rs.last()最后一条
rs.previoust()前一条
rs.next()后一条
6.2 批处理操作,同时执行多条语句
Statement接口里有两个方法:
void addBatch(String sql)
——将给定的 SQL 命令添加到此 Statement 对象的当前命令列表中。通过调用方法 executeBatch可以批量执行此列表中的命令。int[] executeBatch()
——将一批命令提交给数据库来执行,如果全部命令执行成功,则返回更新计数组成的数组。
返回:包含批中每个命令的一个元素的更新计数所组成的数组(数组中的每个元素为:成功处理了命令后,执行命令所影响数据库中行数的更新计数)。数组的元素根据将命令添加到批中的顺序排序。
批处理操作,即同时执行多条语句
代码:
Statement stmt=sample.createStatement();
stmt.addBatch("INSERT INTO DB2ADMIN.DEPARTMENT " +
"VALUES ('BT6','BATCH6 NEWYORK','BBBBB1','BTT','NEW YORK CITY6')");
stmt.addBatch("INSERT INTO DB2ADMIN.DEPARTMENT " +
"VALUES ('BT7','BATCH7 NEWYORK','BBBBB2','BT2','NEW YORK CITY7')");
int []updateCounts=stmt.executeBatch();
sample.commit();
6.3 获取数据库结构
DatabaseMetaData dbmd=sample.getMetaData();//获取数据库的结构,存储等信息。
String []tableTypes={"TABLE","VIEW"};
ResultSet rs=dbmd.getTables(null,"UDBA","%",tableTypes);
知识:
dbmd.getTables(String catalog,String schema,String tableName,String[] types)
,这个方法带有四个参数,它们表示的含义如下:
①String catalog
:要获得表所在的编目。"“”“意味着没有任何编目,Null表示所有编目。
②String schema
:要获得表所在的模式。”“”"意味着没有任何模式,Null表示所有模式。
③String tableName
:指出要返回表名与该参数匹配的那些表。
④String types
:一个指出返回何种表的数组。可能的数组项是:“TABLE”、“VIEW”、“SYSTEM TABLE”, “GLOBAL TEMPORARY”,“LOCAL TEMPORARY”,“ALIAS”,“SYSNONYM”。- 通过getTables()方法返回的结果集中的每个表都有下面是10字段的描述信息,而且只有10个。通常我们用到的也就是标红的几个字段。而且在结果集中直接使用下面字段前面的序号即可获取字段值。
1.TABLE_CAT (String) => 表所在的编目(可能为空)
2.TABLE_SCHEM (String) => 表所在的模式(可能为空)
3.TABLE_NAME (String) => 表的名称
7 任务10:blob类型对象的读取和插入
Blob类型的赋值,用setBinaryStream(int n, java.io.InputStream x, int length)
语句:
①n指示参数编号的 int
②InputStream 对象
③length指示字节数的 int。
7.1 查询图片代码
Statement st=conn.createStatement();
ResultSet rs=st.executeQuery("select image from employee");
while(rs.next()){
//读取Blob对象
Blob blob= (Blob) rs.getBlob(1);
//Blob对象转化为InputStream流
java.io.InputStream inputStream =blob.getBinaryStream();
//要写入的文件
File fileOutput = new File("c:/backa.jpg");
//文件的写入流的定义
FileOutputStream fo = new FileOutputStream(fileOutput);
int c;
//读取流并写入到文件中
while ((c = inputStream.read()) != -1)
fo.write(c);
//流的关闭:
fo.close();
}
7.2 插入图片代码
PreparedStatement preparedStatement = conn.prepareStatement("insert into emp_photo values('000130','jpeg',?)");
//创建文件对象:
File file=new File("e:/123.jpg");//参数是本地图片的路径名
// 创建流对象:
BufferedInputStream imageInput = new BufferedInputStream(new FileInputStream(file));
//参数赋值:
preparedStatement.setBinaryStream(1, imageInput,(int)file.length());
//第二个参数InputStream 对象,第三个参数字节数int
//执行语句
preparedStatement.executeUpdate();
8 任务11:clob类型的读取
Clob resumelob = null;//定义clob类型
resumelob = rs3.getClob(3);//将结果集中第三个位置的clob取出
String detailinfo = resumelob.getSubString((long)1,(int)resumelob.length());
//将clob类型转化为字符串类型,参数固定,基本上就这么写
还用到的sql函数
POSSTR(RESUME,'Personal')//查看Personal这个单词在RESUME中的位置
SUBSTR(RESUME,1,length)//取resume中1-length长度的字段
二. 真题演练(2016-2017年考题)
1. 建立数据库连接的语句,对象自定义
static{
try{
class.forName("COM.ibm.db2.jdbc.app.DB2Driver");
}catch(Exception e){
System.println("\n Error loading DB2 Driver...\n");
System.println(e);
System.exit(1);
}
}
String url = "jdbc:db2:sample";
Connection con = DriverManager.getConnection(url,userid;passwd);
Statement st = con.creatStatement();
2. 定义一个结果集对象,该对象将执行的查询语句是“查询表staff,获取员工编号为10的员工名字(name)工作(job)和工资(salary)”,写出具体执行代码
String SQL="SELECT NAME,JOB,SALARY FROM STAFF WHERE ID = 10";
Resultset rs = st.executeQuery(SQL);
3. 写出结果集中下一行的方法,假设对象为rs,写出具体执行代码。
boolean more = rs.next();
while(more){
String outline;
name = rs.getString(1);
job = rs.getString(2);
salary = rs.getString(3);
outline = ( name + blanks.substring(0,10-name.length()) ) +
( job + blanks.substring(0,10-job.length()) ) +
( salary + blanks.substring(0,12-salary.length()) )
more=rs.next();
}
4. Sql=“SELECT name FROM Temp WHERE id=? ”执行这种sql语句时,该创建什么对象?若对象名为pstmt,写出具体的程序片段。
String sql = "SELECT name FROM Temp WHERE id=?" ;
pstmt = conn.prepareStatement(sql) ;
pstmt.setString(1,id) ; // 这里用于设置了第一个?的值
实质就是等用户去手动“setString”以控制查找条件。设置完成后,sql才构造好。
总结:
- 问号就是我们所谓的一个变量,没有确定值,我们可以通过setString()方法对其赋值,这对于我们sql的灵活性有很好的意义。
5. ①已知sql更新语句“UPDATE temp SET salary=salary*5”,写出具体执行代码;②count为executeUpdate()的执行结果,count=3,但查询原表并未改变,这是为什么?
①
sqlstmt = "UPDATE TEMP SET SALARY = SALARY * 5 WHERE DEPT = ?";
PreparedStatement pstmt = con.prepareStatement( sqlstmt );
②
原因是因为程序被设置为了不自动提交SQL语句con.setAutoCommit(fALSE)
所以刚刚进行修改后立即返回的结果,是程序为了提高性能从设置中的缓存里读取的,而不是从数据库读取的。
总过程:
Connection sample = DriverManager.getConnection("jdbc:db2:sample",userid,passwd);
String deptno = "";
String s = " ";
int mydeptno = 0;
int updateCount=0;
String sqlstmt = "UPDATE TEMP SET SALARY = SALARY * 5 WHERE DEPT = ?";
BufferedReader in = new BufferedReader( new InputStreamReader (System.in));
System.out.println("input deparement no._");
s = in.readLine();
While(s!=null){
deptno = s.substring(0,2);//从输入流中获取指定的dep的值,结果返回字符串
mydeptno = Integer.parseInt(deptno);//转换为int
PreparedStatement pstmt = sample.prepareStatement( sqlstmt );//准备执行sql语句
pstmt.setInt(1, mydeptno);//给sql中第一个?处赋值
updateCount += pstmt.executeUpdate();//每次更新都要计数
System.out.println("input deparement no");
s = in.readline();
}
System.out.println("\n Number of rows updated: " + updateCount);
6. 假设Connection,Statement,ResultSet类的对象分别是con,stmt,rs,在程序结束之前,应该按什么顺序关闭这三个对象,请以此写出具体语句。
rs.close()
stmt.close()
con.close()
从最开始的两道题里面也能看出,是先建立连接,然后获取当前状态下的数据,再进行相应操作获得结果集;那么关闭过程应该溯源,所以关闭结果集——>关闭状态对象——>关闭连接。
7. 将一个图片“e:\photo\a.jpg”插入到表student的photo列(BOLB属性)中,写出主要的操作语句,对象自定义。
//将图片插入到BLOB类型的字段中
//建立一个表:
create table a(blob a);
//建立一个目录:
create directory tmp as 'e:\';
//建立一个PL/SQL块:
declare
bfile b_file;
blob b_lob;
begin
insert into a(a) values(empty_blob())
return a into b_lob;
//为了使PL/SQL编译成功,必须先为该列插入一个empty_blob() 值
//return a into b_lob是将该列与一个blog类型的变量绑定在一起,以后只要为b_lob赋值,即等于将该值插入了表中。
b_file:=bfilename('tmp','filename.jpg');
//tmp是建立的文件所在的目录,filename.jpg是文件名;将文件转换为bfile类型
dbms_lob.open(b_file,dbms_lob.file_readonly);
//将b_file 以只读的方式打开
dbms_lob.loadfromfile(b_lob,b_file,dbms_lob.getlength(b_file));
//将b_file中的内容转换到b_lob中
dbms_lob.close(b_file);
commit;
end;