JDBC学习总结

JDBC学习过程:
01JDBC-更新数据
02JDBC-查询数据
03JDBC-DBUtil
04JDBC-事务
05JDBC-事务锁
06JDBC-SQL注入攻击

01JDBC-更新数据
A、加载驱动
Class.forName("com.mysql.jdbc.Driver");
B、获取数据库链接
Connection connection = DBUtil.getConnect();
C、创建sql容器,加载sql语句
String sql = "insert into t_user(id,name) values(?,?,?)";
PreparedStatement prepareStatement = connection.prepareStatement(sql);
D、填充sql语句中的问号
prepareStatement.setLong(1,user.getId());
prepareStatement.setString(2,user.getName());
E、执行sql语句
prepareStatement.executeUpdate();
G、提交事务
connection.commit;
H、关闭数据库资源
DBUtil.close(prepareStatement, connection);
/*
1、B中出现的DBUtil值一个数据库链接的工具包
2、C中只是一个具体的例子,并不是只局限于插入操作
3、D中setLong中的Long是基本数据类型,它是由该方法的第二个参数类型确定
- 参数1表表示第几个问号
- 参数2表示向问号中输入的具体数据
4、
*/

02JDBC-查询数据
A、加载驱动
Class.forName("com.mysql.jdbc.Driver");
B、获取数据库链接
Connection connection = DBUtil.getConnect();
C、创建sql容器,加载sql语句
String sql = "select * from t_user where id=?";
PreparedStatement prepareStatement = connection.prepareStatement(sql);
D、填充sql语句中的问号
prepareStatement.setLong(1,id);
E、执行sql语句
ResultSet resultSet = prepareStatement.executeQuery();
G、处理查询结果
while(resultSet.next()){
resultSet.getInt("id");
resultSet.getString("name");
}
G、提交事务
connection.commit;
H、关闭数据库资源
DBUtil.close(prepareStatement, connection);

03JDBC-DBUtil
public class DBUtil {
private static final String URL = "jdbc:mysql://127.0.0.1:3306/test2";
private static final String user = "root";
private static final String passwd = "root";

//1 加载驱动
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

//2 获取数据库链接
public static Connection getConnect(){
Connection connection = null;
try {
connection = DriverManager.getConnection(URL,user,passwd);
connection.setAutoCommit(false); //设置为手动提交事务
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return connection;
}

//3 关闭数据库资源
public static void close(PreparedStatement preparedStatement, Connection connection){
DBUtil.close(null,preparedStatement,connection);
}

public static void close(ResultSet resultSet, PreparedStatement preparedStatement, Connection connection){
if (resultSet != null)
{
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (preparedStatement != null)
{
try {
preparedStatement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection != null)
{
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}

04JDBC-事务

如果 connection 调用方法 setAutoCommit 并设置为手动提交
connectio.setAutoCommit(false); //true 为自动 false 为手动

那么在sql语句执行处理之后,必须提交事务
connection.commit();
或者出现异常会滚事务:
connection.rollback();

05JDBC-事务锁


事务锁:

当数据库执行修改语句时,会默认添加一个事务锁,
如果我们的修改条件是索引字段,那么数据库会添加一个行级锁, 【目前索引字段就认为是主键和外键】
如果修改的条件不是索引,那么数据库会添加一个表级锁
行级锁会锁住被修改的记录,不允许其他的线程(事务),在当前事务提交或回滚之前来对数据进行修改
表级锁会锁柱当前表中所有的记录,不允许其他的线程(事务),在当前事务提交或回滚之前来对数据进行修改

因此修改数据时尽量使用主键作为唯一的条件

数据库不仅可以使用update添加锁,也可以使用查询语句添加锁
select * from 表名 where ... for update
在普通的查询语句中添加for update就可以为语句添加一个锁
如果查询语句的where条件使用索引那么就是行级锁
如果查询语句的where条件使用的是普通的字段,那么就是一个表级锁

注意:无论是update还是select语句添加的锁,锁的释放时机以及加锁的时机都是一样的

加锁的时机是,在执行sql语句时直接加锁
释放锁的时机,在事务提交或回滚以后才会释放锁

例如:在数据库中操作

行级锁:

A控制台
start transaction; //打开事务机制
update t_user set name='lisi' where id=22;

B控制台
update t_user set name='王五' where id=22;

总结:因为id是主键,所以A控制台执行sql语句,并且没有提交事务(commit;)
那么id=22那一行记录就被锁定成行级锁
所以B控制台修改该条记录失败

表级锁:

A控制台
start transaction; //打开事务机制
update t_user set name='lisi' where user_name='root';

B控制台
update t_user set name='王五' where id=23;
update t_user set name='王五' where id=23;


总结:因为user_name不是主键,也不是索引项,所以A控制台执行sql语句,并且没有提交事务(commit;)
那么此时该表被锁定成表级锁
所以B控制台无法修改表中任何记录

06JDBC-SQL注入攻击

PreparedStatement 是预编译的,语句中使用?作占位符,需要后期单独动态的为?赋值,
由于使用的是预编译,因此SQL语句指挥预编译一次
然后动态为?赋值即可,它的速度快,而且可以避免SQL注入攻击

Statement 是字符拼接的,所有的语句参数都需要使用字符拼接的方式拼接到SQL中,因此每次编译的SQL都不一样,
所以每次执行SQL语句都需要编译
它的速度慢,而且容易导致SQL的注入攻击




 

posted @ 2021-02-25 14:56  陌上尘如玉  阅读(90)  评论(0)    收藏  举报