JDBC

1、JDBC是什么?

Java DataBase Connectivity ( Java语言连接数据库)
在这里插入图片描述

2、JDBC的本质是什么?

JDBC是SUN公司制定的一套接口( interface )
java.sql.*; (这个软件包下有很多接口)
接口都有调用者和实现者。
面向接口调用、面向接口写实现类,这都属于面向接口编程。
为什么要面向接口编程?
解耦合:降低程序的耦合度,提高程序的扩展力。
多态机制就是非常典型的:面向抽象编程。(不要面向具体编程)
建议:
Animal a = new Cat() ;
Animal a = new Dog() ;
public void feed (Animal a){ //面向父类型编程。
不建议:
Dog d=new Dog();
Cat c=new Cat();

3、思考:为什么SUN制定一套JDBC接口呢?

因为每一个数据库的底层实现原理都不一样。
Oracle数据库有自己的原理。
MySQL数据库也有自己的原理。
MS SqlServer数据库也有自己的原理。
每一个数据库产品都有自己独特的实现原理。
JDBC的本质到底是什么?
一套接口

4、JDBC编程六步

第一步:注册驱动(作用:告诉Java程序,即将要连接的是哪个品牌的数据库)
第二步:获取连接(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用完之后一定要通道)
第三步:获取数据库操作对象(专门执行sql语句的对象)
第四步:执行SQL语句(DQL DML…)
第五步:处理查询结果集(只有当第四步执行的是select语句的时候,才有这步。
第六步:释放资源(使用完资源之后一定要关闭资源。Java和数据库属于进程间的通信,开启后一定要关闭。)

package com.hp.jdbc;

import java.sql.*;

public class Test01 {
    public static void main(String[] args) {
        try {
            Class.forName("com.mysql.jdbc.Driver");

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static class test{
        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、获取连接
                /*
                    url:统一资源定位符(网络中某个资源的绝对路径)
                    https : / /www. baidu. com/ 这就是URL。
                    URL包括哪几部分?
                        协议
                        IP
                        PORT
                        资源名
                http://182.61.200.7:80/index . html
                http://通信协议
                182.61.200.7服务器IP地址
                80服务器上软件的端口
                index.html是服务器上某个资源名

                jdbc :mysql ://127.0.0.1:3306/bjpowernode
                jdbc :mysql://协议
                127.0.0.1 IP地址
                3306 mysql数据库端口号
                bjpowernode具体的数据库实例名。
                            说明: localhost和127.0.0. 1都是本机IP地址。
                            什么是通信协议,有什么用?
                通信协议是通信之前就提前定好的数据传送格式。
                数据包具体怎么传数据,格式提前定好的。
                            oracle的URL:
                jdbc : oracle : thin: @localhost:1521 :orcl
                */
                String url="jdbc:mysql://127.0.0.1:3306/bjpowernode";
                String user="root";
                String password="333";
                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) ;
                //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();
                }

            }
        }
    }
}

注册驱动的另一种方式(重点)

