JDBC - java语言连接数据库、完成增删改查、解决SQL注入问题(详细)
一、基本介绍从本质上来说,JDBC本质是SUN公司制定的一套接口(接口都有调用者和实现者)JDBC 接口一套interface可以在API帮助文档下 java.sql找到1.为什么面向接口编程?解耦合:降低程序的耦合度,提高程序的扩展力。(多态机制是非常典型的面向抽象编程)2、JDBC编程六部概述背过!!!!!!!!!!!!!!!!!(1)注册驱动(告诉java程序,告诉java程序即将要连接的是
目录
3.对比PreparedStatement与Statement
五、PreparedStatement完成增删改以及模糊查询
一、基本介绍
从本质上来说,JDBC本质是SUN公司制定的一套接口(接口都有调用者和实现者)
JDBC 接口一套interface可以在API帮助文档下 java.sql找到
1.为什么面向接口编程?
解耦合:降低程序的耦合度,提高程序的扩展力。
(多态机制是非常典型的面向抽象编程)
2、JDBC编程六部概述
背过!!!!!!!!!!!!!!!!!
(1)注册驱动(告诉java程序,告诉java程序即将要连接的是哪个品牌的数据库)
例子:
方法1:
// 1.注册驱动
// 前后Driver不是同一个Driver
// Driver driver 是java.sql包下的
Driver driver = new com.mysql.cj.jdbc.Driver();
DriverManager.registerDriver(driver);
方法二: 常用
public class JDBCTest03 {
public static void main(String[] args) {
try {
// 1.注册驱动 这种经常使用
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Class.forName()会导致类的加载,类加载之后,静态代码块就会执行,我们可以从下图中可以看到,在静态代码块中,我们的驱动就new了,就创建了(这个地方很巧妙)
(2)获取连接(表示JVM的进程和数据库进程之间的通道打开了,属于进程之间的通信,使用完要关闭)
例子:
// 2.获取连接
String url="jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT";
String username="root";
String password="admin";
Connection conn = DriverManager.getConnection(url,username,password);
(3)获取数据库操作对象(专门执行SQL语句的对象)
例子:
// 3.获取数据库操作对象(专门执行SQL语句)
Statement statement= conn.createStatement();
(4)执行SQL语句(DQL、DML等)
例子:
// 4.执行SQL语句
String sql = "insert into t_book(id,bookName,statue,type) value(44,44,44,44)";
// 专门执行DML语句(增删改)
// 返回值是“影响数据库中的影响条数”
int count = statement.executeUpdate(sql);
(5)处理查询结果集(只有当第四步执行的是select语句的时候,才执行第五步,否则不执行)
(6)释放资源(使用完资源之后一定要关闭资源。java和数据库属于进程间的通信,开启后一定要关闭)
为了保证资源一定释放,要在finally代码块中关闭资源, 按照从小到大依次关闭
二、使用JDBC完成增删改查操作
1.完成简单 增加 操作
import java.sql.*;
public class JDBCConnection {
public static void main(String[] args) {
Connection conn =null;
Statement statement=null;
try {
// 1.注册驱动
Driver driver = new com.mysql.cj.jdbc.Driver();
DriverManager.registerDriver(driver);
// 2.获取连接
String url="jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT";
String username="root";
String password="admin";
conn = DriverManager.getConnection(url,username,password);
// 3.获取数据库操作对象(专门执行SQL语句)
statement= conn.createStatement();
// 4.执行SQL语句
String sql = "insert into t_book(id,bookName,statue,type) value(44,44,44,44)";
// 专门执行DML语句(增删改)
// 返回值是“影响数据库中的影响条数”
int count = statement.executeUpdate(sql);
System.out.println("sql命令影响数据库条数:"+count);
// 5.处理查询结果集,因为我们没有执行查询操作,所以第五步省略
} catch (SQLException e) {
e.printStackTrace();
}finally {
// 6.释放资源
// 为了保证资源一定释放,要下载finally代码块中关闭资源
// 按照从小到大依次关闭
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
2.完成简单 删除 操作
import java.sql.*;
public class JDBCTest02 {
public static void main(String[] args) {
Connection conn =null;
Statement statement=null;
try {
// 1.注册驱动
Driver driver = new com.mysql.cj.jdbc.Driver();
DriverManager.registerDriver(driver);
// 2.获取连接
String url="jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT";
String username="root";
String password="admin";
conn = DriverManager.getConnection(url,username,password);
// 3.获取数据库操作对象(专门执行SQL语句)
statement= conn.createStatement();
// 4.执行SQL语句
String sql = "delete from t_book where id=44";
// 专门执行DML语句(增删改)
// 返回值是“影响数据库中的影响条数”
int count = statement.executeUpdate(sql);
System.out.println("sql命令影响数据库条数:"+count);
// 5.处理查询结果集,因为我们没有执行查询操作,所以第五步省略
} catch (SQLException e) {
e.printStackTrace();
}finally {
// 6.释放资源
// 为了保证资源一定释放,要下载finally代码块中关闭资源
// 按照从小到大依次关闭
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
3.完成简单 更新 操作
import java.sql.*;
public class JDBCTest02 {
public static void main(String[] args) {
Connection conn =null;
Statement statement=null;
try {
// 1.注册驱动
Driver driver = new com.mysql.cj.jdbc.Driver();
DriverManager.registerDriver(driver);
// 2.获取连接
String url="jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT";
String username="root";
String password="admin";
conn = DriverManager.getConnection(url,username,password);
// 3.获取数据库操作对象(专门执行SQL语句)
statement= conn.createStatement();
// 4.执行SQL语句
String sql = "update t_book set id=44 where id=33 ";
// 专门执行DML语句(增删改)
// 返回值是“影响数据库中的影响条数”
int count = statement.executeUpdate(sql);
System.out.println("sql命令影响数据库条数:"+count);
// 5.处理查询结果集,因为我们没有执行查询操作,所以第五步省略
} catch (SQLException e) {
e.printStackTrace();
}finally {
// 6.释放资源
// 为了保证资源一定释放,要下载finally代码块中关闭资源
// 按照从小到大依次关闭
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
4.完成简单的查询操作
import java.sql.*;
import java.util.ResourceBundle;
public class JDBCTest05 {
public static void main(String[] args) {
// 使用资源绑定器绑定属性配置文件
ResourceBundle bundle = ResourceBundle.getBundle("application");
String driver=bundle.getString("driver");
String url = bundle.getString("url");
String user = bundle.getString("user");
String password =bundle.getString("password");
Connection conn =null;
Statement statement=null;
ResultSet rs = null;
try {
// 1.注册驱动 这种经常使用
Class.forName(driver);
// 2.获取连接
conn = DriverManager.getConnection(url,user,password);
// 3.获取数据库操作对象(专门执行SQL语句)
statement= conn.createStatement();
// 4.执行SQL语句
String sql = "select id,bookName,statue,type from t_book";
// 返回值是“影响数据库中的影响条数”
// 专门执行DQL语句的方法
rs = statement.executeQuery(sql);
// 5.处理查询结果集,因为我们没有执行查询操作,所以第五步省略
while(rs.next()){
/*// getString()方法特点:不管数据库中的数据类型是什么,都以String形式取出
String id = rs.getString(1); //数据库表中的第一列
String bookName = rs.getString(2);//数据库表中的第二列
String statue = rs.getString(3);//数据库表中的第三列
String type = rs.getString(4);//数据库表中的第四列*/
// 下面是用方法中的参数是 查询语句中的想要查找的那列的名称,这个地方不需要和数据库中的字段名对应
// 而在select语句中,所查询的字段名要和数据库中的字段名进行对应
String id = rs.getString("id");
String bookName = rs.getString("bookName");
String statue = rs.getString("statue");
String type = rs.getString("type");
// 这个地方的数据不仅仅String
// int id = rs.getInt("id");
// double id = rs.getDouble("id");
System.out.print(id+" ");
System.out.print(bookName+" ");
System.out.print(statue+" ");
System.out.println(type+" ");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
// 6.释放资源
// 为了保证资源一定释放,要下载finally代码块中关闭资源
// 按照从小到大依次关闭
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
先了解处理结果集
三、从属性资源文件中读取连接到数据库
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;
public class JDBCTest03 {
public static void main(String[] args) {
// 使用资源绑定器绑定属性配置文件
ResourceBundle bundle = ResourceBundle.getBundle("application");
String driver=bundle.getString("driver");
String url = bundle.getString("url");
String user = bundle.getString("user");
String password =bundle.getString("password");
Connection conn =null;
Statement statement=null;
try {
// 1.注册驱动 这种经常使用
Class.forName(driver);
// 2.获取连接
conn = DriverManager.getConnection(url,user,password);
// 3.获取数据库操作对象(专门执行SQL语句)
statement= conn.createStatement();
// 4.执行SQL语句
String sql = "update t_book set id=33 where id=44 ";
// 专门执行DML语句(增删改)
// 返回值是“影响数据库中的影响条数”
int count = statement.executeUpdate(sql);
System.out.println("sql命令影响数据库条数:"+count);
// 5.处理查询结果集,因为我们没有执行查询操作,所以第五步省略
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
// 6.释放资源
// 为了保证资源一定释放,要下载finally代码块中关闭资源
// 按照从小到大依次关闭
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
四、解决SQL注入问题
1.演示SQL注入问题
我们可以看下面的一段登录验证代码:
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class JDBCTest06 {
public static void main(String[] args) {
// 初始化一个界面
Map<String,String> userLoginInfo = initUI();
// 验证用户名和密码
Boolean loginSuccess = login(userLoginInfo);
// 最后输出结果
System.out.println(loginSuccess ? "登录成功.":"登录失败.用户名或密码错误.");
}
// 编写JDBC代码
private static Boolean login(Map<String, String> userLoginInfo) {
Boolean loginSuccess =false;
String userName =userLoginInfo.get("userName");
String password =userLoginInfo.get("password");
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2.获取连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT","root","admin");
// 3.获取数据库操作对象
stmt = conn.createStatement();
// 4.执行SQL语句
String sql ="select * from t_student where userName='"+userName+"' and password= '"+password+"' ";
rs=stmt.executeQuery(sql);
if(rs.next()){
// 登陆成功
loginSuccess = true;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn !=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return loginSuccess;
}
// 初始化用户界面(通过控制带接受用户信息),返回登陆者的用户名和密码
private static Map<String, String> initUI() {
Scanner s = new Scanner(System.in);
System.out.print("用户名:");
String userName = s.nextLine(); //一读读一行
System.out.print("密码:");
String password = s.nextLine();
Map<String,String> userLoginInfo = new HashMap<>();
userLoginInfo.put("password", password);
userLoginInfo.put("userName", userName);
return userLoginInfo;
}
}
我们发现,只要按照上面的格式输入,即是我们数据库中不存在这一组用户名和密码,依然可以登陆成功,这就是SQL注入的问题
2.解决SQL注入问题
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class JDBCTest06 {
public static void main(String[] args) {
// 初始化一个界面
Map<String,String> userLoginInfo = initUI();
// 验证用户名和密码
Boolean loginSuccess = login(userLoginInfo);
// 最后输出结果
System.out.println(loginSuccess ? "登录成功.":"登录失败.用户名或密码错误.");
}
// 编写JDBC代码
private static Boolean login(Map<String, String> userLoginInfo) {
Boolean loginSuccess =false;
String userName =userLoginInfo.get("userName");
String password =userLoginInfo.get("password");
Connection conn = null;
PreparedStatement ps=null;//预编译操作对象
ResultSet rs = null;
try {
// 1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2.获取连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT","root","admin");
// 3.获取预编译的数据库操作对象
String sql ="select * from t_student where userName=? and password=?"; //这是SQL语句框架
// ? 是占位符 一个?代表一个值
ps = conn.prepareStatement(sql);
// 给占位符传值(第一个?是1,第二个时2,下标从1开始)
ps.setString(1,userName);
ps.setString(2,password);
// 4.执行SQL语句
rs=ps.executeQuery();
// 5.处理结果集
if(rs.next()){
// 登陆成功
loginSuccess = true;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(ps!=null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn !=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return loginSuccess;
}
// 初始化用户界面(通过控制带接受用户信息),返回登陆者的用户名和密码
private static Map<String, String> initUI() {
Scanner s = new Scanner(System.in);
System.out.print("用户名:");
String userName = s.nextLine(); //一读读一行
System.out.print("密码:");
String password = s.nextLine();
Map<String,String> userLoginInfo = new HashMap<>();
userLoginInfo.put("password", password);
userLoginInfo.put("userName", userName);
return userLoginInfo;
}
}
3.对比PreparedStatement与Statement
五、PreparedStatement完成增删改以及模糊查询
增:
删:
改:
模糊查询:
六、JDBC事务机制
JDBC事物机制: JDBC中的事物是自动提交的,只要执行一条DML语句,就自动提交一次(这是JDBC默认的事物行为)
但是在实际的业务中,通常都是N条DML语句共同联合才能够完成,必须保证这些DML语句在同一个事物中同时成功或同时失败
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)