文章目录
1. PreparedStatement 研究
1.1 PreparedStatement 概念
- 什么是带参数的 SQL 语句?
String sql = "select * from students where sno = ?";
- 解释参数 “ ?”(占位符)
- 这里并不是查询学号为 ? 号的学生。
- 而是代表一个参数,在执行该语句之前,必须给参数赋值。
1.2 为什么要多用 PreparedStatement ?而少用 Statement
- 代码的可读性和可维护性。
在这里插入代码片
- PreparedStatement 提高性能。
- 有一种常见情况:写好的 JDBC 代码,编译器会对代码预编译,而预编译语句可能重复调用。
- 因而,使用 PreparedStatement 可以提高性能。
- 因为,只需要将参数直接传入编译过的语句执行代码。
- 防止 SQL 注入攻击。
SQL 注入攻击:
- 用户合法的输入:但提交的是特殊的非法代码。
- 输入注入了 SQL 中,改变了 SQL 原有的逻辑。
例如:
- 在登陆界面,用户名输入:
- 'or'1'='1'or'1'='1
- SQL 语句就变成了:
- select * from students where sname = ''or'1'='1'or'1'='1'
1.3 如何使用 PreparedStatement
- 连接数据库
/* 驱动程序描述字符串 */
String driver = "com.mysql.jdbc.Driver";
/* 加载驱动程序 */
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
/* 连接数据库 */
String url = "jdbc:mysql://localhost:3306/mydb";
String user = "root";
String passwd = "123456";
Connection con = null;
try {
con = DriverManager.getConnection(url, user, passwd);
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
- 创建命令对象——PreparedStatement
/* 创建命令对象——PreparedStatement */
String sql = "select * from students where sno = ?";
PreparedStatement cmd = null;
try {
cmd = con.prepareStatement(sql);
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
- 输入参数
/* 设置参数 */
try {
/*
* 1. setString(1, "张三")
*
* 2. 1 表示从左到右你写的 sql 语句的第一个参数(相当于 ? 的位置)
*
* 3. "张三" 表示查询的值
*/
cmd.setString(1, "张三");
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
- 执行
/* 执行 */
try {
System.out.print("执行是否成功:" + cmd.execute());
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
- 关闭接口
/* 关闭接口 */
try {
if (cmd != null) {
cmd.close();
cmd = null;
}
if (con != null) {
con.close();
con = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
执行是否成功:true
1.4 使用 PreparedStatement 示例
public static void addStudent() throws UnsupportedEncodingException {
Connection con = null;
PreparedStatement cmd = null;
ResultSet rs = null;
String url = "jdbc:mysql://localhost:3306/mydb";
String user = "root";
String passwd = "123456";
try {
/* 驱动 */
Class.forName("com.mysql.jdbc.Driver");
/* 连接数据库 */
con = DriverManager.getConnection(url, user, passwd);
/* 增加一个学生代码——使用 PreparedStatement */
String sql1 = "insert into students(sno, sname, ssex) values(?, ?, ?);";
cmd = con.prepareStatement(sql1);
cmd.setString(1, "1005");
cmd.setString(2, "李四");
cmd.setString(3, "男");
cmd.executeUpdate();
/* 打印到控制台 */
String sql2 = "select * from students";
rs = cmd.executeQuery(sql2);
while (rs.next()) {
String sno = rs.getString("sno");
String sname = rs.getString(2);
String ssex = rs.getString("ssex");
System.out.printf("%-8s%-6s%-3s\n", sno, sname, ssex);
}
} catch (ClassNotFoundException e) {
// TODO JDBC 驱动
e.printStackTrace();
} catch (SQLException e) {
// TODO 连接数据库
e.printStackTrace();
} finally {
try {
if (rs != null) {
rs.close();
rs = null;
}
if (cmd != null) {
cmd.close();
cmd = null;
}
if (con != null) {
con.close();
con = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
控制台输出:
1001 李晨 男
1002 王丽 女
1003 陈军 男
1004 张三 男
1005 李四 男
MySQL:

2. 如何获得元数据 MetaData
2.1 元数据就是字段那些
- 元数据最本质的定义为:data about data(关于数据的数据)。
- JDBC 通过元数据(MetaData)来获得表的相关信息,如:字段,字段属性等。
- JDBC 提供了两个元数据对象类型:DatabaseMetaData 和 ResultSetMetadata
2.2 元数据访问示例
public static void practiceMetaData() throws Exception {
Connection con = null;
Statement cmd = null;
ResultSet rs = null;
String url = "jdbc:mysql://localhost:3306/mydb";
String user = "root";
String passwd = "123456";
try {
/* 驱动 */
Class.forName("com.mysql.jdbc.Driver");
/* 连接数据库 */
con = DriverManager.getConnection(url, user, passwd);
/* 创建数据库的元数据 */
DatabaseMetaData meta = con.getMetaData(); // 获取数据库的元数据对象
System.out.println("数据库名为:" + meta.getDatabaseProductName());
System.out.println("数据库版本号为:" + meta.getDatabaseProductVersion());
System.out.println("数据库Url为:" + meta.getURL());
System.out.println("数据库登录名为:" + meta.getUserName());
System.out.println("数据库驱动名为:" + meta.getDriverName());
/* 1. 创建表的元数据 */
/* 2. 打印 students 表到控制台 */
System.out.println("Students 表为:");
cmd = con.createStatement();
String sql2 = "select * from students";
rs = cmd.executeQuery(sql2);
// 1
ResultSetMetaData rsmd = rs.getMetaData();
System.out.println("第一列的类型为:" + rsmd.getColumnType(1));
System.out.println("第一列的列类型名为:" + rsmd.getColumnTypeName(1));
System.out.println("第一列所在的表为:" + rsmd.getTableName(1));
// 2
while (rs.next()) {
String sno = rs.getString("sno");
String sname = rs.getString(2);
String ssex = rs.getString("ssex");
System.out.printf("%-8s%-6s%-3s\n", sno, sname, ssex);
}
} catch (ClassNotFoundException e) {
// TODO JDBC 驱动
e.printStackTrace();
} catch (SQLException e) {
// TODO 连接数据库
e.printStackTrace();
} finally {
try {
if (rs != null) {
rs.close();
rs = null;
}
if (cmd != null) {
cmd.close();
cmd = null;
}
if (con != null) {
con.close();
con = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
数据库名为:MySQL
数据库版本号为:8.0.23
数据库Url为:jdbc:mysql://localhost:3306/mydb
数据库登录名为:root@localhost
数据库驱动名为:MySQL Connector/J
Students 表为:
第一列的类型为:4
第一列的列类型名为:INT
第一列所在的表为:students
1001 李晨 男
1002 王丽 女
1003 陈军 男
1004 张三 男
1005 李四 男
3. 事务处理
3.1 什么是 Java 事务
- 要么全部执行成功,要么撤销全部不执行。
- 数据库 JDBC 操作的事务习惯就称为 Java 事务。
3.2 数据库事务编程示例
public static void practiceTransaction() {
Connection con = null;
Statement cmd = null;
ResultSet rs = null;
String url = "jdbc:mysql://localhost:3306/mydb";
String user = "root";
String passwd = "123456";
try {
/* 驱动 */
Class.forName("com.mysql.jdbc.Driver");
/* 连接数据库 */
con = DriverManager.getConnection(url, user, passwd);
/* 创建命令对象 */
String sql1 = "insert into students(sno, sname, ssex) values(1006, \"王老五\", \"男\");";
cmd = con.createStatement();
/* 事务处理 */
try {
con.setAutoCommit(false); // 禁止自动提交事务,我们自己定义事务
cmd.executeUpdate(sql1);
cmd.executeUpdate(sql1);
con.commit(); // 提交事务
} catch (Exception e) {
// TODO 事务
try {
con.rollback();
} catch (SQLException ee) {
ee.printStackTrace();
}
}
/* 打印到控制台 */
String sql2 = "select * from students";
rs = cmd.executeQuery(sql2);
while (rs.next()) {
String sno = rs.getString("sno");
String sname = rs.getString(2);
String ssex = rs.getString("ssex");
System.out.printf("%-8s%-6s%-3s\n", sno, sname, ssex);
}
} catch (ClassNotFoundException e) {
// TODO JDBC 驱动
e.printStackTrace();
} catch (SQLException e) {
// TODO 连接数据库
e.printStackTrace();
} finally {
try {
if (rs != null) {
rs.close();
rs = null;
}
if (cmd != null) {
cmd.close();
cmd = null;
}
if (con != null) {
con.close();
con = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
可以看到,并没有插入数据
1001 李晨 男
1002 王丽 女
1003 陈军 男
1004 张三 男
1005 李四 男
781

被折叠的 条评论
为什么被折叠?



