JDBC

1、JDBC是什么

​ Java Database Connectivity (java语言连接数据库)

2、JDBC本质是什么

​ 是sun公司制定的一套接口

​ java.sql.* ;(这个软件包下有许多的接口)

​ 接口都有调用者和实现者

​ 面向接口调用,面向接口写实现类,这都属于面向接口编程

​ 为什么要面向接口编程?

​ 解耦合,降低程序的耦合度,提高程序的扩展力

​ 多态机制就是典型的面向抽象编程(不要面向具体编程)

​ 思考:为什么要制定JDBC接口

​ 因为每隔数据库的底层实现原理不一样。每个数据库产品都有自己的实现原理

​ 实现者:数据库厂家

​ 调用者:程序员

​ sun公司指定了接口,实现者和 调用者都要遵循这套接口规范

​ image-20210420093308126

 3、JDBC开发前的准备工作

首先下载对应的jar包,然后将其配置到环境变量中

classpath=.;jar路径

这里一定要加.;否则以后类加载器都会到jar路径下去找类

idea不需要配置这些,以上的配置是针对文本编辑器的

4、JDBC编程六步(需要背会)

第一步:注册驱动(作用:告诉JVM,即将要连接的数据库是哪个品牌的数据库)

第二步:获取连接(标识JVM和数据库进程之间的通道打开了,这属于进程之间的通信)

第三步:获取数据库操作对象(专门执行sql语句的对象)

第四步:执行sql语句(DQL,DML)

第五步:处理查询结果集(只有第四步是DQL的时候才会执行第五步)

第六步:释放资源(使用完后一定要关闭,java和数据库之间的通信属于进程之间的通信,开启后一定要关闭)

代码:

添加操作

/*
    JDBC编程六步
*/

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Connection;
import java.sql.Statement;
public class JDBCTest01{
    
    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、获取连接
            /*
                url格式:协议://地址:端口号/数据库具体实例
            */
            String url = "jdbc:mysql://localhost:3306/fhq?serverTimezone=UTC";
            String user = "root";
            String password = "123456";
            conn = DriverManager.getConnection(url,user,password);
            System.out.println("数据库连接对象"+conn);
            
            //3、获取数据库操作对象(Statement专门执行sql语句)
            statement = conn.createStatement();
        
            //4、执行sql语句
            String sql = "insert into port(id,port) values(2,200)";
            
            //专门执行DML语句的(insert delete update)
            //返回值是:影响数据库中记录的条数
            int result = statement.executeUpdate(sql);
            System.out.println(result == 1?"保存成功":"保存失败");
                
            //5、处理查询结果集
            
        }catch(SQLException e){
            e.printStackTrace();
        }finally{
            //6、释放资源
            //为了保障资源一定释放,所以在finally语句块中关闭资源
            //并且遵循从小到大的依次关闭
            //分别try catch 否则第一个报错了之后,后面的就不会执行了
            if(statement!=null){
                try{
                    statement.close();
                }catch(SQLException e){
                    e.printStackTrace();
                }
            }
            if(conn != null){
                try{
                    conn.close();
                }catch(SQLException e){
                    e.printStackTrace();
                }
            }
        }
        
        
    }
    
}

删除和更新操作

/*
    JDBC完成delete update
*/

import java.sql.*;
public class JDBCTest02{
    
    public static void main(String[] args){
        Connection connection = null;
        Statement statement = null;
        try{
            //1、注册驱动
            DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
        
            //2、获取连接
            connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/fhq?serverTimezone=UTC","root","123456");
        
            //3、获取数据库操作对象
            statement = connection.createStatement();
        
            //4、执行sql语句
            String sql01 = "delete from port where port = 100";
            String sql02 = "update port set port = 300 where port = 200";
            int res01 = statement.executeUpdate(sql01);
            int res02 = statement.executeUpdate(sql02);
            System.out.println(res01 == 1?"删除成功":"删除失败");
            System.out.println(res02 == 1?"更新成功":"更新失败");
        }catch(SQLException e){
            e.printStackTrace();
        }finally{
            //6、释放资源
            if(statement != null){
                try{
                    statement.close();
                }catch(SQLException e){
                    e.printStackTrace();
                }
            }
            if(connection != null){
                try{
                    connection.close();
                }catch(SQLException e){
                    e.printStackTrace();
                }
            }
        }
        
        
        
        
        
    }
    
}

5、使用类加载方式注册驱动

Class.forName("com.mysql.cj.jdbc.Driver");

实现原理:

类加载的时候会执行静态代码块

在Driver这个类中有一个静态代码块内容包含了

DriverManager.registerDriver(new Driver());

所以就注册了驱动

这种方式更加的常用

6、将连接数据库的所有配置信息都配置到配置文件中

jdbc.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/fhq?serverTimezone=UTC
user=root
password=123456

java文件

/*
    将数据库连接信息写到配置文件中
*/
import java.sql.*;
import java.util.*;
public class JDBCTest04{
    
