JDBC使用流程

一、概述

  • JAVASE规范:指定Java命令开发时基本规则,比如如何创建一个类,如何实现一次循环遍历
  • JAVAEE规范:指定Java与不同的【服务器】进行联合开发时,需要遵守的规则。由于Java在日常开发中需要与13种类型服务器进行合作,因此在JAVAEE规范包含了13中规则。

JDBC规范是13种JAVAEE规范中的一种。其制定了Java与所有的【关系型数据库服务器(Oracle,sqlServer,mySql)】在进行联合开发时遵守规则,包括开发步骤以及涉及的接口,相关接口来自JDK中java.sql包。

JDBC规范中,只提供了开发时需要的接口并没有提供具体实现类,具体实现类由数据库服务器厂商提供,通过jar包形式提供

二、开发步骤

  1. 从数据库服务器厂商提供的jar包定位一个类(Driver)。来了解本次进行交流的数据库服务器类型,便于JVM对推送的SQL命令编译
  2. 在当前Java类与数据库服务器之间建立一个链接通道(Connection
  3. 在链接通道上创建一个交通工具(PreparedStatement
  4. 将Java类中SQL命令作为货物添加到交通工具上,由交通工具沿着链接通道将SQL命令推到数据库服务器,由数据库服务器自动执行SQL命令
  5. 数据库服务器在执行完毕SQL命令之后,必须将执行结果(ResultSet)交给交通工具,返回给当前Java类
  6. Java类从交通工具得到结果后,负责销毁掉交通工具和链接通道,来结束本次的交易

三、相关的类与接口

  1. com.mysql.jdbc.Driver
    来自于MySql提供jar包,用于通知JVM本次访问的数据库服务器类型。此时JVM根据信息,将推送的SQL命令进行对应的编译
  2. java.sql.Connection接口
    Connection接口修饰的对象,用于管理Java类与数据库服务器之间链接通道,开发人员习惯于将Connection接口修饰的对象称为【连接对象】
  3. java.sql.Statement接口(淘汰)
    Statement接口修饰的对象,用于管理链接通道上的【交通工具】开发人员习惯于将Statement接口修饰的对象称为【数据库操作对象】
  4. java.sql. PreparedStatement接口
    Statement接口的升级版,可以防止SQL注入,比Statement接口(编译n次,执行n次)执行速度快(编译一次,执行n次)

PreparedStatement是如何防止SQL注入?

使用 Statement 往sql语句中传递参数时,只是简单的字符串拼接,有SQL注入的风险:

SELECT COUNT(*) FROM EMP WHERE ENAME=yang or 1=1 AND PASSWORD=123   

而使用PreparedStatement 时,PreparedStatement 要求将SQL命令需要使用参数地方用"?"替换

String sql ="select count(*) from emp where ename = ? and password = ?" 

在执行时由PreparedStatement负责将外部的参数添加到占位符上,PreparedStatement将所有参数都作为字符串类型赋值,此时的sql就会变成如下的格式,可见,有效的防止的SQL注入:

SELECT COUNT(*) FROM EMP WHERE ENAME='yang or 1=1' AND PASSWORD='123'   
  1. java.sql.ResultSet接口
    MySql接收到查询命令时,将查询得到临时表作为货物返回给Java类,在Java类使用ResutlSet接口来管理接收到临时表。通常将ResultSet接口修饰的对象称为【结果集】

四、操作例子

1. 对数据库进行增/删/改时

public class Test1 {
    public static void main(String[] args) throws Exception {
        //货物
        String sql = "INSERT INTO DEPT VALUE(901,'小额贷款部门2','福建')";

        //1.通知JVM加载Driver类,让JVM了解本次进行交流的数据库服务器类型,便于进行对应编译
        Class.forName("com.mysql.jdbc.Driver");

        //2.在当前类文件与MySQL服务器之间建立一个链接通道
        /*
         * 第一个参数:访问的数据库地址
         * jdbc:mysql://mysql服务器IP地址:服务器端口号/访问数据库名称
         * 例子:
         * "jdbc:mysql://localhost:3306/bjpowernode"
         *
         * 第二个参数: 登录名  "root"
         *
         * 第三个参数: 登录密码  "123"
         */
        Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode", "root", "123");

        //2.在链接通道上创建一个交通工具 【数据库操作对象】
        Statement st = con.createStatement();

        //3.将SQL命令作为货物装上交通工具,由交通工具负责将SQL命令推送给MySql服务器来执行,并带回执行结果
        //executeUpdate只能推送用于修改数据行命令,比如 INSERT ,DELETE ,UPDATE,但是不能推送SELECT
        int result = st.executeUpdate(sql);
        if (result > 0) {
            System.out.println("插入成功");
        } else {
            System.out.println("插入失败");
        }
        //4.将交通工具和链接通道依次销毁

        if (st != null) {
            st.close();
        }
        if (con != null) {
            con.close();
        }
    }
}

2. 对数据库进行查询时

public class Test1 {
    public static void main(String[] args) throws Exception {
        //货物
        String sql = "select * from t where id=1";

        //1.通知JVM加载Driver类,让JVM了解本次进行交流的数据库服务器类型,便于进行对应编译
        Class.forName("com.mysql.jdbc.Driver");

        //2.在当前类文件与MySQL服务器之间建立一个链接通道
        /*
         * 第一个参数:访问的数据库地址
         * jdbc:mysql://mysql服务器IP地址:服务器端口号/访问数据库名称
         * 例子:
         * "jdbc:mysql://localhost:3306/bjpowernode"
         *
         * 第二个参数: 登录名  "root"
         *
         * 第三个参数: 登录密码  "123"
         */
        Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode", "root", "123");

        //2.在链接通道上创建一个交通工具 【数据库操作对象】
        Statement st = con.createStatement();

        //3.将SQL命令作为货物装上交通工具,由交通工具负责将SQL命令推送给MySql服务器来执行,并带回执行结果
        //执行sql的查询语句,查询结果封装在resultSet中。
        ResultSet rs = st.executeQuery(sql);

        while (rs.next()) {
            //通过resultSet.getXXX()来获取查询出的结果。
            //其中XXX表示数据的类型,可以通过形参来指定数据的列
        }
        //4.将交通工具和链接通道依次销毁

        if (rs != null) {
            rs.close();
        }

        if (st != null) {
            st.close();
        }
        if (con != null) {
            con.close();
        }
    }
}

五、事务管理

关键:要取消 Connection 的自动提交:con.setAutoConnmit(flase);

public class Main {
    public static void main(String[] args) throws Exception {
        String sql_1 = "insert into emp (empno,ename,deptno) value(555,'小崔',200)";
        String sql_2 = "insert into dept(deptno,dname,loc) value(200,'dept_200','bj')";

        Class.forName("com.mysql.jdbc.Driver");
        Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode", "root", "123");
        //通知MySQL服务器,要求获得一个事务对象管理权
        con.setAutoCommit(false);// 通知MySql,由当前通道推送过来的所有SQL命令都要交给同一个事务对象管理,这个事务对象管理权由当前的通道Connection对象负责

        PreparedStatement ps = con.prepareStatement("");//空车
        try {
            ps.executeUpdate(sql_1);// sql_1------>transaction——1对象
            ps.executeUpdate(sql_2);// sql_2------>transaction——1对象
            //此时通知事务对象,将本次备份的信息全部删除
            con.commit();  // commit;
        } catch (SQLException ex) {
            //推送的SQL命令中至少有一条不能正常执行的,此时通知事务对象将事务中所有的SQL命令都设置为无效
            con.rollback();  // rollback
            ex.printStackTrace();
        }

        if (ps != null) {
            ps.close();
        }

        if (con != null) {
            con.close();
        }
    }
}

六、JDBC封装

  1. JDBC开发步骤:

    1. 加载Driver类
    2. 创建连接通道
    3. 创建交通工具
    4. 交通工具推送SQL命令到数据库中执行,并带回处理结果
    5. 销毁相关资源(ps,con)
  2. 抽取出内容相对固定操作步骤封装成工具类

    1. 加载Driver类
    2. 创建连接通道
    3. 创建交通工具
    4. 销毁相关资源(ps,con)
public class DBUtil {
    private static final String url = "jdbc:mysql://localhost:3306/bjpowernode";
    private static final String root = "root";
    private static final String password = "123";
    private static Connection con = null;
    private static PreparedStatement ps = null;

    //1.加载Driver类
    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    //2.创建连接通道
    public static Connection getConnection() throws Exception {
        con = DriverManager.getConnection(url, root, password);
        return con;
    }

    //3.创建交通工具
    public static PreparedStatement createStatement(String sql) {
        try {
            getConnection();
            ps = con.prepareStatement(sql);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ps;
    }

    //4.销毁相关资源(ps,con)
    public static void close(ResultSet rs) {

        try {
            if (rs != null) {
                rs.close();
            }

            if (ps != null) {
                ps.close();
            }

            if (con != null) {
                con.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

七、创建连接池进行优化

在JDBC的操作中,主要是Connection连接对象的创建和销毁比较耗时间,可以通过监听器对象在项目启动阶段创建Connection,并保存到全局作用域对象中作为共享数据,在网站关闭时对Connection对象进行销毁。

public class OneListener implements ServletContextListener {

    //在项目【启动阶段】创建20个Connection,存入到全局作用域对象
    @Override
    public void contextInitialized(ServletContextEvent event) {
        Map map = new HashMap();
        //1.创建20个Connection
        for (int i = 1; i <= 20; i++) {
            try {
                Connection con = DBUtil.getConnection();
                map.put(con, true);//true 空闲  false被占用
                System.out.println("在项目启动时,创建Connection " + con);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //2.将map管理的20个Connection保存到全局作用域对象,作为共享数据
        ServletContext application = event.getServletContext();
        application.setAttribute("数据库连接池", map);


    }//map

    //在网站关闭时,将网站用过的20个Connection进行销毁
    @Override
    public void contextDestroyed(ServletContextEvent event) {

        //1.得到即将被销毁的Connection
        ServletContext application = event.getServletContext();

        //2.从application得到20个Connection,依次销毁
        Map map = (Map) application.getAttribute("数据库连接池");
        Iterator it = map.keySet().iterator();
        while (it.hasNext()) {
            Connection con = (Connection) it.next();
            System.out.println("在项目关闭期间,销毁Conection " + con);
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值