JDBC学习笔记


1.JDBC是什么?
Java DataBase Connectivity(Java语言连接数据库)

2.JDBC的本质是什么?
JDBC是SUN公司制定的一套接口(interface)。

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

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

3.为什么要面向接口编程?
解耦合:降低程序的耦合度,提高程序的扩展力。

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


4.为什么SUN制定一套JDBC接口呢?
因为每一个数据库产品都有自己独特的实现原理

5.JDBC编程六步(重点)


1.注册驱动(告诉Java程序,即将连接的是哪个品牌的数据库)

2.获取连接(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,使用完后记得关闭通道)。

3.获取数据库操作对象(专门执行sql语句的对象)

4.执行SQL语句(DQL,DML…)

5.处理查询结果集 (只有当第四步执行的是select语句的时候,才有本步)

6.释放资源(使用完资源后一定要关闭资源,Java和数据库之间属于进程间的通信,开启之后一定要记得关闭)
 
 

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
 
/*JDBC编程六步*/
public class JDBCTest1 {
    public static void main(String[] args) throws SQLException {
        Statement stmt=null;
        Connection conn=null;
        try {
 
            //1.注册驱动
            DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
            //2.获取连接
            /*url:统一资源定位符(网络中某个资源的绝对路径)
            URL包含哪几部分:协议、IP、PORT、资源名
            http://是通信协议   什么是协议?有什么用?
            通信协议是通信之前就提前定好的数据传送格式,数据包具体怎么传数据,提前定好了格式
            182.61.200.7是服务器IP地址
            80 是服务器上软件的端口
            index.html是服务器上某个资源名
            */
            String url = "jdbc:mysql://localhost:3306/MySql?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT";
            String user ="root";
            String password="111111";
            conn=DriverManager.getConnection(url,user,password);
            System.out.println("数据库连接的对象 =" +conn);
            //3.获取数据库操作对象(statement专门执行sql语句的)
            stmt= conn.createStatement();
            //4.执行sql
            String sql="insert into dept(deptno,dname,loc) values(50,'人事部','北京')";
            //专门执行DML语句(insert、delete、update)
            //返回值是‘影响数据库中的记录条数’
            int count=stmt.executeUpdate(sql);
            System.out.println(count==1?"保存成功":"保存失败");//insert保存一条语句
 
            // 5.处理查询结果集
 
        }catch (SQLException e){
            e.printStackTrace();
        }finally {
            //6.释放资源(为了保证资源一定释放,在finally语句块中关闭资源)
            //并且要遵循从小到大依次关闭
            //分别对其try...catch
            try {
                if (stmt!=null){
                    stmt.close();
                }
            }catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (conn!=null){
                    conn.close();
                }
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
    }
 
}

 另外一种注册驱动的方式(利用反射机制,Driver中有一个自带静态方法)

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
 
public class JDBCTest3 {
    //注册驱动的另一种方式(常用)
 
