时间:2021-07-01 10:21:17 帮助过:16人阅读
1.什么是sql注入。
* 用户通过相关的特殊关键字sql语句非法访问数据库
*例如:
Xxx(‘ or ‘1‘=‘1 ):sql语句中跟括号的内容,就达到了注入的目的。
2. 原因
仔细分析一下,数据库注入成功的根本原因是,我们把sql语句中的参数(用户的输入)和sql命令拼接成了一个sql语句,因为一个sql语句中既可以有sql的命令又可以有参数,因此,用户的输入也可以被当做sql的语句来解析执行。
那么,既然知道了sql注入成功的原因,我们就反其道而行之,不让用户输入的参数被当做sql命令解析,而是只把它当做普通字符串来解析。
由此,java中引入了prepareStatement,利用preparestatement来防止sql注入的核心思想就是,不把用户的输入当做sql命令来解析和执行。
3. PreparedStatement继承自Statement,可以通过Connection的prepareStatement方法得到。
例如:
//2.定义sql语句
String sql="insert into account values(null,?,?)";
//定义sql语句执行对象,防止注入
PreparedStatement st=con.prepareStatement(sql);
//给? 赋值
st.setString(1, xxx);
st.setString(2, xxx);
//执行sql
rs=st.executeQuery(sql);
4. 分析
prepareStatement很明显的将sql命令语句与参数分开处理,其执行过程是:
1. 首先在sql语句真正执行之前,先把sql命令送到数据库中进行预编译,生成相应 的数据库命令。
2. 然后在获取sql中的参数,然后真正执行该sql语句。
这样一来,用户输入的参数,只被当做参数而非命令来解析,就可以避免数据库注入这样的问题发生。
**缺点**:不过,这样一来,单次执行PreparedStatement需要与数据库通信两次,效率,比之于单词执行Statement要低。
1. 第一种方式
-- 把sql语句加入到批命令中
*statement.addBatch(sql)
-- 执行批处理SQL语句
*executeBatch()方法:执行批处理命令
*clearBatch()方法:清除批处理命令
例如;
//2.定义sql语句
String sql="insert into account values(null,‘你好‘,2000)";
String sql1="insert into account values(null,‘你好‘,2000)";
String sql2="insert into account values(null,‘你好‘,2000)";
//定义sql语句执行对象
st=con.createStatement();
//把sql语句加入到批命令中
st.addBatch(sql);
st.addBatch(sql1);
st.addBatch(sql2);
//执行批处理命令
st.executeBatch();
**优点**:
可以向数据库发送多条不同的SQL语句。
**缺点**:
SQL语句没有预编译。
当向数据库发送多条语句相同,但仅参数不同的SQL语句时,重复写很多条sql语句
2. 第二种方式
*PreparedStatement.addBatch()
例如:
//2.定义sql语句
String sql="insert into account values(null,?,?)";
//定义sql语句执行对象,防止注入
PreparedStatement st=con.prepareStatement(sql);
for (int i = 6; i < 12; i++) {
st.setString(1, "aaa" + i);
st.setString(2, "100" + i);
//加入到批命令中
st.addBatch();
if (i%100==0){
//每一百行清理一次
st.executeBatch();
st.clearBatch();
}
}
//执行批处理命令
st.executeBatch();
优点:与数据库通信次数在批量操作时,PreparedStatment的通信次数远少于Statment。
缺点:只能应用在SQL语句相同,但参数不同的批处理中。因此此种形式的批处理经常用于在同一个表中批量插入数据,或批量更新表的数据。
1. 概念:
* 如果一个包含多个步骤的业务操作,被事务管理,那么这些操作要么同时成功,要么同时失败。
2. 操作:
1. 开启事务: start transaction;
*con.setAutoCommit(false):开启事务
2. 回滚:rollback;
*在catch中回滚事务
3. 提交:commit;
*当所有sql都执行完提交事
3. 例如
try{
//1.获取con
con= JDBCUtils.getConnection();
//开启事务
con.setAutoCommit(false);
//2.定义SQL
String sql="update account set balance=balance-? where id=?";
//3.获取sql 执行对象
pstm=con.prepareStatement(sql);
//赋值操作 张三 -500
pstm.setDouble(1,500);
pstm.setInt(2,1);
pstm.executeUpdate();
int i=3/0;
//赋值操作 李四 +500
pstm.setDouble(1,-500);
pstm.setInt(2,2);
pstm.executeUpdate();
//提交事务
con.commit();
}catch (Exception e){
//事务回滚
try {
if (con!=null){
con.rollback();
}
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
JDBCUtils.releaseResource(con,pstm,null);
}
}
2.事务的四大特性
1. 原子性:是不可分割的最小操作单位,要么同时成功,要么同时失败。
2. 持久性:当事务提交或回滚后,数据库会持久化的保存数据。
3. 隔离性:多个事务之间。相互独立。
4. 一致性:事务操作前后,数据总量不变
3. 事务的隔离级别(了解)
* 概念:多个事务之间隔离的,相互独立的。但是如果多个事务操作同一批数据,则会引发一些问题,设置不同的隔离级别就可以解决这些问题。
* 存在问题:
1. 脏读:一个事务,读取到另一个事务中没有提交的数据
2. 不可重复读(虚读):在同一个事务中,两次读取到的数据不一样。
3. 幻读:一个事务操作(DML)数据表中所有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改。
* 隔离级别:
1. read uncommitted:读未提交
* 产生的问题:脏读、不可重复读、幻读
2. read committed:读已提交 (Oracle)
* 产生的问题:不可重复读、幻读
3. repeatable read:可重复读 (MySQL默认)
* 产生的问题:幻读
4. serializable:串行化
* 可以解决所有的问题
* 注意:隔离级别从小到大安全性越来越高,但是效率越来越低
* 数据库查询隔离级别:
* select @@tx_isolation;
* 数据库设置隔离级别:
* set global transaction isolation level 级别字符串;
* 演示:
set global transaction isolation level read uncommitted;
start transaction;
-- 转账操作
update account set balance = balance - 500 where id = 1;
update account set balance = balance + 500 where id = 2;
JDBC基础02
标签:font size pst 关键字 min orm color 串行 数据库