数据库连接(JDBC)
一、JDBC的概述
(一) 什么是JDBC
JDBC(java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。
(二)JDBC的本质
JDBC本质上是一种规范,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
(三)JDBC的使用
1、导入jar包
2、注册驱动
3、建立数据库连接:
4、获取语句执行者:
5、执行SQL语句,获取结果集或影响行数
7、解析结果
8、释放资源
二、JDBC的接口
(一)DriverManager
1、注册驱动:Class.forName("com.mysql.jdbc.Driver");
2、建立连接:
getConnection(String url, String user, String password);
- url------>jdbc:mysql://ip地址(域名):端口号/数据库名称
- user----->用户名
- password->密码
(二)Connection
1、获取语句执行者对象
- 获取普通执行者对象:createStatement();
- 获取预编译执行者对象:pepareStatement(String sql);
2、管理事务
- 开启事务:setAutoCommitfalse);
- 提交事务:commit();
- 回滚事务:rollback();
3、释放资源:close();
(三) Statement
1、执行DML语句:executeUpdate(String sql);
2、执行DQL语句:executeQuery(String sql);
3、释放资源:close();
sql注入安全问题
一、sql注入产生的原因
//Statement
String id = "5";
String sql = "delete from table where id=" + id;
Statement st = conn.createStatement();
st.executeQuery(sql);
//存在sql注入的危险
//如果用户传入的id为“5 or 1=1”,那么将删除表中的所有记录
//Statement对象在执行sql语句时,将密码的一部分内容当做查询条件来执行了
二、sql注入问题的解决
(一) PreparedStatement–解决SQL注入原理
在执行sql语句之前,将sql语句进行提前编译,明确sql语句的格式后,。剩余的内容都会认为是参数,参数是使用(占位符?)
(二)占位符?赋值的方法
赋值方法:setXxx(参数1,参数2);
- xxx---->数据类型
- 参数1--->?的位置编号
- 参数2--->?的实际参数
(三) PreparedStatement–执行语句
1、执行DML语句:executeUpdate();
2、执行DQL语句:executeQuery();
类与表之间关系
一、类与表关系示意图
二、执行DQL语句封装集合
1.如果结果集关闭,结果集中的数据就不能使用了。在DAO层将结果集中的数据重新封装到一个新的对象中,就可以在DAO层放心的关闭结果集,以后只需要使用重新封装的这个对象即可。
2.如果是一条记录,封装成实体类对象
3.如果是多条记录,封装成一个集合。
案例—查询多条记录
一、数据准备
(一) 数据库建表
(二) 实体类
import java.sql.Date;
public class Student {
//1.属性名与表中列名相同,如果列名是多个单词:user_name,那么属性名:userName
private int id;
private String name;
private boolean sex;
private Date birthday;
//2.提供无参和有参构造
//3.提供get/set方法
//4.重写toString方法
}
二、实现思路
1. 创建一个集合用于封装所有的记录
2. 得到连接对象
3. 得到语句对象,SQL语句没有占位符
4. 得到结果集,每次循环封装一个实体对象
5. 把封装好的实体数据放到集合中
6. 关闭连接
7. 以后使用数据,循环输出集合中实体对象
三、业务实现
public class Demo08List {
public static void main(String[] args) throws SQLException {
//1.创建连接对象
Connection connection = JdbcUtils.getConnection();
//2.创建预编译的语句对象
PreparedStatement preparedStatement = connection.prepareStatement("select * from student");
//3.执行查询操作
ResultSet resultSet = preparedStatement.executeQuery();
//4.遍历整个结果集
//创建一个集合
List<Student> students = new ArrayList<>();
while (resultSet.next()) {
//5.每条记录封装成一个学生对象
Student student = new Student();
student.setId(resultSet.getInt("id"));
student.setName(resultSet.getString("name"));
student.setBirthday(resultSet.getDate("birthday"));
student.setSex(resultSet.getBoolean("sex"));
//6.将学生对象添加到集合中
students.add(student);}
//7.释放资源,关闭连接 (结果集不可用)
JdbcUtils.close(connection,preparedStatement, resultSet);
}}
案例—用户登录
一、数据准备
-- 建表
create table user(
id int primary key auto_increment,
username varchar(20) not null unique, -- 登录名不能重复
password varchar(32) not null
);
-- 插入记录
insert into user values(null, 'Jack','123'),(null,'Rose','456');
-- 什么时候登录成功,有记录就是登录成功
select * from user where username='Jack' and password='123';
-- 什么时候登录失败,没有查到记录
select * from user where username='Newboy' and password='890';
二、实现思路
1、从控制台输入用户名和密码
2、开始登录,使用JDBC访问数据库
3、编写sql查询语句,去查询用户名和密码
4、处理结果集
5、释放资源
三、业务实现
public class Login {
public static void main(String[] args) throws SQLException {
//1.输入用户名和密码
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名:");
String username = scanner.nextLine();
System.out.println("请输入密码");
String password = scanner.nextLine();
//2.建立数据库连接
Connection connection=null;
PreparedStatement preparedStatement=null;
ResultSet resultSet=null;
//2.1 获取连接对象
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","root");
//2.2 获取预编译对象
String sql="SELECT * FROM USER WHERE username=? AND PASSWORD=?";
preparedStatement = connection.prepareStatement(sql);
//2.3 占位符替换为真实值
preparedStatement.setString(1,username);
preparedStatement.setString(2,password);
//2.4 执行sql语句
resultSet = preparedStatement.executeQuery();
//3.解析结果集
//3.1如果结果集不为空,则登录成功
if(resultSet.next()){
System.out.println("登录成功");
//3.2如果结果集 为空, 则登录失败
}else {
System.out.println("登录失败");
}}}
案例—转账功能
一、数据准备
-- 创建账户表:id,name,balance
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT, -- 主键自动增长
NAME VARCHAR(20), -- 账户名
balance INT -- 账户的余额
);
-- 添加数据:Jack和Rose各1000块
INSERT INTO account VALUES(NULL, 'Jack',1000),(NULL,'Rose',1000);
SELECT * FROM account;
-- 模拟Jack转账给Rose 200块钱的功能:
-- 至少要执行2条SQL语句
-- 1. 更新Jack账户,从Jack中减去200
-- 2. 更新Rose账户,给Rose加200块
-- 执行第1条
UPDATE account SET balance=balance-500 WHERE NAME='Jack';
-- 执行第2条,可能会出现第1条语句执行成功,第2条语句没有执行,或者执行失败的情况
UPDATE account SET balance=balance+500 WHERE NAME='Rose';
-- 查询转账后结果
SELECT * FROM account;
-- 还原2个账户的钱为1000
UPDATE account SET balance = 1000;
二、实现思路
1. 获取连接
2. 开启事务
3. 获取语句对象
4. 使用语句对象执行两次更新操作
5. 正常情况下提交事务
6. 出现异常回滚事务
7. 最后关闭资源
三、业务实现
import java.sql.*;
public class Business {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement1 = null;
PreparedStatement preparedStatement2 = null;
try {
//1.建立数据库连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
//2.开启事务
connection.setAutoCommit(false);
//3.获取预编译语句对象
//3.1 编写转账语句,执行更新操作
String sql01 = "update account set balance=balance-500 where name=?";
String sql02 = "update account set balance=balance+500 where name=?";
preparedStatement1 = connection.prepareStatement(sql01);
preparedStatement1.setString(1, "Jack");
preparedStatement1.executeUpdate();
preparedStatement2 = connection.prepareStatement(sql02);
preparedStatement2.setString(1, "Rose");
preparedStatement2.executeUpdate();
//5.提交事务
connection.commit();
//6.没有异常提示转账成功
System.out.println("转账成功");
} catch (Exception e) {
//7.事务回滚
try {
connection.rollback();
} catch (Exception e1) {
e1.printStackTrace();
}
System.out.println("转账失败");
} finally{connection.close(),preparedStatement.close}