    public static void main(String[] args) {
 
        try {
            //1.注册成功
            //这是注册驱动的第一种写法
            //DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());\
            //注册驱动的第二种写法(常用)
            //为什么这种写法常用?因为参数是一个字符串,字符串可以写到xxx.properties文件中。
            //以下方法不需要接收返回值,因为我们只想用它的类加载动作
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2.获取连接
            Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/MySql?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT"
                    ,"root","111111");
            System.out.println(conn);
        } catch (SQLException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
 
}

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

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;
 
/*
* 实际开发中不建议把连接数据库的信息写死到Java程序中。
* */
public class JDBCTest4 {
    //将连接数据库的所有信息配置到配置文件中
    public static void main(String[] args) throws SQLException{
        //使用资源绑定器绑定属性配置文件
        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 conn=null;
        Statement stmt=null;
        try {
            //1.注册驱动
            Class.forName(driver);
            //2.获取连接
            conn=DriverManager.getConnection(url,user,password);
            //3.获取数据库操作对象
            stmt=conn.createStatement();
            //4.执行SQL语句
            String sql="delete from dept where deptno=40";
            int count=stmt.executeUpdate(sql);
            System.out.println(count==1 ?"删除成功":"删除失败");
        }catch (SQLException | ClassNotFoundException e){
            e.printStackTrace();
        }finally {
            //6.释放资源
            if (stmt!=null){
                try {
                    stmt.close();
                }catch (SQLException e){
                    e.printStackTrace();
                }
            }
            if (conn!=null){
                try {
                    conn.close();
                }catch (SQLException e){
                    e.printStackTrace();
                }
            }
        }
    }
 
}

处理查询结果集

import java.sql.*;
import java.util.ResourceBundle;
 
public class JDBCTest5 {
    //处理查询结果集
    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/MySql?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT"
                    ,"root","111111");
            //3.获取数据库操作对象
            stmt=conn.createStatement();
            //4.执行sql
            String sql="select empno,ename,sal from emp";
            //int excuteUpdate(insert/delete/update)
            //ResultSet excuteQuery(select)
            rs=stmt.executeQuery(sql);//专门执行DQL语句的方法
            //5.处理查询结果集
           /* boolean flag1=rs.next();
//            System.out.println(flag1);  true
            if (flag1){
                //光标指向的行有数据
                //取数据
                //getString()方法的特点是:不管数据库中的数据是什么类型的,都按string形式取出
                //1,2,3 说的是第几列
                String empno=rs.getString(1);//JDBC所有下标从1开始
                String ename=rs.getString(2);
                String sal=rs.getString(3);
                System.out.println(empno+","+ename+","+sal);
            }*/
           while (rs.next()){
              /* String empno=rs.getString(1);//JDBC所有下标从1开始
               String ename=rs.getString(2);
               String sal=rs.getString(3);
               System.out.println(empno+","+ename+","+sal);*/
 
 
              //这个不是以列的下标获取,以列的名字获取,(健壮性)
               //除了可以以String类型取出之外,还可以以特定了类型取出
               //int  getInt...
               String empno=rs.getString("empno");
               String ename=rs.getString("ename"); //假如有 AS a  则以a查询,因为是rs是结果集
               String sal=rs.getString("sal");
               System.out.println(empno+","+ename+","+sal);
           }
 
        }catch (Exception 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();
                }
            }
        }
 
    }
 
}


有安全隐患的用户登录界面

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
 
public class JDBCTest6 {
    /*
    * 实现功能:
    * 1.需求:模拟用户登录功能的实现
    * 2.业务描述:程序运行的时候,提供一个输入的入口,可以让用户输入用户名和密码
    * .用户输入用户名和密码后,提交信息,Java程序收集到用户信息
    * .Java程序连接数据库验证用户名和密码是否合法
    * 合法:显示登录成功,不合法:显示登录失败
    * 3.数据的准备:在实际开发中,表的设计会使用专业的建模工具,我们这里安装一个建模工具:powerDesigner
    * 使用PD工具来进行数据库表的设计。
    * 4.当前程序存在问题 :
    * 用户:gsad
    * 密码:fsad' or'1'='1
    * 登陆成功
    * 这种现象被称为SQL注入(安全隐患)(黑客经常使用)
    * 导致这种现象的根本原因是什么?
    * 用户输入的信息中含有sql语句的关键字,并且这些关键字参与了sql语句的编译过程
    * 导致sql语句的原意被扭曲,进而达到sql注入。
    * */
    public static void main(String[] args) throws SQLException {
        //初始化一个界面
        Map<String,String> userLoginInfo= initUI();
        //验证用户名和密码
        boolean loginSuccess= login(userLoginInfo);
        //输出结果
        System.out.println(loginSuccess ?"登录成功":"登录失败");
    }
 
    private static boolean login(Map<String, String> userLoginInfo) throws SQLException {
        //打标记的意识
        boolean loginSuccess=false;
        //单独定义变量
        String loginName=userLoginInfo.get("loginName");
        String loginPwd =userLoginInfo.get("loginPwd");
        //jdbc代码
        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/MySql?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT"
                    ,"root","131138");
            //3.获取数据库操作对象
            stmt=conn.createStatement();
            //4.执行sql语句
            String sql="select * from t_user where loginName='"+loginName+"'and loginPwd='"+loginPwd+"'";
            rs=stmt.executeQuery(sql);
            //5.处理结果集
            if (rs.next()){
                loginSuccess=true;
            }
        } catch (ClassNotFoundException | 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;
    }
 
    /*
    * 初始化用户界面
    * @return用户输入的用户名和密码等登录信息
    * */
    private static Map<String, String> initUI() {
        Scanner scanner=new Scanner(System.in);
        System.out.println("用户名:");
 
        String loginName=scanner.nextLine();
        System.out.println("密码:");
 
        String loginPwd=scanner.nextLine();
 
        Map<String,String> userLoginInfo= new HashMap<>();
        userLoginInfo.put("loginName",loginName);
        userLoginInfo.put("loginPwd",loginPwd);
        return userLoginInfo;
    }
 
}import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
 