public class Test03 {
    public static void main(String[] args) {

        try{
            //1、注册驱动
            //这是注册驱动的第一种方式
            //DriverManager.registerDriver(new com.mysql.jdbc.Driver());

            //这是注册驱动的第二种方式:常用的
            //为什么这种方式常用?因为参数是一个字符串,字符串可以写到xxx.properties文件中

            Class.forName("com.mysql.jdbc.Driver");
            //2、获取连接
            Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","xqy2261579446");


        }catch (SQLException e){
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

jdbc.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/bjpowernode
user=root
password=xxxxxxxxxxxxxx
package com.hp.jdbc;
//将连接数据库的所有信总配置到配置文件中

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;

public class Test04 {
    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 conn=null;
        Statement stmt=null;
        try{
            //1、注册驱动

           Class.forName(driver);
            //2、获取连接
            conn=DriverManager.getConnection(url,user,password);
            //3、获取数据库操作对象
            stmt=conn.createStatement();
            //4、执行SQL语句
            //JDBC中的sql语句不需要提供分号结尾
            //String sql="delete from dept where deptno=40";
            String sql="update dept set dname='销售部',loc='天津' where deptno=20";
            int count=stmt.executeUpdate(sql);
            //System.out.println(count==1?"删除成功":"删除失败");
            System.out.println(count==1?"更新成功":"更新失败");

        }catch (SQLException e){
            e.printStackTrace();
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        } finally{
            //5、释放资源
            if (stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn!=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

        }

    }
}

5、处理查询结果集

遍历结果集

public class Test05 {
    public static void main(String[] args) {
        Connection conn=null;
        Statement stmt=null;
        ResultSet rs=null;
        try {
            //1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、获取连接
            conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","xqy2261579446");
            //3、获取数据库执行对象
            stmt=conn.createStatement();
            //4、执行sql
            String sql="select empno as a,ename,sal from emp";
            // int executeUpdate (insert/delete/update)
            // Resultset executeQuery (select)
            rs=stmt.executeQuery(sql);//专门执行DQL语句的方法
            //5、处理查询结果集
            /*
             boolean flag1 = rs.next() ;
            //System.out.println(flag1) ; // true
            if (flag1) {
                //光标指向的行有数据:
                //取数据
                // getString() 方法的特点是:不管数据库中的数据类型是什么,都以string的形式取出。
                String empno = rs.getString(1); // JDBC中所有下标从1开始。不是从0开始。
                String ename = rs.getString(2);
                String sal = rs.getString(3);
                System.out.println(empno + "," + ename + "," + sal);
            }
            flag1 = rs.next() ;
            if (flag1) {
                //以下程序的12 3说的第几列。
                    String empno = rs.getString(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) ;
                String ename = rs.getString(2) ;
                String sal = rs.getString(3) ;
                System. out.println (empno + "," + ename + ","+sal) ;
                 */
                /*
                //以下不是以列的下标获取,以列的名字获取
                String empno = rs.getString("a") ;//重点注意:列名称不是表中的列名称,是查询结果集的列名称。
                String ename = rs.getString("ename") ;
                String sal = rs.getString("sal") ;
                System. out.println (empno + "," + ename + ","+sal) ;
                 */
                //除了可以以String类型取出之外,还可以以特定的类型取出。
                int empno = rs.getInt(1) ;
                String ename = rs.getString(2) ;
                double sal = rs.getDouble(3) ;
                System.out.println (empno + "," + ename + "," + (sal + 100)) ;


            }
            }catch (Exception e){
            e.printStackTrace();
        }finally {
            //6、释放资源
            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();
                }
            }
        }
    }
}

6、模拟用户登录功能的实现。

6.1 程序运行的时候,提供一个输入的入口,可以让用户输入用户名和密码
用户输入用户名和密码之后,提交信息,java程序收集到用户信息
Java程序连接数据库验证用户名和密码是否合法
合法:显示登录成功
不合法:显示登录失败

public class login {
    public static void main(String[] args) {
        //初始化一个界面
        Map<String,String> userLoginInfo=initUI();
        //验证用户名和密码
        boolean loginSuccess=login(userLoginInfo);
        System.out.println(loginSuccess ? "登录成功":"登陆失败");

    }

