• JAVA 高级特性 JDBC


     需要的jdbc jar 包:
    数据持久化分为很多状态 
    瞬时状态: 保存在内存的程序数据,程序退出后,数据就消失了,称为瞬时状态。
    持久化:  将程序数据在瞬时状态和持久状态之间转换的机制。
    持久状态: 保存在磁盘上的程序数据,程序退出后依然存在,称为程序数据的持久状态。

     数据持久化技术:

    Hibernate : hibernate为应用程序提供了高效的O/R关系映射和查询服务,为面向对象的领域模型到传统的关系型数据库的映射,提供了一个使用方便的框架。
    JPA :  JPA(Java Persistense API)是EJB3.0的一部分,为其提供了一套O/R关系映射的API,但不仅限于EJB中使用,它也可以在web应用或者应用程序客户端中被使用,
    甚至在Java桌面程序中被使用。
    JDBC :  JDBC API是一个Java API,可以访问任何类型的数据库的数据,尤其是存储在关系数据库中的数据。 
     JDBC 实现数据持久化。
     什么是JDBC ?
    JDBC 代表Java数据库连接 (Java Database Connectivity)  ,它是用于Java编程语言和数据库之间的数据库无关连接的标准Java API ,换句话说 JDBC 是用于在Java 语言编程中与数据库连接的API 。
    JDBC 库通常与数据库使用相关,如下面提到的每个任务的API 
    1 , 连接到数据库。
    2, 创建SQL语句
    3,在数据库中执行SQL语句查询
    4,查看和修改结果记录

    常见JDBC组件。

    DriverManager:     此类管理数据库驱动程序列表。 使用通信子协议将来自java应用程序的连接请求与适当的数据库驱动程序进行匹配。在JDBC下识别某个子协议的第一个驱动程序将用于建立数据库连接。
    Driver:   此接口处理与数据库服务器的通信。我们很少会直接与Driver对象进行交互。 但会使用DriverManager对象来管理这种类型的对象。 它还提取与使用Driver对象相关的信息。
    Connection:   此接口具有用于联系数据库的所有方法。 连接(Connection)对象表示通信上下文,即,与数据库的所有通信仅通过连接对象。
    Statement:使用从此接口创建的对象将SQL语句提交到数据库。 除了执行存储过程之外,一些派生接口还接受参数。
    ResultSet:在使用Statement对象执行SQL查询后,这些对象保存从数据库检索的数据。 它作为一个迭代器并可移动ResultSet对象查询的数据。
    SQLException:此类处理数据库应用程序中发生的任何错误

    数据库操作 : 

    //加载驱动 
    Class.forName( 驱动路径 ) 
    //获取数据库连接
    //jdbc:mysql://主机名 : 端口号 / 数据库名
    DriverManager . getconnection
    Statement 对象。
    当获得了与数据库的连接,就可以与数据库进行交互了。JDBC Statement ,CallableStatement 和PreparedStatement  接口定义了可用于发送SQL 或PL/SQL命令。并从数据库接收数据的方法和属性,它们还定义了有助于在Java 和SQL数据类型的数据类型差异转换方法。
    利用Statement 对象操作数据库。
     

    PreparedStatement操作数据库   

    Statement对数据库中的表内容进行增删改操作, 每次增加删除修改都需要加载数据库驱动,连接数据库,执行SQL语句,关闭数据库,这样的话,代码的重复量有些大,代码冗余比较明显,后来进行修改,运用了Java继承封装和多态的思想,对原来的增删改代码进行了优化,在现实的开发中常用PreparedStatement接口而不是Statement接口进行增删改操作:使用PreparedStatement对于代码的可维护性和可读性提高了;使用PreparedStatement尽最大可能提高性能;最重要的一点是极大地提高了安全性。
    PreparedStatement是Statement接口的子接口,属于预处理操作,与直接使用Statement不同,PreparedStatement在操作时,是预先在数据表中准备好了一条SQL语句,但是此SQL语句的具体内容暂时不设置,而是之后在进行设置。
    PreparedStatement实例包含已编译的SQL语句,SQL语句可能包含1个,2个或多个输入的值,这些值未被明确指定在SQL语句中用?作为占位符代替,之后执行SQL语句之前要用setXXX()方法对值进行写入。
    PreparedStatement对象比Statement对象的执行速度要快,因为PreparedStatement对象已经预编译过了,因此需要多次执行的SQL语句也可以用PreparedStatement对象进行执行来加快执行速度。  作为Statement的子类,PreparedStatement接口继承了Statement的所有功能。另外它还整合一整套getXXX()和setXXX()方法,用于对值得获取和输入设置。同时,它还修改了三个方法execute、executeQuery、executeUpdate使它们不需要参数。这些方法的Statement形式,不应该再用于PreparedStatement对象。
    常用方法摘要:

    executeQuery:

    用于产生单个结果集(ResultSet)的语句,例如:被执行最多的SELECT 语句。 
    这个方法被用来执行 SELECT 语句,但也只能执行查询语句,执行后返回代表查询结果的ResultSet对象。
    executeUpdate:
    用于执行 INSERT、UPDATE 或 DELETE 语句以及 SQL DDL(数据定义语言)语句,例如 CREATE TABLE 和 DROP TABLE。
    INSERT、UPDATE 或 DELETE 语句的效果是修改表中零行或多行中的一列或多列。executeUpdate 的返回值是一个整数(int),指示受影响的行数(即更新计数)。对于 CREATE TABLE 或 DROP TABLE 等不操作行的语句,executeUpdate 的返回值总为零。

    execute: 

        可用于执行任何SQL语句,返回一个boolean值,表明执行该SQL语句是否返回了ResultSet。如果执行后第一个结果是ResultSet,则返回true,否则返回false。
    但它执行SQL语句时比较麻烦,通常我们没有必要使用execute方法来执行SQL语句,而是使用executeQuery或executeUpdate更适合。但如果在不清楚SQL语句的类型时则只能使用execute方法来执行该SQL语句了。
      4:getMetaData():获取包含有关ResultSet对象列信息的ResultSetMetaData对象,ResultSet对象将在此执行PreparedStatement对象时返回。
      5:getParameterMetaData():获取此PreparedStatement对象的参数的编号、类型和属性。
      6:setAsciiStream(int parameterIndex, InputStream x, int longth):将指定参数设置为给定输入流,该输入流将具有给定字节数。
    statement、PreparedStatement和CallableStatement区别和联系: 
    1. Statement、PreparedStatement和CallableStatement都是接口(interface)。 
    2. Statement继承自Wrapper、PreparedStatement继承自Statement、CallableStatement继承自PreparedStatement。 
    3. Statement接口提供了执行语句和获取结果的基本方法; 
        PreparedStatement接口添加了处理 IN 参数的方法; 
        CallableStatement接口添加了处理 OUT 参数的方法。 
    4. a. Statement: 
        普通的不带参的查询SQL;支持批量更新,批量删除; 
     
         b. PreparedStatement: 
         可变参数的SQL,编译一次,执行多次,效率高; 
         安全性好,有效防止Sql注入等问题; 
         支持批量更新,批量删除; 
         c. CallableStatement: 
      继承自PreparedStatement,支持带参数的SQL操作; 
      支持调用存储过程,提供了对输出和输入/输出参数(INOUT)的支持; 
    Statement每次执行sql语句,数据库都要执行sql语句的编译 ,最好用于仅执行一次查询并返回结果的情形时,效率高于PreparedStatement。
    PreparedStatement是预编译的,使用PreparedStatement有几个好处 
    1. 在执行可变参数的一条SQL时,PreparedStatement比Statement的效率高,因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率要高。 
    2. 安全性好,有效防止Sql注入等问题。 
    3.  对于多次重复执行的语句,使用PreparedStament效率会更高一点,并且在这种情况下也比较适合使用batch; 
    4.  代码的可读性和可维护性。 
     
    注: 
    executeQuery:返回结果集(ResultSet),预编译状态下executeQuery( ) 不能传入参数,只有statement 连接对象才能传入参数
    executeUpdate: 执行给定SQL语句,该语句可能为 INSERT、UPDATE 或 DELETE 语句, 
    或者不返回任何内容的SQL语句(如 SQL DDL 语句)。 
    execute: 可用于执行任何SQL语句,返回一个boolean值, 
    表明执行该SQL语句是否返回了ResultSet。如果执行后第一个结果是ResultSet,则返回true,否则返回false。 
     
    假设现在有一个本地数据库 localhost 利用java 代码 进行数据库操作;
    package com.project.jdbc;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Scanner;
    import java.sql.CallableStatement;
    public class JdbcDemo {
        private static final String url = "jdbc:mysql://localhost:3306/test";
        private static final String userName = "root";
        private static final String passWord = "";
        //初始化驱动,静态代码块
        static {
            try {
                // 加载驱动
                Class.forName("com.mysql.jdbc.Driver");
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }   
        public static void main(String[] args) {
            JdbcDemo demo = new JdbcDemo();
            // 创建一个 Connection 连接对象 通过一个连接对象操作数据库,一个连接多个操作
            Connection con = JdbcDemo.getcon();
            //demo.updateprepareDemo(con);
            demo.callableDemo(con);
            demo.selectDemo(con);
            JdbcDemo.closeDemo(con);
        }
              //调用存储过程
         public void callableDemo(Connection con){
             //准备SQL
             String SQL ="{CALL test(?,?,?,?)}";
             //创建连接状态
             try {
                CallableStatement state = con.prepareCall(SQL);
                //设置参数
                state.setString(1, "LIDAHU");
                state.setInt(2, 23);
                state.setString(3, "man");
                state.registerOutParameter(4, java.sql.Types.INTEGER);
                //执行SQL
                state.execute();
                //处理结果
                //获取参数
                int result = state.getInt(4);
                if (result==1){
                    System.out.println("注册成功!");
                }else {
                    System.out.println("注册失败!");
                }
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
         }
            //利用预编译preparedstatement进行更新操作
        public void updateprepareDemo(Connection con) {
            // 准备SQL语句
    //      String SQL1 = "INSERT INTO student(id,name,age,sex) VALUES(8,'YANGWU',18,'woman')";
    //      String SQL2 = "DELETE FROM student WHERE id=1";  
            // 提交数据库的对象
            PreparedStatement state = null;
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入修改的姓名 :");
            String name = sc.nextLine();
            System.out.println("请输入年龄 : ");
            int age = sc.nextInt();
            //关闭自动提交 , 事务不会实现数据持久化,即不会写入到数据库里面
            try {
                con.setAutoCommit(false);
            } catch (SQLException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            String SQL3 = "UPDATE student SET name=? WHERE age=?";
            System.out.println(SQL3);
            //获取状态
            try {
                state = con.prepareStatement(SQL3);
                //设置参数, SQL语句里面的 ? 按照顺序。
                state.setString(1, name);       
                state.setInt(2,age);
                //executeUpdate 返回一个执行影响行数的int 提交SQL语句,执行SQL
                int set = state.executeUpdate();
                //处理执行结果
                if (set > 0) {
                    //结束事务 , 数据上传到数据库, 实现持久化
    con.commit();
                    System.out.println("执行成功: " + set + "行");
                }else {
                    //让其回滚。
                    con.rollback();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    state.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        //更新SQL 操作
        @SuppressWarnings("unused")
        public void updateDemo(Connection con) {
            // 准备SQL语句
            String SQL1 = "INSERT INTO student(id,name,age,sex) VALUES(8,'YANGWU',18,'woman')";
            String SQL2 = "DELETE FROM student WHERE id=1";
            String SQL3 = "UPDATE student SET name='NIHAO' WHERE id = 1";
            // 提交数据库的对象
            Statement state = null;
            try {
                state = con.createStatement();
                //executeUpdate 返回一个执行行数的int
                int set = state.executeUpdate(SQL1);
                System.out.println(set);
                if (set > 0) {
                    System.out.println("执行成功: " + set + "行");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    state.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        //获取连接对象
        public static Connection getcon(){
            Connection con = null;
            try {
                // 获取数据库连接
                con = DriverManager.getConnection(url, userName, passWord);
            } catch (Exception e) {
                // TODO: handle exception
            }
            return con;
        }
            
        
        // 查询方法
        public void selectDemo(Connection con) {
            // 步骤:
            // 创建提交对象,,结果集对象
            Statement state = null;
            ResultSet set = null;
            // 准备SQL语句
            String sql = "select * from student";
            // 执行SQL语句
            // 创建提交数据库的连接
            try {
                // 连接对象 ,执行executeQuery查询命令,并保存到结果集set里面
                state = con.createStatement();
                set = state.executeQuery(sql);
                // 处理结果集(对set 结果集进行遍历操作)
                // next(); 切换到下一条目标数据,如果存在下一条数据则返回true ,否则返回false
                while (set.next()) {
                    // 每次循环操作一条结果
                    int id = set.getInt("id");
                    String name = set.getString("name");
                    String sex = set.getString("sex");
                    int age = set.getInt("age");
                    System.out.println(id + " " + name + " " + sex + " " + age+ ";");
                }
                
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                try {
                    state.close();
                    set.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                
            }       
        }
        public static void closeDemo(Connection con) {
            // 关闭数据库连接
            // 处理异常
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    struts2的在aJax中无法传参数到后台使用:解决方法
    jqGrid的属性(2)特指内容属性
    [leetcode]Binary Tree Maximum Path Sum
    判断二叉树是否平衡(Bottomup)
    [转]反向迭代器(rbegin,rend)
    Crack Interview 3.3
    Crack Interview 9.1 合并排序数组
    字符串转整数
    [转]了解如何通过reverse_iterator的base得到iterator
    通过bitmap的方式用8个int实现对256个char是否出现过做记录
  • 原文地址:https://www.cnblogs.com/thelovelybugfly/p/10821962.html
Copyright © 2020-2023  润新知