Statement:

创建数据库:

创建表:

插入数据:

查询数据:

Statement 会引入 SQL 注入问题:

PreparedStatement:
通常我们执行一条 SQL 语句,得经过下面三个过程。
1. 词法和语义解析
2. 优化 SQL 语句,制定执行计划
3. 执行并返回结果

编译:

执行:

删除:

SQL代码:
# 预编译语句
# 编译
prepare ps from 'select * from t_user where name=? and password=?';
# 设置参数
set @name='Thomas_He';
set @password='123456';
# 执行
execute ps using @name, @password;
# 删除
drop prepare ps;
在 Java 中我们提供了 PreparedStatement 这个接口来调用数据库的预编译功能。
public class PrepareStatementDemo {
//java预编译
@Test
public void testInjection() throws SQLException {
Connection conn = getConnection();
String sql = "select * from t_user where name=? and password=?";
PreparedStatement pstmt = conn.prepareStatement(sql);
// 设置参数
String name = "aaa' or 1=";
String password = " or 1='1";
name = "'" + name + "'";
password = "'" + password + "'";
pstmt.setString(1, name);
pstmt.setString(2, password);
// 执行
ResultSet rs = pstmt.executeQuery();
// 处理结果集
while (rs.next()) {
String username = rs.getString("name");
BigDecimal balance = rs.getBigDecimal("balance");
System.out.println(username + ": " + balance);
}
}
//测试java预编译的性能(发现差别并不大,因为消耗的时间主要来自于网络通信)
@Test
public void testPerformance() throws SQLException { //23673ms
Connection conn = getConnection();
String sql = "insert into t_user(name, password) values(?, ?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
long start = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
pstmt.setString(1, "user" + i);
pstmt.setString(2, "123456");
pstmt.executeUpdate();
}
long end = System.currentTimeMillis();
System.out.println(end - start + "ms");
}
//连接的方法
private Connection getConnection() {
Properties info = new Properties();
try (Reader reader = new FileReader("db.properties")) {
info.load(reader);
} catch (IOException e) {
e.printStackTrace();
}
String url = info.getProperty("url");
String user = info.getProperty("user");
String password = info.getProperty("password");
Connection conn = null;
try {
conn = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
}
只会把它当做参数,不是当做逻辑处理(所以能够避免sql注入)


批处理:batch
pstmt.addBatch();
pstmt.executeBatch();
pstmt.clearBatch();



ResultSet


@Test
public void testTransaction() throws SQLException {
Connection conn = getConnection();
String sql = "update t_user set balance = balance - 100 where id=?";
PreparedStatement pstmt1 = conn.prepareStatement(sql);
pstmt1.setInt(1, 1);
// 开启事务
conn.setAutoCommit(false);
pstmt1.executeUpdate();
System.out.println(1/0);
sql = "update t_user set balance = balance + 100 where id=?";
PreparedStatement pstmt2 = conn.prepareStatement(sql);
pstmt2.setInt(1, 2);
pstmt2.executeUpdate();
// 提交事务
conn.commit();
}