    /**
     * 用户登录
     * @param userLoginInfo 用户登录信息
     * @return false表示失败,true表示成功
     */
    private static boolean login(Map<String,String>userLoginInfo){
        //打标记
        boolean LoginSuccess=false;
        //JDBC代码
        Connection conn=null;
        Statement stmt=null;
        ResultSet rs=null;

        try {
            //1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、建立连接
            conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","xqy2261579446");
            //3、获取数据库操作对象
            stmt=conn.createStatement();
            //4、执行sql
            String sql="select * from t_user where loginName='"+userLoginInfo.get("loginName")+"'and loginPwd='"+userLoginInfo.get("loginPwd")+"'";
            //以上正好完成了sql语句的拼接,以下代码的含义是,发送sql语句给DBMS,DBMS进行sql编译
            //正好将用户提供的“非法信息”编译进去。导致了原sql语句的含义被扭曲了。
            rs=stmt.executeQuery(sql);
            //5、处理结果集
            if (rs.next()){
                LoginSuccess=true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //6、释放资源
            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 s=new Scanner(System.in);
        System.out.print("用户名:");
        String loginName=s.nextLine();
        System.out.print("密码:");
        String loginPwd=s.nextLine();
        Map<String,String> userLoginInfo=new HashMap<>();
        userLoginInfo.put("loginName",loginName);
        userLoginInfo.put("loginPwd",loginPwd);
        return  userLoginInfo;
    }


}

当前程序存在的问题
用户名:fdsa
密码:fdsa’ or ‘1’='1
登录成功
这种现象被称为SQL注入
6.2 导致SQL注入的根本原因是什么?
用户输入的信息中含有sql语句的关键字,并且这些关键字参与sql语句的编译过程,
导致sq1语句的原意被扭曲,进而达到sql注入。
6.3 解决sql注入问题
只要用户提供的信息不参与SQL语句的编译过程,问题就解诀了。
即使用户提供的信息中含有SQL语句的关键字,但是没有参与编译,不起作用。
要想用户信息不参与SQL语句的编译,那么必须使用java.sql.Preparedstatement
Preparedstatement接口继承了java.sql.Statement
Preparedstatement是属于预编译的数据库操作对象。
Preparedstatement的原理是:预先对SQL语句的框架进行编译,然后再给SQL语句传“值”。

public class Test07 {
    public static void main(String[] args) {
        //初始化一个界面
        Map<String,String> userLoginInfo=initUI();
        //验证用户名和密码
        boolean loginSuccess=login(userLoginInfo);
        System.out.println(loginSuccess ? "登录成功":"登陆失败");

    }

    /**
     * 用户登录
     * @param userLoginInfo 用户登录信息
     * @return false表示失败,true表示成功
     */
    private static boolean login(Map<String,String>userLoginInfo){
        //打标记
        boolean LoginSuccess=false;
        //单独定义变量
        String loginName=userLoginInfo.get("loginName");
        String loginPwd=userLoginInfo.get("loginPwd");
        //JDBC代码
        Connection conn=null;
        PreparedStatement ps=null;//这里使用PreparedStatement (预编译的数据库操作对象)

        ResultSet rs=null;

        try {
            //1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、建立连接
            conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","xqy2261579446");
            //3、获取预编译的数据库操作对象
            //SQL语句的框子。其中一个?表示一个占位符,一个?将来接收一个"值",注意:占位符不能使用单引号括起来。
            String sql="select * from t_user where loginName= ? and loginPwd=?";//SQL语句框架
            //程序执行到此处,会发送sql语句框给DBMS,然后DBMS进行sql语句的预先编译。
            ps=conn.prepareStatement(sql);
            //给占位符?传值(第1个问号下标是1,第2个问号下标是2,JDBC中所有下标从1开始。)
            ps.setString(1,loginName);
            ps.setString(2,loginPwd);
            //4、执行sql
            rs=ps.executeQuery();
            //5、处理结果集
            if (rs.next()){
                LoginSuccess=true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //6、释放资源
            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 s=new Scanner(System.in);
        System.out.print("用户名:");
        String loginName=s.nextLine();
        System.out.print("密码:");
        String loginPwd=s.nextLine();
        Map<String,String> userLoginInfo=new HashMap<>();
        userLoginInfo.put("loginName",loginName);
        userLoginInfo.put("loginPwd",loginPwd);
        return  userLoginInfo;
    }

}

测试结果
用户名:fdsa
密码:fdsa’ or ‘1’='1
登陆失败
6.4解决SQL注入的关键是什么?
用户提供的信息中即使含有sql语句的关键字,但是这些关键字并没有参与编译。不起作用。
6.5、对比一下Statement和PreparedStatement
-Statement存在sql注入问题。
-Statement是编译一次执行一次。PreparedStatement是编译一次执行N次。
-PreparedStatement会在编译阶段做类型的安全检查。
综上所述,PreparedStatement会在编译阶段做类型的安全检查

6.6、什么情况下必须使用Statement?
业务方面要求必须支持SQL注入的时候
Statement支持SQL注入,凡是业务方面需要进行SQL语句拼接的,必须使用Statement

public class Test08 {
    public static void main(String[] args) {
        /*
        //用户在控制台输入desc就是降序,输入asc就是升序
        Scanner s=new Scanner(System.in);
        System.out.println("请输入desc或asc,desc表示降序,asc表示升序");
        System.out.println("请输入:");
        String keywords=s.nextLine();
        //执行SQL
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","xqy2261579446");
            //获取预编译的操作对象
            String sql="select ename from emp order by ename ?";
            ps=conn.prepareStatement(sql);
            ps.setString(1,keywords);
            //执行sql
            rs=ps.executeQuery();
            while (rs.next()){
                System.out.println(rs.getString("ename"));
            }
        } catch ( Exception 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();
                }
            }
        }*/

        //用户在控制台输入desc就是降序,输入asc就是升序
        Scanner s=new Scanner(System.in);
        System.out.println("请输入desc或asc,desc表示降序,asc表示升序");
        System.out.println("请输入:");
        String keywords=s.nextLine();
        //执行SQL
        Connection conn=null;
        Statement stmt=null;
        ResultSet rs=null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","xqy2261579446");
            //获取数据库操作对象
            stmt=conn.createStatement();
            //执行sql
            String sql="select ename from emp order by ename "+ keywords;
            rs=stmt.executeQuery(sql);
            while (rs.next()){
                System.out.println(rs.getString("ename"));
            }
        } 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();
                }
            }
        }

    }


}

