jdbc - 210321 - 01
- 了解JDBC
- JDBC编程
- JDBC编程步骤 连接方法01/02
- 从资源文件读取数据库配置参数
- 处理查询结果集
- 登录实例(sql注入)
- 预编译处理
- 事务机制
JDBC了解
什么是JDBC
Java DataBase Connective(Java语言连接数据库)
JDBC的本质是什么
JDBC是SUN公司指定的一套接口(interface)
java.sql.*; 这个包下的接口
接口都有调用者和实现者。
面向接口调用,面向接口写实现类,这都属于面向接口编程
为什么要面向接口编程:
解耦合,降低程序的耦合性,提高程序的扩展性
多态机制就是典型的面向抽象编程
JDBC的本质实则就是------>一套接口
每个数据库的底层实现原理都是不一样的,
所以SUN公司制定了JDBC这样的一套接口,用来规范,方便了程序员开发

JDBC编程
JDBC编程步骤
1. 注册驱动 (告诉Java程序,要连接哪个数据库)
2. 获取连接 (表示JVM的进程和数据库之间的进程打开了,这属于进程之间的通信,使用完要关闭资源)
3. 获取数据操作对象 (用来执行SQL语句)
4. 执行SQL语句 (DQL,DML...)
5. 处理查询结果集 (只有第4步执行的是select语句的时候,才会使用到这第5步处理查询结果集)
6. 释放资源 (使用完资源一定要关闭,Java和数据库属于进程间的通信,开启之后一定要关闭)
url: 统一资源定位符
url组成部分:
协议
ip
port 端口号
资源名
一下两个都是百度
https://www.baidu.com/
http://110.242.68.3:80/index.html
http:// 通信协议
110.242.68.3 服务器IP地址
index.html 服务器上的某个资源名
连接方法01
/*
这是jar包为mysql-connector-java-5.1.25-bin的,,
我的jar包为mysql-connector-java-8.0.22
我的8版本的不能运行此代码,,但是5版本的能,
因为我的数据库也是mysql-8.0.22-winx64,,,对应着jar包为mysql-connector-java-8.0.22
*/
import com.mysql.jdbc.Driver;
import java.sql.*;
public class Demo02 {
private static final String URL1 = "jdbc:mysql://localhost:3306/test";
private static final String ROOT = "root";
private static final String PASSWORD = "admin";
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
try {
// 1. 注册驱动
Driver driver = new com.mysql.jdbc.Driver();
DriverManager.registerDriver(driver);
// 2.连接数据库
conn = DriverManager.getConnection(URL1,ROOT,PASSWORD);
System.out.println(conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
连接方法02
import java.sql.*;
public class Demo01 {
private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String URL1 = "jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC";
private static final String ROOT = "root";
private static final String PASSWORD = "admin";
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
try{
// 1.注册驱动
Class.forName(DRIVER);
// 2.获取连接
conn = DriverManager.getConnection(URL1,ROOT,PASSWORD);
// 输出连接对象
System.out.println(conn); //com.mysql.cj.jdbc.ConnectionImpl@51081592
// 3.获取数据库操作对象
stmt = conn.createStatement();
// 4.执行SQL语句
String insersql = "insert into student(name,sex,address) values('张三','男','Chain')";
String updatesql = "update student set name='lisi' , address='henan' where id=5";
String deletesql = "delete from student where id=6";
int count1 = stmt.executeUpdate(insersql);
int count2 = stmt.executeUpdate(updatesql);
int count3 = stmt.executeUpdate(deletesql);
System.out.println(count1 == 1 ? "添加成功":"添加失败");
System.out.println(count2 == 1 ? "修改成功":"修改失败");
System.out.println(count3 == 1 ? "删除成功":"删除失败");
// 5.处理查询结果集
}catch (SQLException e){
e.printStackTrace();
}catch (Exception e){
e.printStackTrace();
}finally {
// 6.释放资源
try {
if(stmt != null){
stmt.close();
}
}catch (SQLException e){
e.printStackTrace();
}
try {
if(conn != null){
conn.close();
}
}catch (SQLException e){
e.printStackTrace();
}
}
}
}
从资源文件读取参数
import java.sql.*;
import java.util.ResourceBundle;
public class Demo03 {
// 从 jdbc.properties 文件中读取资源
static ResourceBundle rb = ResourceBundle.getBundle("jdbc");
static String driver = rb.getString("driver");
static String url = rb.getString("url");
static String user = rb.getString("user");
static String password = rb.getString("password");
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
try{
// 1.注册驱动
Class.forName(driver);
// 2.获取连接
conn = DriverManager.getConnection(url,user,password);
// 输出连接对象
System.out.println(conn); //com.mysql.cj.jdbc.ConnectionImpl@51081592
// 3.获取数据库操作对象
stmt = conn.createStatement();
// 4.执行SQL语句
String updatesql = "update student set name='lisi' , address='henan' where id=5";
int count2 = stmt.executeUpdate(updatesql);
System.out.println(count2 == 1 ? "修改成功":"修改失败");
// 5.处理查询结果集
}catch (SQLException e){
e.printStackTrace();
}catch (ClassNotFoundException e){
e.printStackTrace();
}finally {
// 6.释放资源
try {
if(stmt != null){
stmt.close();
}
}catch (SQLException e){
e.printStackTrace();
}
try {
if(conn != null){
conn.close();
}
}catch (SQLException e){
e.printStackTrace();
}
}
}
}
jdbc.properties
driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC
user = root
password = admin
#jdbc.properties
处理查询结果集

import java.sql.*;
public class Demo04 {
public static void main(String[] args) {
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/test?&useSSL=false&serverTimezone=UTC","root","admin");
// 3.获取数据操作对象
stmt = conn.createStatement();
// 4.执行SQL语句
// int executeUpdate(sql) sql语句是insert,delete,update,,,返回一个int类型
// ResultSet executeQuery(sql) sql语句是select,,,返回一个ResultSet类型
String sql = "select id,name,sex,address from student";
rs = stmt.executeQuery(sql); //执行DQL语句
// 5.返回结果集
// 5.1
// 光标所有行数据
// 根据下标找数据,,,1,2,3 代表数据库表中的类,,,数据库中的下标从1开始
// getString(),,,方法不管从数据库中取出什么类型的数据,都以String类型返回
// boolean flag = rs.next();
// if(flag){
// String name = rs.getString(1);
// String sex = rs.getString(2);
// String address = rs.getString(3);
// System.out.println(name + " " + sex + " " + address);
// }
// flag = rs.next();
// if(flag){
// String name = rs.getString(1);
// String sex = rs.getString(2);
// String address = rs.getString(3);
// System.out.println(name + " " + sex + " " + address);
// }
// while (rs.next()){
// String name = rs.getString(1);
// String sex = rs.getString(2);
// String address = rs.getString(3);
// System.out.println(name + " " + sex + " " + address);
// }
// 5.2
// 根据数据库的列明找数据
while (rs.next()){
// 取出特定类型的数据
int id = rs.getInt("id");
String name = rs.getString("name");
String sex = rs.getString("sex");
String address = rs.getString("address");
System.out.println(id + " " + name + " " + sex + " " + address);
}
}catch (ClassNotFoundException e){
e.printStackTrace();
}catch (SQLException e){
e.printStackTrace();
}finally {
// 6.关闭资源
try{
if(rs != null){
rs.close();
}
}catch (SQLException e){
e.printStackTrace();
}
try {
if(stmt != null){
stmt.close();
}
}catch (SQLException e){
e.printStackTrace();
}
try {
if(conn != null){
conn.close();
}
}catch (SQLException e){
e.printStackTrace();
}
}
}
}
登录实例(sql注入)
/**
* Statement存在sql注入问题
请输入登录名:
111
请输入密码:
111' or '1'='1
登录成功
导致sql注入问题:
用户输入的信息中,含有sql语句关键字,,,
并且在编译sql时,编译了进去,从而导致sql语句失去原来的含义
*/
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class Demo01 {
public static void main(String[] args) {
// 接收页面用户登录信息
Map<String , String> userLoginInfo = intiUI();
boolean loginIsSuccess = login(userLoginInfo);
System.out.println(loginIsSuccess ? "登录成功":"登录失败");
}
/**
* 初始化用户登录界面
* @return 返回一个Map类型的数组,用来保存用户数据的登录信息
*/
private static Map<String, String> intiUI() {
Scanner s = new Scanner(System.in);
System.out.println("请输入登录名:");
String loginName = s.nextLine();
System.out.println("请输入密码:");
String loginPwd = s.nextLine();
Map<String,String> loginInfo = new HashMap<>();
loginInfo.put("loginName",loginName);
loginInfo.put("loginPwd",loginPwd);
return loginInfo;
}
/**
*
* @param userLoginInfo
* @return 返回一个boolean,用来判断数据库中的数据和userLoginInfo是否一致
*/
private static boolean login(Map<String, String> userLoginInfo) {
boolean flag = false;
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 获取连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC","root","admin");
// 获取数据库操作对象
stmt = conn.createStatement();
// 执行sql语句
/*
以下语句完成了sql语句拼接,发送sql语句给DBMS,DBMS进行编译
正好将用户提供的,,非法信息,,编译进去,,导致原来sql语句含义被扭曲
*/
String sql = "select * from t_user where loginname='"+userLoginInfo.get("loginName")+"' and loginpwd='"+userLoginInfo.get("loginPwd")+"'";
rs = stmt.executeQuery(sql);
// 处理结果集
if(rs.next()){
flag = 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 flag;
}
}
预编译处理(PreparedStatement)
/*
解决SQL注入问题:
只要用户体统的信息不参与SQL语句的编译过程,就OK
所以要是用PreparedStatement
PreparedStatement接口继承了java.sql.Statement
PreparedStatement是属于预编译数据库操作对象
PreparedStatement原理是,,预先对sql语句的框架进行编译,然后宰割sql语句传值
Statement 和 PreparedStatement :
Statement存在sql注入问题,,PreparedStatement解决了sql注入问题
Statement是编译一次执行一次,,PreparedStatement是编译一次,可执行多次,,PreparedStatement效率高
PreparedStatement在编译阶段做类型安全检查
Statement也不是没有用,,如果业务方面必须要sql注入时,就必须是Statement
*/
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class Demo02 {
public static void main(String[] args) {
// 页面初始化,接收用户信息
Map<String,String> userLoginInfo = initUI();
// 验证用户信息
boolean isSucceedLogin = login(userLoginInfo);
System.out.println(isSucceedLogin ? "登录成功":"登录失败");
}
private static boolean login(Map<String, String> userLoginInfo) {
boolean flag = false;
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
String driver = "com.mysql.cj.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC";
String user = "root";
String password = "admin";
try {
// 注册驱动
Class.forName(driver);
// 获取连接
conn = DriverManager.getConnection(url,user,password);
// 获取预编译操作对象
String sql = "select * from t_user where loginname=? and loginpwd=?";
ps = conn.prepareStatement(sql);
ps.setString(1,userLoginInfo.get("loginName")); // 数字1,,代表第一个?
ps.setString(2,userLoginInfo.get("loginPwd")); // 数字2,,代表第二个?
// 执行sql语句
rs = ps.executeQuery();
// 处理结果
if(rs.next()){
flag = 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 flag;
}
private static Map<String, String> initUI() {
Scanner scanner = new Scanner(System.in);
System.out.println("please input you loginNumber:");
String loginName = scanner.nextLine();
System.out.println("please input you loginPassword:");
String loginPwd = scanner.nextLine();
Map<String , String> userLoginInfo = new HashMap<>();
userLoginInfo.put("loginName",loginName);
userLoginInfo.put("loginPwd",loginPwd);
return userLoginInfo;
}
}
PreparedStatement增删改
package bgy02;
import java.sql.*;
public class Demo03 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
int count = 0;
String driver = "com.mysql.cj.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC";
String user = "root";
String password = "admin";
try {
// 注册驱动
Class.forName(driver);
// 连接数据库
conn = DriverManager.getConnection(url,user,password);
// 预编译sql语句
// 添加
// String sql = "insert into t_user (id,loginname,loginpwd) values(?,?,?)";
// ps = conn.prepareStatement(sql);
// ps.setInt(1,10);
// ps.setString(2,"hhh");
// ps.setString(3,"hhh");
// 修改
// String sql = "update t_user set loginname=? ,loginpwd=? where id=?";
// ps = conn.prepareStatement(sql);
// ps.setString(1,"hhh01");
// ps.setString(2,"hhh01");
// ps.setInt(3,10);
// 删除
String sql = "delete from t_user where id=?";
ps = conn.prepareStatement(sql);
ps.setInt(1,10);
// 执行sql语句
count = ps.executeUpdate();
System.out.println(count);
System.out.println(count == 1 ? "操作成功":"操作失败");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e){
e.printStackTrace();
}finally {
if(ps != null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
事务机制
JDBC事务机制:
JDBC中的事务是自动提交的。只要执行任意一条DML语句,则提交一次,这是JDBC默认的事务行为。
在实际的业务当中,通常是N条DML语句共同联合才能完成的,必须要保证他们这些DML语句在同一个事务中同 时成功或同时失败
失败Demo
package bgy02;
import java.sql.*;
public class Demo04 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
int count = 0;
String driver = "com.mysql.cj.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC";
String user = "root";
String password = "admin";
try {
// 1.
Class.forName(driver);
// 2.
conn = DriverManager.getConnection(url,user,password);
// 3.
String sql = "update t_act set balance=? where actno=?";
ps = conn.prepareStatement(sql);
// 传值
ps.setInt(1,10000);
ps.setInt(2,111);
count = ps.executeUpdate();
// 这个会抛出异常,,,以至于不会执行下面的程序,,到这就直接结束了
String s =null;
s.toString();
/*
会造成数据的丢掉
*/
// 传值
ps.setInt(1,10000);
ps.setInt(2,222);
count += ps.executeUpdate();
System.out.println(count == 2 ? "转账成功":"转账失败");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e){
e.printStackTrace();
}finally {
if(ps != null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
运行前:

运行后:

报错:

解决
/*
三步:
conn.setAutoCommit(false);
conn.commit();
if(conn != null){
try{
conn.rollback();
}catch (SQLException e1){
e1.printStackTrace();;
}
}
*/
import java.sql.*;
public class Demo05 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
int count = 0;
String driver = "com.mysql.cj.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC";
String user = "root";
String password = "admin";
try {
// 1.
Class.forName(driver);
// 2.
conn = DriverManager.getConnection(url,user,password);
// 将 ‘自动提交机制’ 修改为 ‘手动提交’
// 将 ‘自动提交机制’ 修改为 ‘手动提交’
// 将 ‘自动提交机制’ 修改为 ‘手动提交’
// 开启事务
// 开启事务
// 开启事务
conn.setAutoCommit(false);
// 3.
String sql = "update t_act set balance=? where actno=?";
ps = conn.prepareStatement(sql);
// 传值
ps.setInt(1,10000);
ps.setInt(2,111);
count = ps.executeUpdate();
String s =null;
s.toString();
/*
会造成数据的丢掉
*/
// 传值
ps.setInt(1,10000);
ps.setInt(2,222);
count += ps.executeUpdate();
System.out.println(count == 2 ? "转账成功":"转账失败");
// 程序能走到这,说明上面程序没异常,事务结束,手动提交数据
// 程序能走到这,说明上面程序没异常,事务结束,手动提交数据
// 程序能走到这,说明上面程序没异常,事务结束,手动提交数据
// 提交事务
// 提交事务
// 提交事务
conn.commit();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e){
e.printStackTrace();
} catch (Exception e){
// 回滚事务,,,,就是出了异常的话就,,数据恢复
// 回滚事务,,,,就是出了异常的话就,,数据恢复
// 回滚事务,,,,就是出了异常的话就,,数据恢复
if(conn != null){
try{
conn.rollback();
}catch (SQLException e1){
e1.printStackTrace();;
}
}
}finally {
if(ps != null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}