    public static void main(String[] args){
        
        //使用资源绑定器绑定属性配置文件
        ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
        String driver = bundle.getString("driver");
        String url = bundle.getString("url");
        String user = bundle.getString("user");
        String password = bundle.getString("password");
        Connection connection = null;
        Statement statement = null;
        try{
            //1、注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2、获取连接
            connection = DriverManager.getConnection(url,user,password);
            //3、获取数据库操作对象
            statement = connection.createStatement();
            //4、执行sql语句
            String sql = "insert into port(port) values (400)";
            int result = statement.executeUpdate(sql);
            System.out.println(result == 1?"插入成功":"插入失败");
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(statement != null){
                try{
                    statement.close();
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
            if(connection != null){
                try{
                    connection.close();
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        }
    }
    
}

7、处理查询结果集

 

/*
    处理查询结果集合
*/
import java.sql.*;
import java.util.*;

public class JDBCTest05{
    
    public static void main(String[] args){
        ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        String driver = bundle.getString("driver");
        String url = bundle.getString("url");
        String user = bundle.getString("user");
        String password = bundle.getString("password");
        try{
            //1、注册驱动
            Class.forName(driver);
            //2、获取连接
            connection = DriverManager.getConnection(url,user,password);
            //3、创建数据库操作对象
            statement = connection.createStatement();
            //4、执行sql语句
            String sql = "select * from port";
            resultSet = statement.executeQuery(sql);
            //5、处理结果集
            while(resultSet.next()){
                /*
                    这里有两种方式:
                    第一种:根据下标获取列的值,默认从1开始
                    String id = resultSet.getString(1);
                    
                    第二种:根据列名称获取
                    String id = resultSet.getString("id");
                */
                int id = resultSet.getInt("id");
                int port = resultSet.getInt("port");
                System.out.println(id+"  "+port);
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            //6、释放资源
            if(resultSet != null){
                try{
                    resultSet.close();
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
            if(statement != null){
                try{
                    statement.close();
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
            if(connection != null){
                try{
                    connection.close();
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        }
        
        
    }
    
}

8、用户登录练习

package com.fjh.jdbc;

import javax.xml.transform.Result;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Scanner;

public class UserLogin {
    public static void main(String[] args) {
        //初始化界面
        Map<String,String > userLoginInfo = initUI();
        //用户登录方法
        boolean result = userLogin(userLoginInfo);
        System.out.println(result == true?"登录成功":"登录失败");
    }

    /**‘
     *
     * @param userLoginInfo 用户的登录信息
     * @return true 登录成功 false 登录失败
     */
    private static boolean userLogin(Map<String, String> userLoginInfo) {
        boolean userLoginFlag = false;
        ResourceBundle bundle = ResourceBundle.getBundle("com.fjh.properties.userLogin");
        String driver = bundle.getString("driver");
        String url = bundle.getString("url");
        String user = bundle.getString("user");
        String password = bundle.getString("password");
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        String userNameLogin = userLoginInfo.get("userName");
        String passwordLogin = userLoginInfo.get("password");


        try {

            //1、注册驱动
            Class.forName(driver);
            //2、获取连接
            connection = DriverManager.getConnection(url,user,password);
            //3、创建数据库操作对象
            statement = connection.createStatement();
            //4、执行sql语句
            String sql = "select * from userLogin where userName = '"+userNameLogin+"' and password = '"+passwordLogin+"'";
            resultSet = statement.executeQuery(sql);
            //5、处理结果集
            if(resultSet.next()){
                userLoginFlag = true;
            }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }finally {
            if (resultSet == null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (statement == null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection == null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return userLoginFlag;


        //6、释放资源
    }

    /**
     * 输入用户信息
     * @return userloginInfo 用户名和密码
     */
    private static Map<String, String> initUI() {
        Scanner scanner = new Scanner(System.in);
        System.out.printf("请输入用户名:");
        String userName = scanner.nextLine();
        System.out.printf("请输入密码:");
        String password = scanner.nextLine();
        Map<String,String> userLoginInfo = new HashMap<>();
        userLoginInfo.put("userName",userName);
        userLoginInfo.put("password",password);
        return userLoginInfo;
    }
}

9、sql注入

如果以上代码输入如下也会登录成功

请输入用户名:aaa
请输入密码:aaa' or '1'='1
登录成功

这种现象叫做sql注入

1、产生sql注入的原因

用户输入的信息含有sql与的关键字,并且这些关键字参与了sql语句的编译过程

10、解决sql注入

方法:使用preparedStatement(预编译数据库操作对象)

package com.fjh.jdbc;

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Scanner;

/**
 * 解决sql注入问题
 */

public class UserLogin02 {

    public static void main(String[] args) {
        //初始化界面
        Map<String,String > userLoginInfo = initUI();
        //用户登录方法
        boolean result = userLogin(userLoginInfo);
        System.out.println(result == true?"登录成功":"登录失败");
    }

    /**‘
     *
     * @param userLoginInfo 用户的登录信息
     * @return true 登录成功 false 登录失败
     */
    private static boolean userLogin(Map<String, String> userLoginInfo) {
        boolean userLoginFlag = false;
        ResourceBundle bundle = ResourceBundle.getBundle("com.fjh.properties.userLogin");
        String driver = bundle.getString("driver");
        String url = bundle.getString("url");
        String user = bundle.getString("user");
        String password = bundle.getString("password");
        Connection connection = null;
        //Statement statement = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        String userNameLogin = userLoginInfo.get("userName");
        String passwordLogin = userLoginInfo.get("password");


        try {

            //1、注册驱动
            Class.forName(driver);
            //2、获取连接
            connection = DriverManager.getConnection(url,user,password);
            //3、创建数据库操作对象
            //使用占位符?,然后预先将要使用的sql语句编译
            String sql = "select * from userLogin where userName = ? and password = ?";
            preparedStatement = connection.prepareStatement(sql);
            //statement = connection.createStatement();
            //4、执行sql语句
            //mysql的下标从1开始,这里的下标代表第一个问号
            preparedStatement.setString(1,userNameLogin);
            preparedStatement.setString(2,passwordLogin);
            preparedStatement.executeQuery();
            //resultSet = statement.executeQuery(sql);
            //5、处理结果集
            if(resultSet.next()){
                userLoginFlag = true;
            }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }finally {
            if (resultSet == null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (preparedStatement == null) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection == null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return userLoginFlag;


        //6、释放资源
    }

    /**
     * 输入用户信息
     * @return userloginInfo 用户名和密码
     */
    private static Map<String, String> initUI() {
        Scanner scanner = new Scanner(System.in);
        System.out.printf("请输入用户名:");
        String userName = scanner.nextLine();
        System.out.printf("请输入密码:");
        String password = scanner.nextLine();
        Map<String,String> userLoginInfo = new HashMap<>();
        userLoginInfo.put("userName",userName);
        userLoginInfo.put("password",password);
        return userLoginInfo;
    }
    
}

11、Statement和preparedStatement的区别

Statement是将值直接拼接到sql语句中,值参与了sql的编译过程,容易造成sql注入

preparedStatement是先将要执行的sql语句框架编译好,传值的地方用?占位置,最后将值传入,值不参与sql的编译过程

注意:在有些时候必须使用Statement,就像排序,传入的值是desc或者asc 那么这个值就必须参与编译过程

12、JDBC的事务自动提交机制

JDBC中只要执行任意一条DML语句,就提交一次

idea块编辑:alt+shift+insert

将自动提交事务变为手动提交

//开启事务
conn.setAutoCommit(false);
//中间写要完成的事务
//提交事务
conn.commit()
    
//catch语句块中写回滚事务(如果发生异常,要保证数据的安全)
    if(conn != null){
        try{
            conn.rollback();//手动回滚事务
        }catch(Exception e){
            e.printStackTrace();
        }
    }

最重要的就是这三行

单机事务简单

分布式事务难

12、悲观锁和乐观锁

悲观锁:加锁后其他线程就不能够访问,是单线程模式

乐观锁:加锁了之后依旧可以访问,不过会对加锁的内容添加一个序号,如果其他线程访问的时候,发现事务开始和结束的序号不一样就不会提交

代码测试:

加锁代码

package com.fjh.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class JDBCTest07 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            connection = DButil.getConnection("jdbctest","root","123456");
            connection.setAutoCommit(false);//关闭自动提交
            String sql = "select * from userLogin where userName = ? for update ";//这里加for update就是对查询到的数据加了悲观锁
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,"fjh");
            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()){
                System.out.println(resultSet.getString("userName") +"   "+resultSet.getString("password"));
            }
            connection.commit();//手动提交
        } catch (Exception e) {
            try {
                if(connection != null){
                    connection.rollback();//事务回滚
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        }
    }
}

在加锁情况下修改数据

package com.fjh.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class JDBCTest08 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            connection = DButil.getConnection("jdbctest","root","123456");
            connection.setAutoCommit(false);//关闭自动提交
            String sql = "update userLogin set userName = 'root' where userName = ?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,"fjh");
            int count = preparedStatement.executeUpdate();
            System.out.println(count);
            connection.commit();//手动提交
        } catch (Exception e) {
            try {
                connection.rollback();//事务回滚
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        }
    }
}

测试方法:

在07类的提交代码处加断点观察08是否有输出,将断点打开后,08有了输出

实验结果:到断点时没有输出,打开后有输出,说明行级锁生效了

13、封装JDBC

package com.fjh.jdbc;

import java.sql.*;

public class DButil {
    //一般工具类的构造方法都是私有的,因为不需要new对象
    private DButil(){}

    //静态代码块在类加载的时候只加载一次,并且只执行一次
    static{
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    //获取连接
    public static Connection getConnection(String dbName,String userName,String passwoord) throws SQLException {
        return DriverManager.getConnection("jdbc:mysql://localhost:3306/"+dbName+"?serverTimezone=UTC",userName,passwoord);
    }
    //关闭连接
    public static void close(Connection connection, Statement statement, ResultSet resultSet){
        if(connection!=null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(statement!=null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(resultSet!=null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

14、以上测试所用到的表结构

id 自增

userName 用户名

password 密码
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mizui_i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值