href="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_filelist.xml" rel="File-List" />
5.7.2 JDBC 要点
下文为方便理解本章内容所整理的 JDBC 要点,需要指出的是,这一节内容不能代替
专业的 JDBC教材或者参考资料。
JDBC 要点
1. 用接口的方式将数据库分成两部分. 一部分是对开发人员提供的编程接口, java.sql.*;第
二部分是给各大厂商, 给他们是驱动接口(java.sql.Driver).
DriverManager.getConnection(String url, String username, String password).
java.sql.Connection ==> 实现类, 不是接口.
class OracleConnection implements java.sql.Connection
createStatement() -> OracleStatement implements java.sql.Statement
提供者/调用者 => 工厂模式 => 透明的开发和调用
2. 一般的 JDBC 项目(增删查改)
增删改: 能改数据
INSERT INTO TABLE_NAME [(列 1, 列 2, ...)] VALUES(值 1, 值 2, ...)
DELETE TABLE_NAME [WHERE 条件子句]
列名 = 值 AND 列名 LIKE 'beijing%' OR 列 1 = 列 2
UPDATE TABLE_NAME SET 列 1 = 值 1 , 列 2 = 值 2, ... [WHERE 条件子句]
查就算是查询
SELECT *, 或者用列名 FROM [表 1 别名 1, 表 2 别名 1] [WHERE 条件子句]
两个表的查询: 表 1.id = 表 2.id 或者 别名 1.id = 别名 2.id
select c.roomName from student s, classroom c where s.id = c.student_id
1) 把驱动程序加入到 classpath;
2)
// 加载驱动程序
// 方式 a
new com.mysql.jdbc.Driver();
// 方式 b 动态类加载
try {
Class.forName("com.mysql.jdbc.Driver");
} catch(Exception e) {
}
// 打开数据库连接
try {
String url = "jdbc:mysql://localhost:3306/test";
String username = "root";
String password = "";// 空密码可以写成 "" 或者 null
Connection conn = DriverManager.getConnection(url, username, password); MyEclipse 6 Java开发中文教程
85 刘长炯著
// 数据改动用 executeUpdate(String sql)
Statement stmt = conn.createStatement();
// Statement stm = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);//获得可更新和可滚动的结果集
String sql = "insert into student values(1, 'student1')";
int rows = stmt.executeUpdate(sql);// 返回改动的数据的行数
// 读取数据 executeQuery(String sql)
sql = "select * from student";
ResultSet rs = stmt.executeQuery(sql);
// rs = null;
while(rs != null && rs.next()) {
// 取数据可以根据下标或者列名
String studentname = rs.getString(2);// 下标从 1 开始
int id = rs.getInt("id");// 根据列名获取
byte[] bytes = rs.getBytes("face");// 读取二进制
}
// 释放资源
rs.close();
stmt.close();
conn.close();
} catch(Exception e) {
}
代码的问题在于如果中间出现异常, 那么连接资源就不能释放, 解决办法是把变量声
明放在 try-catch 语句之外; 第二把资源释放给放进 finally 里面.
// 打开数据库连接
// 声明用到的资源
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
String url = "jdbc:oracle:thin:@hostname:1521:tarena";
String username = "openlab";
String password = "";// 空密码可以写成 "" 或者 null
conn = DriverManager.getConnection(url, username, password); MyEclipse 6 Java开发中文教程
86 刘长炯著
// 数据改动用 executeUpdate(String sql)
stmt = conn.createStatement();
// Statement stm = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
String sql = "insert into student values(1, 'student1')";
int rows = stmt.executeUpdate(sql);// 返回改动的数据的行数
// 读取数据 executeQuery(String sql)
sql = "select * from student";
rs = stmt.executeQuery(sql);
// rs = null;
while(rs != null && rs.next()) {
// 取数据可以根据下标或者列名
String studentname = rs.getString(2);// 下标从 1 开始
int id = rs.getInt("id");// 根据列名获取
byte[] bytes = rs.getBytes("face");// 读取二进制
}
} catch(SQLException e) {
throw new 数据处理失败异常();
// throw SQLExeption
} finally {
// 释放资源
try {
rs.close();
} catch(Exeption ex) {
}
try {
stmt.close();
} catch(Exeption ex) {
}
try {
conn.close(); MyEclipse 6 Java开发中文教程
87 刘长炯著
} catch(Exeption ex) {
}
// 简化成
// close(rs, stmt, conn);
}
close(ResultSet rs, Statement stmt, Connection conn) {
// 释放资源
try {
rs.close();
} catch(Exeption ex) {
}
try {
stmt.close();
} catch(Exeption ex) {
}
try {
conn.close();
} catch(Exeption ex) {
}
}
3. 获取结果集中有多少字段及其类型,可以用 rs.getMetaData() 来获取
ResultSetMetaData 对象, 很多框架就是用这种办法再加上反射来进行自动的属性填充操作
的,例如 Hibernate。
ResultSetMetaData 可用于获取关于 ResultSet 对象中列的类型和属性信息的对象。
以下代码片段创建 ResultSet 对象 rs,创建 ResultSetMetaData 对象 rsmd,并使用
rsmd 查找 rs 有多少列,以及 rs 中的第一列是否可以在 WHERE 子句中使用。
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2");
ResultSetMetaData rsmd = rs.getMetaData();
int numberOfColumns = rsmd.getColumnCount();
boolean b = rsmd.isSearchable(1);
4. PreparedStatement 的用法
PreparedStatement 继承自 Statement, 所有的 Statement 能进行的操作这里都可以MyEclipse 6 Java开发中文教程
88 刘长炯著
用.
1) 执行速度优化(预编译)
2) 简化 SQL 编写
String sql = "select * from user where username = ?";
3) 增加安全性
SQL 注入攻击
String sql = "select * from user where username = '" + username + "'";
username 输入 1' = '1' or username = '张三
select * from user where username = '1' = '1' or username = '张三'
避免方法: a) 过滤用户输入的特殊字符 '' = '
username.replaceAll("'", "''");
b) 用 PreparedStatement.setString(下标, username) 自动转换输入的字符串为合法
的 SQL 的格式
用法:
// 1. 打开
PreparedStatement pstmt = conn.createPreparedStatement("select * from user where
username = ? and regdate = ?");
// 2. 设置要处理的数据
pstmt.setString(1, "张三");
java.util.Date now = new java.util.Date();
pstmt.setDatetime(2, new java.sql.Date(now.getTime()) );// 设置日期
// 3. 执行查询或者更新
ResultSet rs = pstmt.executeQuery();//
rs = pstmt.executeQuery("select * ..:");//
int rows = pstmt.executeUpdate();// 更新
3. CallableStatement 用来调用存储过程(了解)
在 JDBC 中调用已储存过程的语法如下所示。注意,方括号表示其间的内容是可选项;方
括号本身并不是语法的组成部份。
{call 过程名[(?, ?, ...)]}
返回结果参数的过程的语法为:
{? = call 过程名[(?, ?, ...)]}
不带参数的已储存过程的语法类似:
{call 过程名}
示例代码:
String procedure="{call Operator_login(?,?,?)}";
//注册存储过程 MyEclipse 6 Java开发中文教程
89 刘长炯著
CallableStatement callStmt=conn.prepareCall(procedure);
//注册存储过程输出参数的类型
callStmt.registerOutParameter(3,java.sql.Types.INTEGER);
//提供输入参数的值
callStmt.setString(1,this.operatorID);
callStmt.setString(2,this.password);
//执行存储过程
callStmt.execute();
//返回输出参数
login_state=callStmt.getInt(3);
CallableStatement cs = conn.prepareCall("{call ec_get_cust_terms(?)}");
cs.setInt(1, custNo);
rs = cs.executeQuery();