Chapter5 Advanced SQL
5.1 Accessing SQL From a Programming Language
SQL处理数据的力度与通用程序语言是不匹配的。SQL的数据处理单位是表格,而通用程序语言的数据处理单位是变量。
通过通用程序语言访问数据库有以下两种方式:
- Dynamic SQL:在程序运行时连接数据库,通过函数调用向数据库发送请求,对数据库进行操作,得到返回结果。如ODBC(C++)、JDBC(Java)等
- Embedded SQL:将SQL语句嵌入到通用程序语言的代码中,在编译时解析。
JDBC:
JDBC是Java Database Connectivity的缩写,是Java访问数据库的API。
JDBC与数据库的交互过程可分为以下几步:
- 建立数据库连接
- 创建Statement对象
- 通过Statement对象执行SQL语句
- 处理报错
以下java代码展示了如何使用JDBC连接并操作数据库:
整体框架定义了一个名为JDBCexample
的方法,public
说明可以从任何地方调用,static
说明属于类本身,而不是某个对象,void
说明没有返回值。三个参数dbid
为数据库ID,userid
为用户ID,passwd
为密码。
try
模块中,Connection
对应的语句用于建立数据库连接,其中参数"jdbc:oracle:thin:@db.yale.edu:2000:univdb"
是连接字符串(内含多重信息),userid
和passwd
是用户名和密码。Statement
对应的语句用于创建一个Statement对象。
{...Do Actual Work...}
部分是实际的数据库操作代码。
catch
模块用于捕获异常,可暂时不去细究。
使用executeUpdate
方法执行数据库的更新:
使用executeQuery
方法执行数据库的查询:
ResultSet rset = stmt.executeQuery("select dept_name, avg(salary)
from instructor
group by dept_name");
ResultSet
对象rset
是一个元组的集合,需要通过循环逐个取出元组。不同属性的数据类型不同,因此使用不同的方法获取(getString
,getFloat
等),参数可以是属性名,也可以是属性的序号:
使用wasNull
方法判断是否为空值:
Prepared Statement:
prepared statement是一种预编译SQL语句,使用占位符?
。
prepared statement的好处之一是只需要编译一次,便可执行多次。
prepared statement的另一个好处是避免通过字符串拼接的方法注入攻击。
Note
假设查询语句使用"select * from instructor where name = '" + name + "'"
的字符串拼接方法,如果用户输入的name
为恶意内容X' or 'Y' = 'Y
,那么实际解析出来的字符串为select * from instructor where name = 'X' or 'Y' ='Y'
,这个查询语句始终返回所有记录。
假如使用prepared statement,则SQL查询语句会被预编译,用户的输入不会被直接拼接到查询字符串中。如果用户的输入中含有特殊字符(如单引号),那么prepared statement会自动进行转义处理,避免SQL注入攻击。
Metadata:
元数据是描述数据的数据,分为以下两种:
- ResultSet Metadata:描述查询结果的元数据,如属性等
- Database Metadata:描述数据库的数据,如视图、索引等
使用getMetaData()
方法获取表格的元数据:
ResultSetMetaData rsmd = rset.getMetaData();
for (int i = 1; i <= rsmd.getColumnCount(); i++)
{
System.out.println(rsmd.getColumnName(i)); // 输出列名
System.out.println(rsmd.getColumnTypeName(i)); // 输出列的数据类型
}
DatabaseMetaData dbmd = conn.getMetaData();
ResultSet rs = dbmd.getColumns(null, "univdb", "department", "%");while( rs.next())
{
System.out.println(rs.getString("COLUMN_NAME"),rs.getString("TYPE_NAME"));
}
Transaction Control:
每次执行一条SQL语句后,JDBC会自动提交该语句作为一个单独的事务。然而,对于需要执行多个更新的事务,默认的自动提交可能导致部分操作成功,部分操作失败,从而破坏数据的一致性。
可以关闭自动提交:
若关闭自动提交,则之后的提交或者回滚都需要手动操作:
5.2 Functions and Procedures
SQL支持函数和过程,函数和过程的区别在于函数有返回值,通常无副作用;过程没有返回值,包含一系列副作用。
SQL Functions:
使用create function
创建函数:
其中,returns
定义返回的数据类型,declare
定义局部变量,select ... into ...
用于查询并将结果赋值给变量,return
返回结果。
调用函数:
Table Function:
表函数是一类特殊的函数,其返回结果是一张表。
创建表函数与创建普通函数类似,只是要在返回类型中声明返回的是表:
调用表函数:
SQL Procedures:
使用create procedure
创建过程:
create procedure dept_count_proc (in dept_name varchar(20), out d_count integer)
begin
select count(*) into d_count
from instructor
where instructor.dept_name = dept_count_proc.dept_name;
end;
其中,in
表示输入参数,out
表示输出参数。
调用过程: