Day 37 学习分享 - JDBC入门

1. JDBC 概念
JDBC: 
	Java Data Base Connectivity - Java数据库连接技术
	这是一种用于执行SQL语句的Java API, 可以为多种关系数据库提供统一的访问, 是SUN公司提供的一套连接并操作数据库的技术.
	
使用要求:
	JDBC需要连接驱动:
		我们操作数据库是在控制台使用SQL语句来操作
		而JDBC是用Java语言向数据库发送SQL语句,帮助我们完成执行数据库的操作.

注意:
	JDBC连接不同的数据库, 需要导入不同的数据库驱动包!
2. JDBC工作原理

在这里插入图片描述

3. JDBC初步应用示例
3.1 创建表并新增数据
-- 创建数据库
create database singerdb;

-- 使用数据库
use singerdb;

-- 创建数据库表
create table singer(
  id int(4) primary key auto_increment,
  name VARCHAR(20),
  age int(3),
  birthday date,
  works VARCHAR(50) not null,
  sex char(1),
  idcard VARCHAR(20) not null UNIQUE
);

-- 使用数据库
use singerdb;

-- 新增几条测试数据
INSERT into singer values (null,'汪峰',50,'2010-10-10','飞得更高','男','34535434535675467567');
INSERT into singer values (null,'杰伦',50,'2010-10-20','双杰伦','男','345354345356754673');
INSERT into singer values (null,'哈林',56,'2010-11-10','情非得已','男','3453543453567543');
INSERT into singer values (null,'娜姐',60,'2010-10-13','征服','女','345354345356754676');
3.2 将mysql驱动包导入当前工程当中

在这里插入图片描述

3.3 完成程序编译
public class Demo1 {

	public static void main(String[] args) {

		Connection conn = null; // 数据库的连接对象,获取到这个对象 表示连接上数据库了
		Statement st = null; // 执行SQL语句的对象
		ResultSet rs = null; // SQL语句的查询结果集对象

		try {
			// 1.加载驱动 放入Mysql驱动类的全路径,让JVM预先加载这个类到内存中
			Class.forName("com.mysql.jdbc.Driver");

			// 2.获取数据库连接,三个参数: 1.连接字符串 2.数据库账号 3.密码
			// jdbc:mysql://127.0.0.1:3306/singerdb?useUnicode=true&characterEncoding=utf-8
			conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/singerdb?useUnicode=true&characterEncoding=utf-8", "root", "123");

			// 3.获取执行SQL对象
			st = conn.createStatement();

			// 4.执行SQL(查询) 并获得结果
			String sql = "SELECT * FROM singer";
			rs = st.executeQuery(sql);

			// 4.1 显示结果集中的数据(遍历结果集对象)
			System.out.println("编号\t姓名\t年龄\t生日\t作品\t性别\t身份证号");
			while (rs.next()) {
				int id = rs.getInt("ID"); // 表中字段不区分大小写,根据列名获取对应的值
				String name = rs.getString("NAME");
				int age = rs.getInt("AGE");
				String birthday = rs.getString("BIRTHDAY");
				String works = rs.getString("WORKS");
				String sex = rs.getString("SEX");
				String idcard = rs.getString("IDCARD");
				System.out.println(id+"\t"+name+"\t"+age+"\t"+birthday+"\t"+works+"\t"+sex+"\t"+idcard);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			//5. 关闭流
			try {
				if(rs!=null){
					rs.close();
				}
				if(st!=null){
					st.close();
				}
				if(conn!=null){
					conn.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}
4. JDBC API详解
4.1 DriverManager类
	DriverManager是驱动管理类, JDBC程序中DriverManager用于加载驱动并创建与数据库的连接.
	获取DriverManager方式:
		Class.forName("com.mysql.jdbc.Driver");
	此方法会将com.mysql.jdbc.Driver中的静态代码块执行, 实现驱动的注册, 将指定的类加载到内存中.
	
	DriverManager.getConnection(url, user, password);
	url: 连接到某一个具体的数据库, 通过URL地址告诉JDBC程序需要连接哪个数据库
	URL写法如下:
		jdbc:mysql://localhost:3306/test?参数名:参数值
		协议:子协议://       主机:端口/数据库
	user: 
		数据库用户名
	password: 
		数据库用户名对应的密码
	此方法会返回一个Connection类对象, 并将建立到给定数据库URL的连接.
	常用属性:
		useUnicode=true&characterEncoding=UTF-8
    作用:
    	解决入库乱码问题
    url最终格式:
    	jdbc:mysql://主机IP:端口/库名?useUnicode=true&characterEncoding=UTF-8
4.2 Connection类
作用:
	用于代表数据库的链接, Collection是数据库编程中最重要的一个对象, 客户端与数据库所有交互都是通过connection对象完成的
	
常用API:
	createStatement();
		创建向数据库发送sql的statement对象
		
	prepareStatement(sql);
		创建向数据库发送预编译sql的PrepareSatement对象
		
	prepareCall(sql);
		创建执行存储过程的callableStatement对象
		
	setAutoCommit(boolean autoCommit);
		设置事务是否自动提交
		
	commit();
		在链接上提交事务
		
	rollback();
		在此链接上回滚事务
4.3 Statement类
作用:
	Statement对象用于向数据库发送SQL语句

常用API:
	executeQuery(String sql);
		用于向数据发送查询语句
		
	executeUpdate(String sql);
		用于向数据库发送insert、update或delete语句
		
	execute(String sql);
		用于向数据库发送任意sql语句
		
	addBatch(String sql);
		把多条sql语句放到一个队列处理中
		
	executeBatch();
		向数据库发送一个队列的sql语句执行
4.4 ResultSet类
作用:
	ResultSet用于代表Sql语句的执行结果
	Resultset封装执行结果时,采用的类似于表格的方式, ResultSet 对象维护了一个指向表格数据行的游标
	初始的时候,游标在第一行之前,调用ResultSet.next() 方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据
	
常用API:
	getObject(int index);
	getObject(string columnName);
	
	getString(int index);
	getString(String columnName);
	
	next();
		移动到下一行
	Previous();	
		移动到前一行
	absolute(int row);	
		移动到指定行
	beforeFirst();
		移动resultSet的最前面。
	afterLast();	
		移动到resultSet的最后面。
5. Statement面对SQL注入攻击问题 - PreparedStatement
5.1 完成一个登录操作
// 数据库
-- 创建一个userdb数据库
CREATE database userdb;

-- 使用userdb数据库
USE userdb;

-- 创建用户表
CREATE TABLE users(
   id int PRIMARY key auto_increment,
   username VARCHAR(20) not null,
   `password` VARCHAR(20) not null,
   age int not null,
   email VARCHAR(20) not null,
   phone VARCHAR(20) not null UNIQUE
);

-- 插入测试数据
insert into users values(null,'悟空','admin',50,'wukong@163.com','13367899901');
insert into users values(null,'八戒','12346',52,'bajie@163.com','13367896601');
// 登录代码
package com.bruce.demo2;

import java.sql.*;
import java.util.Scanner;

public class Demo1 {

    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);

        System.out.print("请输入您的账号:");
        String name=input.next();

        System.out.print("请输入您的密码:");
        String pass=input.next();

        Connection conn=null;
        Statement st=null;
        ResultSet result=null;

        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn= DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/userdb?useUnicode=true&characterEncoding=UTF-8","root","123456");
            st=conn.createStatement();
            //登录sql,拼接登录的SQL语句
            String sql="select * from users where username='"+name+"' and password='"+pass+"'";
            System.out.println("登录的SQL语句是:"+sql);
            result=st.executeQuery(sql);
            //如果登录成功,最多只能有一条数据
            if(result.next()){
                //表示登录成功
                System.out.println("登录成功,欢迎您:"+name);
            }else{
                System.out.println("登录失败,账号或密码错误!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if(result!=null){
                    result.close();
                }
                if(st!=null){
                    st.close();
                }
                if(conn!=null){
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
            }
        }
    }
}
// 控制台结果
请输入您的账号:ffff
请输入您的密码:6'or'8'='8
登录的SQL语句是:select * from users where username='ffff' and password='6'or'8'='8'
登录成功,欢迎您:ffff
5.2 总结
	上述登录程序,存在一些安全隐患,容易遭到黑客的恶意攻击!这种攻击叫做SQL注入攻击!

	为什么会遭到攻击?
	
	登录的SQL语句是人为字符串拼接的!账号和密码是拼接到SQL语句中的,容易导致SQL拼接恒成立!而且拼接SQL还容易出错!
	
Statement和PreparedStatement的对比:
	1.PreparedStatement是Statement子接口
	2.PreparedStatement的SQL是预编译,可以执行多次,执行效率高于Statement
	3.PreparedStatement中SQL中使用问号来占位,不是直接把变量拼接到SQL中,所以没有SQL注入问题。安全性比Statement要好!
5.3 使用PreparedStatement完成登录代码
package com.bruce.demo2;

import java.sql.*;
import java.util.Scanner;

public class Demo2 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        System.out.print("请输入您的账号:");
        String name = input.next();

        System.out.print("请输入您的密码:");
        String pass = input.next();

        Connection conn = null;
        PreparedStatement st = null;
        ResultSet result = null;

        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/userdb?useUnicode=true&characterEncoding=UTF-8", "root", "123456");
            //登录sql,拼接登录的SQL语句,变量使用?占位
            String sql = "select * from users where username=? and password=?";
            st = conn.prepareStatement(sql);
            //给?赋值
            st.setObject(1, name); // 给第一个?赋值
            st.setObject(2, pass); // 给第二个?赋值

            result = st.executeQuery();
            //如果登录成功,最多只能有一条数据
            if (result.next()) {
                //表示登录成功
                System.out.println("登录成功,欢迎您:" + name);
            } else {
                System.out.println("登录失败,账号或密码错误!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (result != null) {
                    result.close();
                }
                if (st != null) {
                    st.close();
                }
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
            
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值