public class JDBCTest6 {
    /*
    * 实现功能:
    * 1.需求:模拟用户登录功能的实现
    * 2.业务描述:程序运行的时候,提供一个输入的入口,可以让用户输入用户名和密码
    * .用户输入用户名和密码后,提交信息,Java程序收集到用户信息
    * .Java程序连接数据库验证用户名和密码是否合法
    * 合法:显示登录成功,不合法:显示登录失败
    * 3.数据的准备:在实际开发中,表的设计会使用专业的建模工具,我们这里安装一个建模工具:powerDesigner
    * 使用PD工具来进行数据库表的设计。
    * 4.当前程序存在问题 :
    * 用户:gsad
    * 密码:fsad' or'1'='1
    * 登陆成功
    * 这种现象被称为SQL注入(安全隐患)(黑客经常使用)
    * 导致这种现象的根本原因是什么?
    * 用户输入的信息中含有sql语句的关键字,并且这些关键字参与了sql语句的编译过程
    * 导致sql语句的原意被扭曲,进而达到sql注入。
    * */
    public static void main(String[] args) throws SQLException {
        //初始化一个界面
        Map<String,String> userLoginInfo= initUI();
        //验证用户名和密码
        boolean loginSuccess= login(userLoginInfo);
        //输出结果
        System.out.println(loginSuccess ?"登录成功":"登录失败");
    }
 
    private static boolean login(Map<String, String> userLoginInfo) throws SQLException {
        //打标记的意识
        boolean loginSuccess=false;
        //单独定义变量
        String loginName=userLoginInfo.get("loginName");
        String loginPwd =userLoginInfo.get("loginPwd");
        //jdbc代码
        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/MySql?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT"
                    ,"root","131138");
            //3.获取数据库操作对象
            stmt=conn.createStatement();
            //4.执行sql语句
            String sql="select * from t_user where loginName='"+loginName+"'and loginPwd='"+loginPwd+"'";
            rs=stmt.executeQuery(sql);
            //5.处理结果集
            if (rs.next()){
                loginSuccess=true;
            }
        } catch (ClassNotFoundException | 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;
    }
 
    /*
    * 初始化用户界面
    * @return用户输入的用户名和密码等登录信息
    * */
    private static Map<String, String> initUI() {
        Scanner scanner=new Scanner(System.in);
        System.out.println("用户名:");
 
        String loginName=scanner.nextLine();
        System.out.println("密码:");
 
        String loginPwd=scanner.nextLine();
 
        Map<String,String> userLoginInfo= new HashMap<>();
        userLoginInfo.put("loginName",loginName);
        userLoginInfo.put("loginPwd",loginPwd);
        return userLoginInfo;
    }
 
}


解决sql注入问题

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/*
* 解决sql注入问题
* 只要用户提供的信息 不参与sql语句的编译过程,问题就解决了
* 即使用户提供的信息中含有sql语句的关键字,但是没有参与编译,不起作用
* 要想用户信息不参与sql语句的编译,那么必须使用java.sql.PreparedStatement
* PreparedStatement接口继承了java.sql.PreparedStatement
* PreparedStatement是属于预编译的数据库操作对象。
* PreparedStatement的原理是:预先对sql语句的框架进行编译,然后再给sql语句传"值"
* 解决SQL注入问题的关键是什么?
* 用户提供的信息中即使含有sql语句的关键字 ,但是这些关键字并没有参与编译,不起作用。
对比PreparedStatement与Statement
* 1.Statement存在sql注入问题,PreparedStatement解决了sql注入问题
* 2.Statement是编译依次执行一次,PreparedStatement是编译一次,可以执行n次,效率略高
* 3.PreparedStatement会在编译阶段做类型安全检查
* 综上所述:大部分时候使用PreparedStatement   有些情况用statement,如需要输入desc(降序) asc(升序)
* */
public class JDBCTest7 {
    public static void main(String[] args) throws SQLException {
        //初始化一个界面
        Map<String,String> userLoginInfo= initUI();
        //验证用户名和密码
        boolean loginSuccess= login(userLoginInfo);
        //输出结果
        System.out.println(loginSuccess ?"登录成功":"登录失败");
    }
 