7、PreparedStatement完成insert delete update

public class Test09 {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement ps=null;
        try {
            //1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、建立连接
            conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","xqy2261579446");
            //3、获取预编译的数据库操作对象
            /*
            String sql="insert into dept(deptno,dname,loc) values(?,?,?)";
            ps=conn.prepareStatement(sql);
            ps.setInt(1,60);
            ps.setString(2,"销售部");
            ps.setString(3,"上海");
             */

           /* String sql="update dept set dname=?,loc=? where deptno=?";
            ps=conn.prepareStatement(sql);
            ps.setString(1,"研发一部");
            ps.setString(2,"北京");
            ps.setInt(3,60);*/

            String sql="delete from dept where deptno = ?";
            ps=conn.prepareStatement(sql);
            ps.setInt(1,60);



            //4、执行SQL
            int count=ps.executeUpdate();
            System.out.println(count);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //6、释放资源
            if (ps !=null){
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn !=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

10、JDBC事务机制

1、JDBC中的事务是自动提交的,什么是自动提交?
只要执行任意一条DML语句, 则自动提交一次。这是JDBC默认的事务行为。
但是在实际的业务当中,通常都是N条DML语句共同联合才能完成的,必须
保证他们这些DML语句在同一个事务中同时成功或者同时失败。
2、以下程序先来验证一下JDBC的事务是否是自动提交机制!
测试结果:JDBC中只要执行任意一条DML语句,就提交一次。

public class Test10 {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement ps=null;
        try {
            //1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、建立连接
            conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","xqy2261579446");
            //3、获取预编译的数据库操作对象
            String sql="update dept set dname = ? where deptno = ?";
            ps=conn.prepareStatement(sql);

            //第一次给占位符传值
            ps.setString(1,"x部门");
            ps.setInt(2,30);
            int count=ps.executeUpdate();//执行第一条UPDATE语句
            System.out.println(count);
            //重新给占位符传值
            ps.setString(1,"y部门");
            ps.setInt(2,20);
            count=ps.executeUpdate();//执行第二条UPDATE语句
            System.out.println(count);



        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //6、释放资源
            if (ps !=null){
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn !=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

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

/**
 * sql脚本
 * drop table if exists t_act;
 * create table t_act(
 *      actno int,
 *      balance double(7,2)//注意:7表示有效数字的个数(从左往右第一个不是0的数字开始成为有效数字),2表示小数位的个数
 * );
 * insert into t_act(actno,balance) values(111,20000);
 * insert into t_act(actno,balance) values(222,0);
 * commit;
 * select * from t_act;
 *
 * 重点代码:
 *      conn.setAutoCommit(false);
 *      conn.commit();
 *      conn.rollback();
 */
public class Test11 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            //1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、建立连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode", "root", "xqy2261579446");
           //将自动提交机制修改为手动提交
            conn.setAutoCommit(false);//开启事务

            //3、获取预编译的数据库操作对象
            String sql = "update t_act set balance = ? where actno = ?";
            ps = conn.prepareStatement(sql);
            //给?传值
            ps.setDouble(1, 10000);
            ps.setInt(2, 111);
            int count = ps.executeUpdate();

//            String s=null;
//            s.toString();

            //给?传值
            ps.setDouble(1, 10000);
            ps.setInt(2, 222);
            count += ps.executeUpdate();
            System.out.println(count == 2 ? "转账成功" : "转账失败");
            //程序能够走到这里说明以上程序没有异常,事务结束,手动提交数据
            conn.commit();//提交事务
        } catch (Exception e) {
            if (conn !=null){
                try {
                    conn.rollback();//回滚事务
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
        } finally {
            //6、释放资源
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

11、JDBC工具类,简化JDBC编程

public class DBUtil {
    /**
     * 工具类的构造方法都是私有的
     * 因为工具类当中的方法都是静态的,不需要new对象,直接用类名调用
     */
    private DBUtil(){

    }
    //静态代码块在类加载的时候执行,并且只执行一次
    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

    /**
     * 获取数据库连接对象
     * @return 连接对象
     * @throws SQLException
     */
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","xqy2261579446");
    }

    /**
     * 关闭资源
     * @param conn 连接对象
     * @param stmt 数据库操作对象
     * @param rs   结果集
     */
    public static void close(Connection conn, Statement stmt, ResultSet rs){
        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();
            }
        }

    }
}

12、java中的模糊查询

public class Test12 {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            //获取连接
            conn= DBUtil.getConnection();
            //获取预编译的数据库操作对象
            //错误写法
            /*String sql="select ename from emp where ename like '_?%'";
            ps=conn.prepareStatement(sql);
            ps.setString(1,"A");*/

            String sql="select ename from emp where ename like ?";
            ps=conn.prepareStatement(sql);
            ps.setString(1,"_A%");
            rs=ps.executeQuery();
            while (rs.next()){
                System.out.println(rs.getString("ename"));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //释放资源
            DBUtil.close(conn,ps,rs);
        }
    }
}

13、乐观锁和悲观锁

在这里插入图片描述

/**
 * 这个程序开启一个事务,这个事务专门进行查询,并且使用行级锁/悲观锁,
 * 锁住相关的记录
 */
public class Test13 {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            conn= DBUtil.getConnection();
            conn.setAutoCommit(false);
            String sql="select ename,job,sal from emp where job = ? for update";
            ps=conn.prepareStatement(sql);
            ps.setString(1,"MANAGER");
            rs=ps.executeQuery();
            while (rs.next()){
                System.out.println(rs.getString("ename")+","+rs.getString("job")+","+rs.getDouble("sal"));
            }
            conn.commit();

        } catch (SQLException e) {
            if (conn != null){
                try {
                    //回滚事务(事务结束)
                    conn.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
        }finally {
            DBUtil.close(conn,ps,rs);
        }
    }
}

/**
 * 修改被锁定的记录
 */
public class Test14 {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement ps=null;
        try {
            conn= DBUtil.getConnection();
            conn.setAutoCommit(false);
            String sql="update emp set sal =sal * 1.1 where job = ?";
            ps.setString(1,"MANAGER");
            int count=ps.executeUpdate();
            System.out.println(count);
            conn.commit();
        } catch (SQLException e) {
            if (conn !=null){
                try {
                    conn.rollback();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
            }
            e.printStackTrace();
        }finally {
            DBUtil.close(conn,ps,null);
        }

    }
}

在test13中提交事务之前设置断点,test13不结束,test14无法执行完成,只有test13结束了,test14才乐意执行完。验证了悲观锁一旦锁上,想要修改记录或者执行其它操作需要排队等待。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值