问题代码:
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
// 注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 获取数据库连接
String url = "jdbc:mysql://localhost:3306/数据库名";
String user = "用户";
String pwd = "密码";
conn = DriverManager.getConnection(url, user,pwd);
// 获取数据库操作对象
stat = conn.createStatement();
//执行sql语句
String sql = "select * from t_user where user = '"+userName+"' and pwd = '"+passwd+"'";
rs = stat.executeQuery(sql);
// 处理结果集
if (rs.next()){
return true;
}
问题:
userName = sasas passwd = sa' or '1' = '1 那么就会出现sql注入现象 语句就会成这样 String sql = "select * from t_user where user = 'sasas' and pwd = 'sa' or '1' = '1'"; 那么select语句就会执行成功
怎么解决SQL注入现象?
解决sql注入问题
使用:PreparedStatement(预编译数据库操作对象)
原理:预先对sql语句的框架进行编译,再给sql语句传值
解决代码:
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
// 注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 获取数据库连接
String url = "jdbc:mysql://localhost:3306/数据库名";
String user = "用户";
String pwd = "密码";
conn = DriverManager.getConnection(url, user,pwd);
// 获取预编译数据库操作对象
String sql = "select * from t_user where user = ? and pwd = ?"; // 问号代表占位符,一个"?"代表一个值,不能用单引号括起来
ps = conn.prepareStatement(sql);
//给?号传值 --> 在jdbc中索引是从1开始
ps.setString(1,userName); // 1代表第一个问号
ps.setString(2,passwd);
//执行sql语句
rs = ps.executeQuery();
// 处理结果集
if (rs.next()){
return true;
}
二、对PreparedStatement的"增删改"进行演示
Connection conn = null;
PreparedStatement ps = null;
// 注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 获取连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/数据库名","用户","密码");
// 获取数据库预编译对象
// 增 insert
String sql = "insert into dept values(?,?,?)";
ps = conn.prepareStatement(sql);
ps.setInt(1, 60);
ps.setString(2, "经理");
ps.setString(3, "广州");
// 改 update
String sql = "update dept set deptno = ? where deptno = 60";
ps = conn.prepareStatement(sql);
ps.setInt(1, 80);
// 删 delete
String sql = "delete from dept where deptno = ?";
ps = conn.prepareStatement(sql);
ps.setInt(1, 80);
// 执行sql语句
int count = ps.executeUpdate();
System.out.println(count);
// 关闭资源
ps.close();
conn.close();
三、演示事务机制
演示jdbc中的事务机制
重点三行代码
conn.setAutoCommit(false)
conn.commit()
conn.rollback()
void setAutoCommit(boolean autoCommit)
autoCommit - 为 true 表示启用自动提交模式;为 false 表示禁用自动提交模式
将此连接的自动提交模式设置为给定状态。如果连接处于自动提交模式下,则它的所有
SQL 语句将被执行并作为单个事务提交。否则,它的 SQL 语句将聚集到事务中,直到调用
commit 方法或 rollback 方法为止。默认情况下,新连接处于自动提交模式。
没有事务的情况:
// 没有事务的情况
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
// 1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2、获取连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/数据库","用户","密码");
// 3、获取预编译数据库对象
String sql = "update tbl_act set money = ? where no = ?";
ps = conn.prepareStatement(sql);
ps.setDouble(1, 10000);
ps.setInt(2,111);
int count = ps.executeUpdate();
// 但抛出异常那么下面的语句不会执行,导致钱丢失,所以这里需要用到事务机制
String s = null;
s.toString();
ps.setDouble(1,10000);
ps.setInt(2,222);
count += ps.executeUpdate();
System.out.println(count == 2 ? "转账成功" : "转账失败");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally{
if (ps != null) {
try {
ps.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
开启事务的情况:
// 有事务的情况
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
// 1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2、获取连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/数据库","用户","密码");
// 设置为手动提交模式,手动提交sql语句
conn.setAutoCommit(false);
// 3、获取预编译数据库对象
String sql = "update tbl_act set money = ? where no = ?";
ps = conn.prepareStatement(sql);
ps.setDouble(1, 10000);
ps.setInt(2,111);
int count = ps.executeUpdate();
// 当抛出异常那么下面的语句不会执行,导致钱丢失,所以这里需要用到事务机制
ps.setDouble(1,10000);
ps.setInt(2,222);
count += ps.executeUpdate();
System.out.println(count == 2 ? "转账成功" : "转账失败");
// 能执行到这里说明没有出现异常,就是说转账成功
// 执行commit方法
conn.commit();
} catch (Exception e) {
// 如果出现异常需要进行回滚操作,即是第一个转账成功之后进行回滚回到没有转账之前
// 也就是上一次事务提交成功的位置
if (conn != null){
try {
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
e.printStackTrace();
} finally{
if (ps != null) {
try {
ps.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
四、悲观锁的概念(行级锁)
语法:
select * from emp where job = ? for update加了for update后只要当前事务不提交,那其他事务就无法对当前查询的行内容进行操作
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
// 注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 获取连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/数据库","用户","密码");
conn.setAutoCommit(false);
// 获取预编译数据库操作对象
String sql = "select * from emp where job = ? for update";
ps = conn.prepareStatement(sql);
ps.setString(1, "manager");
// 执行sql语句
rs = ps.executeQuery();
while(rs.next()){
System.out.println(rs.getString("ename"));
}
conn.commit();
不懂到时候在看代码。