    private static boolean login(Map<String, String> userLoginInfo) throws SQLException {
        //打标记的意识
        boolean loginSuccess=false;
        //单独定义变量
        String loginName=userLoginInfo.get("loginName");
        String loginPwd =userLoginInfo.get("loginPwd");
        //jdbc代码
        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/MySql?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT"
                    ,"root","131138");
            //3.获取预编译的数据库操作对象
            //SQl语句的框子,其中一个?代表一个占位符,一个?将来接收一个值。(占位符不可以用单引号括起来)
            String sql="select * from t_user where loginName=? and loginPwd=? ";
            //程序执行到此处。会发送sql语句框子给DBMS,然后DBMS进行sql语句的预编译
            ps=conn.prepareStatement(sql);
            //给占位符 ?传值,(第一个问号下标是1,第二个问号下标是2,JDBC都是1开始)
            ps.setString(1,loginName);
            ps.setString(2,loginPwd);
            //4.执行sql语句
            rs=ps.executeQuery();
            //5.处理结果集
            if (rs.next()){
                loginSuccess=true;
            }
        } catch (ClassNotFoundException | 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;
    }
 
    /*
     * 初始化用户界面
     * @return用户输入的用户名和密码等登录信息
     * */
    private static Map<String, String> initUI() {
        Scanner scanner=new Scanner(System.in);
        System.out.println("用户名:");
 
        String loginName=scanner.nextLine();
        System.out.println("密码:");
 
        String loginPwd=scanner.nextLine();
 
        Map<String,String> userLoginInfo= new HashMap<>();
        userLoginInfo.put("loginName",loginName);
        userLoginInfo.put("loginPwd",loginPwd);
        return userLoginInfo;
    }
 
}

JDBC事物机制:
1.JDBC中的事务自动提交的,什么是自动提交?
只要执行任意一条 DML语句,则自动提交一次。这是JDBC默认的事务行为。
但是在实际的业务中,通常都是N条DML语句共同联合才能完成,必须
保证这些DML语句在同一个事务中同时成功或者同时失败
解决方案:三行重要的代码
conn.setAutoCommit(false);//手动提交事务
conn.commit();//提交事务
conn.roolback;当发生异常时或者程序错误时,进行回滚。

工具类封装

package utils;
 
import java.sql.*;
 
/*
* JDBC工具类,简化JDBC编程
* */
public class DBUtil {
 
    /*工具类中的构造方法都是私有的,以为工具类当中的方法都是静态的
      不需要new对象,直接采用类名调用。*/
 
    private DBUtil(){}
    //静态代码块在类加载时执行,并且只执行一次。
    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
 
    public static Connection getConnection() throws SQLException{
        //获取数据库连接对象,返回连接对象
        return DriverManager.getConnection("jdbc:mysql://localhost:3306/MySql?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT"
                    ,"root","131138");
 
    }
 
    //关闭资源,conn:连接对象,ps:数据库操作对象 rs:结果集
    public static void close(Connection conn, Statement ps, ResultSet rs){
        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();
            }
        }
    }
}


8.悲观锁和乐观锁的概念
事务1–>读取到版本号1.1
事务2—>读取到版本号1.1

其中事务1先修改了,修改之后看了版本号是1.1 ,于是提交修改的数据,将版本号修改为1.2
其中事务2后修改的,修改之后准备提交的时候,发现版本号是1.2 ,和它最初读的版本号不一致。回滚。

悲观锁:事务必须排队执行。数据锁住了,不允许并发。 (行级锁: select后面添加for update )
乐观锁:支持并发,事务也不需要排队,只不过需要一个版本号。
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值