zoukankan      html  css  js  c++  java
  • JDBC学习总结 -- JDBC 快速入门 教程

    先感谢前人的劳动成果,

    本教程中含有多处指路,请注意筛选.

    详细请阅读官方文档:https://docs.oracle.com/javase/tutorial/jdbc/basics/index.html (不建议直接上手)

              https://www.journaldev.com/2681/jdbc-tutorial

    前置知识:基本SQL 语句,JAVA SE基础

     

    JDBC 目录:

    1.JDBC概念

    2.JDBC处理SQL语句的过程(建表,查表) 

    •  建立与数据库的连接
    •  创建 statement
    •  执行 Query
    •  处理 结果集(ResultSets)

     3.专题介绍

    • ResultSet 与 Statement 中的 Prestatement,CallableStatement 详细介绍
    • 批处理的使用 + 删除表格
    • DataSource 与连接池,事务 (DBCP,简易连接池)

    4.结尾

    • ORM
    • DAO封装自己的JDBC

     

    1. JDBC的概念  

    JDBC(Java DataBase Connectivity)

    是一种数据库连接技术,
    能实现Java程序对各种数据库的访问。由一组使用Java语言编写的类和接口(JDBC API)
    组成,他们位于java.sql以及javax.sql中。

    推荐解释指路 中的 (二.JDBC是什么)

     

    作用:

    1. 与数据库建立联系.

    2. 将编写好的SQL语句发送至数据库执行

    3. 对数据库返回的结果进行操作

     

    JDBC API

    • java.sql.*
    • javax.sql.*

      连接数据库相关的:

        DriverManager

        用URL连接数据库,

           在4.0版本之前要进行加载.  即用映射加载驱动 Class.forName("com.mysql.jdbc.Driver");

        DataSource  

       相对于DriverManager类,DataSource更适合用于获取操作数据的Connection对象,

       它相对灵活,并且支持 JNDI ,可以为servlet容器提供连接池 

       (可以去找DBCP的资料,这里涉及到了 The Java EE Tutorial.)

     连接池解释推荐指路,后续会解释DataSource的使用.

        Connection接口

       负责连接数据库并担任传送数据的任务。

      数据库SQL相关的:

       Statement接口

      负责执行SQL语句。

    • PreparedStatement: 预编译,可以让SQL拥有参数,防止SQL注入
    • CallableStatement:  可以Statement基础上执行存储过程

       ResultSet接口

      负责保存Statement执行后所产生的查询结果。

       RowSet接口:   

      RowSet 比 ResultSet 功能更多,更易使用,所有的RowSet对象都继承于 ResultSet.

     

    2.JDBC处理SQL语句的过程(建表,查表)

    使用JDBC 的步骤

    •  建立 与数据库的连接 (其中包括用
    •  创建 statement
    •  执行 Query
    •  处理 结果集(ResultSets)
    •  关闭 连接

    这里,我们使用MySQL 进行演示,

    如果你使用是JAVA DB,他自带了JDBC

    首先去MySQL官方下载 MYSQL 和 Connector/J.

     

    (以下内容请根据自己环境进行配置)(官方教程使用的是 Apache ANT)

    我们要使用 Connector/J

    这里我们使用Eclipse - 在项目窗口右击Properties

     之后选择 JAVA Build Path->中的Libraries ,然后点击右边的 Add External JARS 将Connector/J 中的JAR文件导入

     

    这样就可以开始编写了我们的JDBC了.

     

    1. 建立与数据库的连接,这里使用DriverManager

     我们需要用到DBMS的 URL 进行连接

    • 一般mysql的URL : jdbc:mysql://localhost:3306/
    • JDBC URL: jdbc:derby:testdb;create=true
    •  

    在用正确的用户密码,服务器等等参数连接数据库URL后,

    DriverManager 会返回一个Connection,

     

    我们编写一个方法来获取相关的Connection 

    //根据自己的数据库进行修改
    public class JDBCTutorials {
        String userName = "root"; //用户名
        String password = "password";//用户密码
        String dbms = "mysql";//数据库管理系统名称
        String serverName = "localhost";//服务器名称
        String portNumber = "3306";//服务器接口
        String Atribute = "serverTimezone=UTC"
                + "&characterEncoding=utf-8"
                + "&useSSL=false";//时区与SLL连接方式禁用
        String dbName = "crashcourse";//需要访问的数据库名称,可以为空,但是得自己用USE语句
        //jdbc:mysql://localhost:3306/
        //jdbc:derby:testdb;create=true
        public Connection getConnection() throws SQLException{
            Connection conn = null;
            Properties connectionPros = new Properties();//新建一个Propeties容器
            connectionPros.put("user", userName);
            connectionPros.put("password", password);
            if(this.dbms.equals("mysql")) {
                conn = DriverManager.getConnection("jdbc:" + this.dbms + "://" + this.serverName +
                                                        ":" + this.portNumber + "/" + this.dbName + "?" + this.Atribute,connectionPros);//获取连接
    
                //conn.setCatalog(this.dbName);
            } else if (this.dbms.equals("derby")) {
                conn = DriverManager.getConnection("jdbc:" + this.dbms + ":"+ this.dbName + ":" 
                                                    + ";create=true",connectionPros);
            }
            System.out.println("Connection DBMS Successfully");
            return conn;
        }
    }

    更改相关的参数后,如果出现

    "Connection DBMS Successfully"

    就说明连接数据库管理系统成功了.返回的Connection就要用到了, 

    接下来我们需要将SQL语句运用起来.

     

    2. 创建Statement , 和执行Query, ResultSet使用(建表 查表)

    接下来我们需要使用的表格如下:

    建立这个表格的SQL语句:

     

    //---------------------------------------建立表格-----------------------------------------
    CREATE TABLE customers
    (
      cust_id      int       NOT NULL AUTO_INCREMENT,
      cust_name    char(50)  NOT NULL ,
      cust_address char(50)  NULL ,
      cust_city    char(50)  NULL ,
      cust_state   char(5)   NULL ,
      cust_zip     char(10)  NULL ,
      cust_country char(50)  NULL ,
      cust_contact char(50)  NULL ,
      cust_email   char(255) NULL ,
      PRIMARY KEY (cust_id)
    ) ENGINE=InnoDB;
    
    //---------------------------------------填充数据-----------------------------------------
    INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
    VALUES(10001, 'Coyote Inc.', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'Y Lee', 'ylee@coyote.com');
    INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
    VALUES(10002, 'Mouse House', '333 Fromage Lane', 'Columbus', 'OH', '43333', 'USA', 'Jerry Mouse');
    INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
    VALUES(10003, 'Wascals', '1 Sunny Place', 'Muncie', 'IN', '42222', 'USA', 'Jim Jones', 'rabbit@wascally.com');
    INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
    VALUES(10004, 'Yosemite Place', '829 Riverside Drive', 'Phoenix', 'AZ', '88888', 'USA', 'Y Sam', 'sam@yosemite.com');
    INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
    VALUES(10005, 'E Fudd', '4545 53rd Street', 'Chicago', 'IL', '54545', 'USA', 'E Fudd');
    

     

    那么我们怎么使用上面的SQL语句?

    首先,我们要知道之前编写的 getConnection 方法返回了一个connetion

    我们现在要再执行SQL语句的方法中使用它, SQL语句也需要先储存到一个String中

     

        public void createTable(Connection con) throws SQLException{
            String createSQL = "CREATE TABLE customers
    " + //存储SQL语句
                    "(
    " + 
                    "  cust_id      int       NOT NULL AUTO_INCREMENT,
    " + 
                    "  cust_name    char(50)  NOT NULL ,
    " + 
                    "  cust_address char(50)  NULL ,
    " + 
                    "  cust_city    char(50)  NULL ,
    " + 
                    "  cust_state   char(5)   NULL ,
    " + 
                    "  cust_zip     char(10)  NULL ,
    " + 
                    "  cust_country char(50)  NULL ,
    " + 
                    "  cust_contact char(50)  NULL ,
    " + 
                    "  cust_email   char(255) NULL ,
    " + 
                    "  PRIMARY KEY (cust_id)
    " + 
                    ") ENGINE=InnoDB;";
            try(Statement statement = con.createStatement()){//用connection 创建一个statement
                statement.executeUpdate(createSQL);//编译SQL语句
            }catch (Exception e) {
                System.out.println(e);
            }
        }

    这样,建表的SQL语句就完成了.

     

    为什么要把statement的建立写到try中?

       因为JAVA7 提供了自动关闭资源的机制 

    executeUpdate是什么?

       与之对于的是execute,executeQuery

    • executeQuery 只执行查 (select语句)
    • executeUpdate 执行 增删改  (insert或者update/delete(DML)语句,或者 什么也不返回的DDL语句)
    • execute 执行 增删改查

     

    我们建立了表,但是表是空的,我们应该怎么样使用SQL的插入语句?

      原理类似

    	public void populateTable(Connection con) throws SQLException{
    		try(Statement statement = con.createStatement()){
    			statement.executeUpdate("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
    " + 
    					"VALUES(10001, 'Coyote Inc.', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'Y Lee', 'ylee@coyote.com');");
    			statement.executeUpdate("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
    " + 
    					"VALUES(10002, 'Mouse House', '333 Fromage Lane', 'Columbus', 'OH', '43333', 'USA', 'Jerry Mouse');");
    			statement.executeUpdate("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
    " + 
    					"VALUES(10003, 'Wascals', '1 Sunny Place', 'Muncie', 'IN', '42222', 'USA', 'Jim Jones', 'rabbit@wascally.com');");
    			statement.executeUpdate("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
    " + 
    					"VALUES(10004, 'Yosemite Place', '829 Riverside Drive', 'Phoenix', 'AZ', '88888', 'USA', 'Y Sam', 'sam@yosemite.com');");
    			statement.execute("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
    " + 
    					"VALUES(10005, 'E Fudd', '4545 53rd Street', 'Chicago', 'IL', '54545', 'USA', 'E Fudd');");//这里需要使用excute,因为返回多个ResultSet
    		}catch (Exception e) {
    			System.out.println(e);
    		}
    	}

     

    接着,写一个查询表的方法

    	public void viewTable(Connection con,String dbName) throws SQLException{//查询表的功能
    		String query =  
    				"SELECT * FROM customers;";//SQL语句
    		try(Statement statement = con.createStatement()){//创建Statement
    			ResultSet resultSet = statement.executeQuery(query);//编译SQL语句,用ResultSet存储查询结果
    			while(resultSet.next()) {//换一行
    				String custID = resultSet.getString("cust_id");//获取该行列为"cust_id"的的数据
    				String custName = resultSet.getString("cust_name");
    				String custAddress = resultSet.getString("cust_address");
    				System.out.println(custID + ", " + custName + ", " + 
    									custAddress);
    			}
    		}catch (SQLException e) {
    			System.out.println(e);
    		}
    	}

    注意:

      executeQuery 是只能执行一条SQL 语句的,要执行多条需要用到批处理

     

    3.使用

    	public static void main(String[] args) {
    		JDBCTutorials jdbcTutorials = new JDBCTutorials();
    		try (Connection connection = jdbcTutorials.getConnection()){
    			jdbcTutorials.createTable(connection);
    			jdbcTutorials.populateTable(connection);
    			jdbcTutorials.viewTable(connection,"crashcourse");
    		}catch (SQLException e) {
    			System.out.println(e);
    		}
    	}

    执行结果:

     

    4.关闭步骤

    一般步骤是:

    } finally {
        if (stmt != null) { stmt.close(); }
    }
    

     不过后来JAVA 7出那个新特性,可以用try来自动关闭了

    try (Statement stmt = con.createStatement()) {
        // ...
    }

     

    ============SQL 语句的处理 以及 连接数据库 的入门结束============

    3.专题讲解

    1.ResultSet 讲解 推荐阅读:

    http://www.iteye.com/topic/560109  

    https://www.cnblogs.com/zxg-6/p/5598329.html 

    https://www.tutorialspoint.com/jdbc/jdbc-result-sets.htm (英文)

    JAVADOC : https://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html

    ResultSet 有不同功能特性,

    1.1 三个特性

    1. 类型
    2. 并发性
    3. 光标保持性

     

    光标是什么?

       光标就是指向行的标记,告诉他指向了哪里.

      如图,左边的红箭头指向的,这个就是个光标,他指着第一行 (cust_id = 10001 .....)

     

    (1) ResultSet 有三个不同的类型,

    默认类型:TYPE_FORWARD_ONLY.

    TYPE_FORWARD_ONLY:

       光标只能向前滚动, (只能使用 next() )

      效率:高

    TYPE_SCROLL_INSENSITIVE:

       前后鼓动的方法 next(),previous() ,回到首尾的方法 first(),last() , 到达指定位置的方法 absolute(int n ) // n代表行数,下标从1开始

       光标可以向前向后滚动,对数据库的更改不敏感,

       效率:中等

    TYPE_SCROLL_SENSITIVE:

      光标可以前后移动,对数据库的更改敏感

      只对UPDATE操作有效,对INSERT,DELETE无效

      (敏感的意思就是你数据库更改后,ResultSet的数据也会更改,比如数据库中第一行第一列的

      "苹果"变为"李子",ResultSet也会跟着变化)

      效率:低

     

    (2) 并发性

    默认类型:CONCUR_READ_ONLY.
    CONCUR_READ_ONLY: 

      只读,在ResultSet中的数据无法更改
    CONCUR_UPDATABLE

      在ResultSet中的数据可以更改

    注意:有些JDBC drivers 和 数据 不支持并发.

     

    (3)光标保持性

    默认类型取决你的DBMS

    HOLD_CURSORS_OVER_COMMIT:

      在事务commit 或rollback 后,ResultSet 仍然可用 (推荐在大部分ResultSet 都是 CONCUR_READ_ONLY 的情况下使用)
    CLOSE_CURSORS_AT_COMMIT:

      在事务commit 或rollback 后,ResultSet 不可用

    注意:不是所有 数据库支持

     

    (4)检测当前数据库时候支持某种特性

    boolean supportsResultSetType(int resultSetType); //类型
    boolean supportsResultSetConcurrency(int type, int concurrency);//并发性
    boolean supportsResultSetHoldability(int holdability);//保持性

    public static void cursorHoldabilitySupport(Connection conn)
    	    throws SQLException {
    
    	    DatabaseMetaData dbMetaData = conn.getMetaData();
    
    	    System.out.println("Default cursor holdability: " +
    	        dbMetaData.getResultSetHoldability());//检测是否支持并发性
    
    	    System.out.println("Supports HOLD_CURSORS_OVER_COMMIT? " +
    	        dbMetaData.supportsResultSetHoldability(
    	            ResultSet.HOLD_CURSORS_OVER_COMMIT));//检测时候支持并发性的某一种
    
    	    System.out.println("Supports CLOSE_CURSORS_AT_COMMIT? " +
    	        dbMetaData.supportsResultSetHoldability(
    	            ResultSet.CLOSE_CURSORS_AT_COMMIT));
    	}
    

     

    1.2 功能

    1.2.1 控制光标的函数介绍:

    前后滚动的方法 next(),previous()

    回到首尾的方法 first(),last()

    到达指定位置的方法 absolute(int n) // n代表行数,下标从1开始

                relative(int n) 移动到相对于当前位置

    移动到最后一行后面,此时没有指向任意行 afterLast()

    移动到第一行前面,此时没有指向任意行 beforeFirst()

     

    1.2.2 ResultSet支持用下标进行查询,查询更高效

    从左到右,下标从1开始,(即1 代表cust_id 列)

     如: int custID = resultSet.getInt(1); // 获取该行第一列的整数

    示范代码:

        public void viewTable(Connection con,String dbName) throws SQLException{
            String query =  
                    "SELECT * FROM customers;";//查询 SQL语句
            try(Statement statement = con.createStatement()){//创建Statement
                ResultSet resultSet = statement.executeQuery(query);//编译SQL语句
                while(resultSet.next()) {
                    int custID = resultSet.getInt(1); // 获取该行第一列的整数,即cust_id的信息
                    String custName = resultSet.getString(2);
                    String custAddress = resultSet.getString(3);
                    System.out.println(custID + ", " + custName + ", " + 
                                        custAddress);
                }
            }catch (SQLException e) {
                System.out.println(e);
            }
        }

     

    1.2.3 用ResultSet 更新行

    用ResultSet.updateFloat(int columnInex ,  Array x) 去更新行,让行进行改变,

    只有在执行Result.updateRow() 之后,改变才会生效.

        public void changeTable(Connection con,String dbName) throws SQLException{
            String query =  
                    "SELECT * FROM customers;";//SQL语句
            try(Statement statement = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE)){//创建Statement
                ResultSet resultSet = statement.executeQuery(query);//编译SQL语句
                resultSet.afterLast();//从前往后更新ID,因为他是 PRIMARY KEY不能重复
                while(resultSet.previous()) {
                    int custID = resultSet.getInt(1);
                    resultSet.updateInt(1, custID+1);//客服ID + 1
                    resultSet.updateRow();//更改生效
                }
            }catch (SQLException e) {
                System.out.println(e);
            }
        }

     

    1.2.4 用ResultSet 插入行 

    注意:有些JDBC driver不支持 这个功能,如果不支持,会抛出一个 SQLFeatureNotSupportedException  异常

    先用 ResultSet.moveToInsertRow(); 将光标移动到要插入的地方

    之后用 ResultSet.update() 修改要插入的数据

    最后用 ResultSet.insertRow(); 完成插入

        public void insertTableReSet(Connection con) throws SQLException{
            String query =  
                    "SELECT * FROM customers;";//SQL语句
            try (Statement statement = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE)){
                ResultSet resultSet = statement.executeQuery(query);
                resultSet.moveToInsertRow();
                resultSet.updateInt(1, 10006);
                resultSet.updateString(2, "New Man");
                resultSet.updateString(3, "3123 street");
                resultSet.insertRow();
            }catch (Exception e) {
                System.out.println(e);
            }
        }

     

    2.Statement 

    2.1 Statement 方法

    Statement和ResultSet是怎么工作的?

      查询到的的数据先存到数据库的缓冲中,ResultSet就是对缓冲数据的应用.

    setFetchsize 设置每次获取的数据数(rs.next),当数据数量多,处理时间长,就需要用到

    setMaxRows 限制返回的数据集数量,类似SQL 中的LIMIT

    getGeneratedKeys() 获取自动生成的主键值.

    executeQuery 只执行查 (select语句)

    executeUpdate 执行 增删改  (insert或者update/delete(DML)语句,或者 什么也不返回的DDL语句)

    execute 执行 增删改查

     

    2.2  PreparedStatement

    PreparedStatement 是一个预编译SQL语句,可以用setter传入参数

    也就是可以用有参数的SQL语句了,参数代替用 ? 从左往右排序, 下标为1开始.

    动态参数化用来查询的 演示代码:

        public void viewTablePreparedStatement(Connection con,String dbName) throws SQLException{
            String query =  
                    "SELECT * FROM customers WHERE cust_id = ?;";// ? 可以用一个参数代替
            try(PreparedStatement statement = con.prepareStatement(query)){//创建Statement
                ResultSet resultSet = statement.executeQuery(query);//编译SQL语句
                int i = 0;
                while(resultSet.next()) {
                    statement.setInt(1, 10001 + i++);//用 10001 + i 替代 第一个 ?
                    int custID = resultSet.getInt(1);
                    String custName = resultSet.getString(2);
                    String custAddress = resultSet.getString(3);
                    System.out.println(custID + ", " + custName + ", " + 
                                        custAddress);
                }
            }catch (SQLException e) {
                System.out.println(e);
            }
        }

     

    可以用一个循环去设置参数

    for(Map.Entry<Integer, String> e: customerCondition.entrySet()) {
        statement.setInt(1, e.getKey());
        statement.setString(2, e.getValue());
      //写执行语句
    }

    演示代码:

        public void viewTablePreparedStatement(Connection con,String dbName) throws SQLException{
            String query =  
                    "SELECT * FROM customers WHERE cust_id = ? AND cust_name = ?;";//? 可以用一个参数代替
            HashMap<Integer, String> customerCondition = new HashMap<>();
            customerCondition.put(10001, "Coyote Inc.");
            customerCondition.put(10002, "Mouse House");
            customerCondition.put(10003, "Wascals");
            customerCondition.put(10004, "Yosemite Place");
            customerCondition.put(10005, "New Man");
            
            try(PreparedStatement statement = con.prepareStatement(query)){//创建Statement
                ResultSet resultSet = statement.executeQuery(query);//编译SQL语句
                int i = 0;
                for(Map.Entry<Integer, String> e: customerCondition.entrySet()) {
                    statement.setInt(1, e.getKey());
                    statement.setString(2, e.getValue());
                    resultSet.next();
                    int custID = resultSet.getInt(1);
                    String custName = resultSet.getString(2);
                    String custAddress = resultSet.getString(3);
                    System.out.println(custID + ", " + custName + ", " + 
                                        custAddress);
                }
            }catch (SQLException e) {
                System.out.println(e);
            }
        }

     

    优点:

      性能比Statement 好,

      还可以防止臭名昭著的 SQL注入 攻击, 简单原理

      应该尽量使用PreparedStatement.

    缺点:

      无法使用 IN 语句,

    解放方案

      1.多个单条SQL语句拼成与有 IN 语句一样的查询 -- 效率低

      2.使用存储过程, (因为存储过程是数据库专有,

      推荐在只使用一种数据库 和 不打算换数据库服务器 的情况下使用)

      3.动态生成PreparedStatement查询 (但是无法 使用 PreparedStatement caching)

      4.使用NULL在PreparedStatement查询.(推荐)

    第四种方法的演示代码:

        public void viewTablePreaparedStatementNull(Connection con) {
             final String QUERY = "SELECT * FROM customers WHERE cust_id IN (?,?,?,?,?,?,?,?,?,?);";
             final int PARAM_SIZE = 10;
             int[] ids = {10001,10002,10003,10004,10005};
             if(ids.length > PARAM_SIZE) {
                 System.out.println("MAXIMUM INPUT SIZE " + PARAM_SIZE);
                 return;
             }
             int i = 1;
             try(PreparedStatement preparedStatement = con.prepareStatement(QUERY)){
                 for(; i<= ids.length;i++) {//填充参数
                     preparedStatement.setInt(i, ids[i-1]);
                 }
                 for(; i<=PARAM_SIZE;i++) {//设置未填充的参数为空
                     preparedStatement.setNull(i, java.sql.Types.INTEGER);
                 }
                 try(ResultSet re = preparedStatement.executeQuery()){
                     while(re.next()) {
                         System.out.println(re.getInt(1) + " "+ re.getString(2));
                     }
                 }catch (SQLException e) {
                     e.printStackTrace();
                }
             }catch (SQLException e) {
                 e.printStackTrace();
            }
        }

     

    2.3 CallableStatement

     调用储存过程

    SQL语句

    DROP procedure IF exists SHOW_CUSTOMERS;
    DELIMITER //
    CREATE PROCEDURE SHOW_CUSTOMERS(
        IN in_cust_id INT,
        OUT out_cust_name VARCHAR(40)
    )
    BEGIN
        SELECT cust_name FROM customers
        WHERE cust_id = in_cust_id INTO out_cust_name;
    END//
    DELIMITER ;
    
    CALL SHOW_CUSTOMERS(10006,@custID);
    SELECT @custID;

    演示代码:

    创建存储过程

        public void createStoredProcedure(Connection con) {
            String dropProcedure = "DROP procedure IF exists SHOW_CUSTOMERS;";
            String createProcedure = "CREATE PROCEDURE SHOW_CUSTOMERS(
    " + 
                    "    IN in_cust_id INT,
    " + 
                    "    OUT out_cust_name VARCHAR(40)
    " + 
                    ")
    " + 
                    "BEGIN
    " + 
                    "    SELECT cust_name FROM customers
    " + 
                    "    WHERE cust_id = in_cust_id INTO out_cust_name;
    " + 
                    "END;";
            try(CallableStatement cs = con.prepareCall(createProcedure);PreparedStatement ps = con.prepareStatement(dropProcedure)){
                ps.executeUpdate();
                cs.executeUpdate();
            }catch(SQLException e){
                e.printStackTrace();
            }
        }

    使用存储过程

        public void useStoredProcedure(Connection con) {
            try(CallableStatement cs = con.prepareCall("{CALL SHOW_CUSTOMERS(?,?)}")){
                cs.setInt(1, 10005);
                cs.registerOutParameter(2, Types.CHAR);
                cs.executeQuery();
                System.out.println(cs.getString(2));
            }catch(SQLException e) {
                e.printStackTrace();
            }
        }

    3.批处理 + 删除表格

    主要用到statement中

    addBatch ,executeBatch ,clearBatch 三个方法.

    即添加语句,执行语句,清除含有的语句.

     

    接下来我们需要用 批处理 重新创建 填充表格的方法,

    为了容易说明, 我们需要删除掉刚刚的表,然后重新创建,再填充.

     

    删表的原理类似与建表

        public void dropTable(Connection con) throws SQLException{
            String query = "DROP TABLE customers";
            try(Statement statement = con.createStatement()){//创建Statement
                statement.executeUpdate(query);//编译SQL语句
            }catch (SQLException e) {
                System.out.println(e);
            }
        }

     

    删除表之后,我们重新创建表(原理类似),然后再使用填充方法

    用批处理写的填充方法:

        public void populateTable(Connection con) throws SQLException{
            try(Statement statement = con.createStatement()){
                con.setAutoCommit(false);//开启事务
                statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
    " + 
                        "VALUES(10001, 'Coyote Inc.', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'Y Lee', 'ylee@coyote.com');");
                statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
    " + 
                        "VALUES(10002, 'Mouse House', '333 Fromage Lane', 'Columbus', 'OH', '43333', 'USA', 'Jerry Mouse');");
                statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
    " + 
                        "VALUES(10003, 'Wascals', '1 Sunny Place', 'Muncie', 'IN', '42222', 'USA', 'Jim Jones', 'rabbit@wascally.com');");
                statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
    " + 
                        "VALUES(10004, 'Yosemite Place', '829 Riverside Drive', 'Phoenix', 'AZ', '88888', 'USA', 'Y Sam', 'sam@yosemite.com');");
                statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
    " + 
                        "VALUES(10005, 'E Fudd', '4545 53rd Street', 'Chicago', 'IL', '54545', 'USA', 'E Fudd');");
                int[] successNum = statement.executeBatch();//返回成功数,并且执行批语句
                System.out.println("成功插入:" + Arrays.toString(successNum));
                con.commit();
            }catch (Exception e) {
                System.out.println(e);
            }finally{
                con.setAutoCommit(true);
            }
        }

     

    4.DataSource 与连接池,事务

    1.1DataSource 与连接池

    推荐阅读:https://www.cnblogs.com/kevinf/p/3705148.html

    一般开源的数据连接池有两种:C3P0 与 DBCP 区别与介绍

    接下来我们要用

    javax.sql.DataSource;

    中 DataSource 来写一个简易连接池.

    首先明确几个概念.

    连接池:

      连接数据库的操作十分昂贵,

      所以我们想到可以把已经建立好的连接先存起来,

      这就用到了连接池.

    动态代理模式:

      参考文章1 参考文章2 参考文章3

      使用一个代理类 代理 原有的对象, 在代理类中原有对象的方法调用之前,

      都要经过代理类的处理,然后再决定是否回到原有对象.

      比如: 我们的Connection中有一个close() 方法,意思就是关闭连接,

      那么我们需要修改Connecttion.close()的执行方式,这时候就需要

      写一个代理类代理Connection类.

    简易连接池的思路:

    1.实现DataSource接口,批量创建一定 连接(connection) 并且将其加入 容器 中

    2.每次使用getConnection(),都从容器中去除一个 连接(connection),如果容器中没有可用容器,提示"数据库繁忙"

    3.每次close的时候,保证用完的 连接(connection) 回到容器中.

    简易连接池代码:

    import java.io.IOException;
    import java.io.InputStream;
    import java.io.PrintWriter;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.sql.SQLFeatureNotSupportedException;
    import java.util.LinkedList;
    import java.util.Properties;
    import java.util.logging.Logger;
    
    import javax.management.RuntimeErrorException;
    import javax.sql.DataSource;
    
    public class JDBCPool implements DataSource{
        private static LinkedList<Connection> conPool = new LinkedList<Connection>();
        static {
            //InputStream in = JDBCPool.class.getClassLoader().getResourceAsStream("db.properties");
            //Properties pro = new Properties();
            try {
                //pro.load(in);
                //String driver = pro.getProperty("driver");
                //String url = pro.getProperty("url");
                //String username = pro.getProperty("username");
                //String password = pro.getProperty("password");
                //int jdbcPoolInitSize = Integer.parseInt(pro.getProperty("jdbcPoolInitSize"));
                String driver = "mysql";
                String url = "jdbc:mysql://localhost:3306/crashcourse?serverTimezone=UTC&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true";
                String username = "root";
                String password = "***";
                int jdbcPoolInitSize = 10;
                for(int i=0;i<jdbcPoolInitSize;i++) {
                        Connection connection  = DriverManager.getConnection(url,username,password);
                        System.out.println("初始化数据库 " + (i+1) + "个连接");
                        conPool.add(connection);
                 }
            }catch (SQLException e) {
                e.printStackTrace();
            }
        }
        @Override
        public Logger getParentLogger() throws SQLFeatureNotSupportedException {
            // TODO Auto-generated method stub
            return null;
        }
        @Override
        public <T> T unwrap(Class<T> iface) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
        @Override
        public boolean isWrapperFor(Class<?> iface) throws SQLException {
            // TODO Auto-generated method stub
            return false;
        }
        @Override
        public Connection getConnection() throws SQLException {
            // TODO Auto-generated method stub
            if(conPool.size() > 0) {
                final Connection conn = conPool.removeFirst();
                return (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(),
                        new Class[] {Connection.class},
                        new InvocationHandler() {
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                if(!"close".equals(method.getName())) {
                                    return method.invoke(conn, args);
                                }
                                else {
                                    conPool.add(conn);
                                    System.out.println("关闭连接,实际还给了连接池");
                                    System.out.println("池中连接数为 " + conPool.size());
                                    return null;
                                }
                            }
                        });
            }else {
                throw new RuntimeErrorException(null, "数据库繁忙");
            }
        }
        @Override
        public Connection getConnection(String username, String password) throws SQLException {
            return null;
        }
        @Override
        public PrintWriter getLogWriter() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
        @Override
        public void setLogWriter(PrintWriter out) throws SQLException {
            // TODO Auto-generated method stub
            
        }
        @Override
        public void setLoginTimeout(int seconds) throws SQLException {
            // TODO Auto-generated method stub
            
        }
        @Override
        public int getLoginTimeout() throws SQLException {
            // TODO Auto-generated method stub
            return 0;
        }
    }

    另一个调用类代码:

    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.sql.Types;
    import java.util.Properties;
    import java.sql.CallableStatement;
    import java.sql.Connection;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.LinkedList;
    import java.util.Map;
    import javax.sql.DataSource;
    
    public class JDBCTutorials {
        JDBCPool jdbcPool = new JDBCPool();
        String userName = "root"; //用户名
        String password = "***";//用户密码
        String dbms = "mysql";//数据库管理系统名称
        String serverName = "localhost";//服务器名称
        String portNumber = "3306";//服务器接口
        String Atribute = "serverTimezone=UTC"
                + "&characterEncoding=utf-8"
                + "&useSSL=false"
                + "&allowPublicKeyRetrieval=true";//时区与SLL连接方式禁用
        String dbName = "crashcourse";//数据库名称
        //jdbc:mysql://localhost:3306/
        //jdbc:derby:testdb;create=true
        public Connection getConnection() throws SQLException{
            Connection conn = jdbcPool.getConnection();
    //        Connection conn = null;
    //        Properties connectionPros = new Properties();
    //        connectionPros.put("user", userName);
    //        connectionPros.put("password", password);
    //        if(this.dbms.equals("mysql")) {
    //            conn = DriverManager.getConnection("jdbc:" + this.dbms + "://" + this.serverName +
    //                                                    ":" + this.portNumber + "/" + this.dbName + "?" + this.Atribute,connectionPros);
    //            //conn.setCatalog(this.dbName);
    //        } else if (this.dbms.equals("derby")) {
    //            conn = DriverManager.getConnection("jdbc:" + this.dbms + ":"+ this.dbName + ":" 
    //                                                + ";create=true",connectionPros);
    //        }
    //        System.out.println("Connection DBMS Successfully");
            return conn;
        }
        
        public void viewTable(Connection con,String dbName) throws SQLException{
            String query =  
                    "SELECT * FROM customers;";//SQL语句
            try(Statement statement = con.createStatement()){//创建Statement
                ResultSet resultSet = statement.executeQuery(query);//编译SQL语句
                while(resultSet.next()) {
                    int custID = resultSet.getInt(1);
                    String custName = resultSet.getString(2);
                    String custAddress = resultSet.getString(3);
                    System.out.println(custID + ", " + custName + ", " + 
                                        custAddress);
                }
            }catch (SQLException e) {
                System.out.println(e);
            }
        }
        
        public void viewTablePreparedStatement(Connection con,String dbName) throws SQLException{
            String query =  
                    "SELECT * FROM customers WHERE cust_id = ? AND cust_name = ?;";//? 可以用一个参数代替
            HashMap<Integer, String> customerCondition = new HashMap<>();
            customerCondition.put(10001, "Coyote Inc.");
            customerCondition.put(10002, "Mouse House");
            customerCondition.put(10003, "Wascals");
            customerCondition.put(10004, "Yosemite Place");
            customerCondition.put(10005, "New Man");
            
            try(PreparedStatement statement = con.prepareStatement(query)){//创建Statement
                ResultSet resultSet = statement.executeQuery(query);//编译SQL语句
                int i = 0;
                for(Map.Entry<Integer, String> e: customerCondition.entrySet()) {
                    statement.setInt(1, e.getKey());
                    statement.setString(2, e.getValue());
                    resultSet.next();
                    int custID = resultSet.getInt(1);
                    String custName = resultSet.getString(2);
                    String custAddress = resultSet.getString(3);
                    System.out.println(custID + ", " + custName + ", " + 
                                        custAddress);
                }
            }catch (SQLException e) {
                System.out.println(e);
            }
        }
        public void viewTablePreaparedStatementNull(Connection con) {
             final String QUERY = "SELECT * FROM customers WHERE cust_id IN (?,?,?,?,?,?,?,?,?,?);";
             final int PARAM_SIZE = 10;
             int[] ids = {10001,10002,10003,10004,10005};
             if(ids.length > PARAM_SIZE) {
                 System.out.println("MAXIMUM INPUT SIZE " + PARAM_SIZE);
                 return;
             }
             int i = 1;
             try(PreparedStatement preparedStatement = con.prepareStatement(QUERY)){
                 for(; i<= ids.length;i++) {
                     preparedStatement.setInt(i, ids[i-1]);
                 }
                 for(; i<=PARAM_SIZE;i++) {
                     preparedStatement.setNull(i, java.sql.Types.INTEGER);
                 }
                 try(ResultSet re = preparedStatement.executeQuery()){
                     while(re.next()) {
                         System.out.println(re.getInt(1) + " "+ re.getString(2));
                     }
                 }catch (SQLException e) {
                     e.printStackTrace();
                }
             }catch (SQLException e) {
                 e.printStackTrace();
            }
        }
        
        public void changeTable(Connection con,String dbName) throws SQLException{
            String query =  
                    "SELECT * FROM customers;";//SQL语句
            try(Statement statement = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE)){//创建Statement
                ResultSet resultSet = statement.executeQuery(query);//编译SQL语句
                resultSet.afterLast();//从前往后更新ID,因为他是 PRIMARY KEY不能重复
                while(resultSet.previous()) {
                    int custID = resultSet.getInt(1);
                    resultSet.updateInt(1, custID+1);//客服ID + 1
                    resultSet.updateRow();
                }
            }catch (SQLException e) {
                System.out.println(e);
            }
        }
        
        public void dropTable(Connection con) throws SQLException{
            final String QUERY = "DROP TABLE customers";
            try(Statement statement = con.createStatement()){//创建Statement
                statement.executeUpdate(QUERY);//编译SQL语句
            }catch (SQLException e) {
                System.out.println(e);
            }
        }
        public void createTable(Connection con) throws SQLException{
            String createSQL = "CREATE TABLE customers
    " + 
                    "(
    " + 
                    "  cust_id      int       NOT NULL AUTO_INCREMENT,
    " + 
                    "  cust_name    char(50)  NOT NULL ,
    " + 
                    "  cust_address char(50)  NULL ,
    " + 
                    "  cust_city    char(50)  NULL ,
    " + 
                    "  cust_state   char(5)   NULL ,
    " + 
                    "  cust_zip     char(10)  NULL ,
    " + 
                    "  cust_country char(50)  NULL ,
    " + 
                    "  cust_contact char(50)  NULL ,
    " + 
                    "  cust_email   char(255) NULL ,
    " + 
                    "  PRIMARY KEY (cust_id)
    " + 
                    ") ENGINE=InnoDB;";
            try(Statement statement = con.createStatement()){
                statement.executeUpdate(createSQL);
            }catch (Exception e) {
                System.out.println(e);
            }
        }
        
        public void populateTableBatch(Connection con) throws SQLException{
            try(Statement statement = con.createStatement()){
                con.setAutoCommit(false);//关闭事务自动commit 和 rollback
                statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
    " + 
                        "VALUES(10001, 'Coyote Inc.', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'Y Lee', 'ylee@coyote.com');");
                statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
    " + 
                        "VALUES(10002, 'Mouse House', '333 Fromage Lane', 'Columbus', 'OH', '43333', 'USA', 'Jerry Mouse');");
                statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
    " + 
                        "VALUES(10003, 'Wascals', '1 Sunny Place', 'Muncie', 'IN', '42222', 'USA', 'Jim Jones', 'rabbit@wascally.com');");
                statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
    " + 
                        "VALUES(10004, 'Yosemite Place', '829 Riverside Drive', 'Phoenix', 'AZ', '88888', 'USA', 'Y Sam', 'sam@yosemite.com');");
                statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
    " + 
                        "VALUES(10005, 'E Fudd', '4545 53rd Street', 'Chicago', 'IL', '54545', 'USA', 'E Fudd');");
                int[] successNum = statement.executeBatch();//返回成功数
                System.out.println("成功插入:" + Arrays.toString(successNum));
                con.commit();
            }catch (Exception e) {
                System.out.println(e);
            }finally{
                con.setAutoCommit(true);
            }
        }
        public void insertTableReSet(Connection con) throws SQLException{
            String query =  
                    "SELECT * FROM customers;";//SQL语句
            try (Statement statement = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE)){
                ResultSet resultSet = statement.executeQuery(query);
                resultSet.moveToInsertRow();
                resultSet.updateInt(1, 10006);
                resultSet.updateString(2, "New Man");
                resultSet.updateString(3, "3123 street");
                resultSet.insertRow();
            }catch (Exception e) {
                System.out.println(e);
            }
        }
        public void createStoredProcedure(Connection con) {
            String dropProcedure = "DROP procedure IF exists SHOW_CUSTOMERS;";
            String createProcedure = "CREATE PROCEDURE SHOW_CUSTOMERS(
    " + 
                    "    IN in_cust_id INT,
    " + 
                    "    OUT out_cust_name VARCHAR(40)
    " + 
                    ")
    " + 
                    "BEGIN
    " + 
                    "    SELECT cust_name FROM customers
    " + 
                    "    WHERE cust_id = in_cust_id INTO out_cust_name;
    " + 
                    "END;";
            try(CallableStatement cs = con.prepareCall(createProcedure);PreparedStatement ps = con.prepareStatement(dropProcedure)){
                ps.executeUpdate();
                cs.executeUpdate();
            }catch(SQLException e){
                e.printStackTrace();
            }
        }
        public void useStoredProcedure(Connection con) {
            try(CallableStatement cs = con.prepareCall("{CALL SHOW_CUSTOMERS(?,?)}")){
                cs.setInt(1, 10005);
                cs.registerOutParameter(2, Types.CHAR);
                cs.executeQuery();
                System.out.println(cs.getString(2));
            }catch(SQLException e) {
                e.printStackTrace();
            }
        }
        
        
        public static void main(String[] args) {
            JDBCTutorials jdbcTutorials = new JDBCTutorials();
            try (Connection connection = jdbcTutorials.getConnection()){
                jdbcTutorials.dropTable(connection);
                jdbcTutorials.createTable(connection);
                jdbcTutorials.populateTableBatch(connection);
                jdbcTutorials.insertTableReSet(connection);
                jdbcTutorials.viewTablePreaparedStatementNull(connection);
                jdbcTutorials.changeTable(connection,"crashcourse");
                System.out.println();
                jdbcTutorials.viewTable(connection,"crashcourse");
                System.out.println();
                jdbcTutorials.createStoredProcedure(connection);
                jdbcTutorials.useStoredProcedure(connection);
            }catch (SQLException e) {
                System.out.println(e);
            }
        }
    }
    View Code

    DBCP使用(JDNI):

    推荐阅读:https://www.cnblogs.com/sunseine/p/5947448.html

    去官方下三个包 http://commons.apache.org/proper/

    基础的BasicDataSource 就是我们的第三类DataSource(连接池,Connection,事务)

        public Connection getConnection()  {
            Connection con = null;
            BasicDataSource ds = new BasicDataSource();
            ds.setUrl("jdbc:mysql://localhost:3306/crashcourse?serverTimezone=GMT&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true");
            ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
            ds.setUsername("root");
            ds.setPassword("***");
            ds.setMaxTotal(30);
            try{
                con = ds.getConnection( );
            }catch(SQLException e) {
                e.printStackTrace();
            }
            return con;
        }

    我们可以用.properties 来保存BasicDataSource的配置

    ########DBCP配置文件##########
    #驱动名
    driverClassName=com.mysql.jdbc.Driver
    #url
    url=jdbc:mysql://127.0.0.1:3306/mydb
    #用户名
    username=sa
    #密码
    password=123456
    #初试连接数
    initialSize=30
    #最大活跃数
    maxTotal=30
    #最大idle数
    maxIdle=10
    #最小idle数
    minIdle=5
    #最长等待时间(毫秒)
    maxWaitMillis=1000
    #程序中的连接不使用后是否被连接池回收(该版本要使用removeAbandonedOnMaintenance和removeAbandonedOnBorrow)
    #removeAbandoned=true
    removeAbandonedOnMaintenance=true
    removeAbandonedOnBorrow=true
    #连接在所指定的秒数内未使用才会被删除(秒)(为配合测试程序才配置为1秒)
    removeAbandonedTimeout=1

    然后写一个类来用它

    public class JDBCPool {
        private static Properties properties = new Properties();
        private static DataSource dataSource;
        static {
            try (FileInputStream is = new FileInputStream("config/dbcp.properties")){
                dataSource = BasicDataSourceFactory.createDataSource(properties);
                properties.load(is);
            } catch (IOException e){
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        public static Connection getConnection() {
            Connection connection = null;
            try {
                connection = dataSource.getConnection();
            }catch(SQLException e){
                e.printStackTrace();
            }
            return connection;
        }
    }

     1.2 事务

    • 数据库中的一组相关的SQL语句,作为一个执行单元,全部执行成功,或者全部不执行,不能拆分的这种SQL语句组合的执行方式叫做事务
    • 转账是一种典型的使用事务的案例

      转出账户和转入账户必须同时执行成功才能算作是一次转账,如果一方没有执行成功,那么另一方也要不执行

    因为JDBC中commit是默认开启,

    要使用事务就得将其关闭,并且事务内的连接(Connection)只有一个

    Connection.setAutoCommit(false);

    在语句的最后使用 Connection.commit(); 提交

    或者在中途使用Connection.rollback();回滚

        public void populateTableBatch(Connection con) throws SQLException{
            try(Statement statement = con.createStatement()){
                con.setAutoCommit(false);//开启事务
                statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
    " + 
                        "VALUES(10001, 'Coyote Inc.', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'Y Lee', 'ylee@coyote.com');");
                statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
    " + 
                        "VALUES(10002, 'Mouse House', '333 Fromage Lane', 'Columbus', 'OH', '43333', 'USA', 'Jerry Mouse');");
                statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
    " + 
                        "VALUES(10003, 'Wascals', '1 Sunny Place', 'Muncie', 'IN', '42222', 'USA', 'Jim Jones', 'rabbit@wascally.com');");
                statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
    " + 
                        "VALUES(10004, 'Yosemite Place', '829 Riverside Drive', 'Phoenix', 'AZ', '88888', 'USA', 'Y Sam', 'sam@yosemite.com');");
                statement.addBatch("INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
    " + 
                        "VALUES(10005, 'E Fudd', '4545 53rd Street', 'Chicago', 'IL', '54545', 'USA', 'E Fudd');");
                int[] successNum = statement.executeBatch();//返回成功数
                System.out.println("成功插入:" + Arrays.toString(successNum));
                con.commit();
            }catch (Exception e) {
                System.out.println(e);
                con.rollback();
            }finally{
                con.setAutoCommit(true);
            }
        }

    =============== 专题介绍结束 ===============

    4.结尾

    1. ORM (Object relation mapping) 对象关系映射

    ORM 是一种思想,将数据库中的数据变成对象,对象变成数据库中的数据。

    因为我们编程语言是面对对象的,一切都是对象,而关系数据库是有数学理论发展起来的,

    这两者直接有一定区别,ORM就是为了解决这个问题而存在的。

     https://blog.csdn.net/ma15732625261/article/details/74332441

    ORM 工具介绍:ADO.NET等

    2. DAO 封装自己的JDBC

    DAO: DAO 就是一个模型,它将数据库与业务逻辑之间,将访问数据库的代码封装成一个类。(增删改,不包含业务信息)

    需要的包:

    http://commons.apache.org/proper/

    还是用上面的表

     写一个Customers 类

    public class Customers {
        int custID;
        String custName;
        String custAddress;
        String custCity;
        String custState;
        String custZip;
        @Override
        public String toString() {
            return "Customers [custID=" + custID + ", custName=" + custName + ", custAddress=" + custAddress + ", custCity="
                    + custCity + ", custState=" + custState + ", custZip=" + custZip + ", custCountry=" + custCountry
                    + ", custContact=" + custContact + ", custEmail=" + custEmail + "]";
        }
        String custCountry;
        String custContact;
        String custEmail;
        public int getCustID() {
            return custID;
        }
        public void setCustID(int custID) {
            this.custID = custID;
        }
        public String getCustName() {
            return custName;
        }
        public void setCustName(String custName) {
            this.custName = custName;
        }
        public String getCustAddress() {
            return custAddress;
        }
        public void setCustAddress(String custAddress) {
            this.custAddress = custAddress;
        }
        public String getCustCity() {
            return custCity;
        }
        public void setCustCity(String custCity) {
            this.custCity = custCity;
        }
        public String getCustState() {
            return custState;
        }
        public void setCustState(String custState) {
            this.custState = custState;
        }
        public String getCustZip() {
            return custZip;
        }
        public void setCustZip(String custZip) {
            this.custZip = custZip;
        }
        public String getCustCountry() {
            return custCountry;
        }
        public void setCustCountry(String custCountry) {
            this.custCountry = custCountry;
        }
        public String getCustContact() {
            return custContact;
        }
        public void setCustContact(String custContact) {
            this.custContact = custContact;
        }
        public String getCustEmail() {
            return custEmail;
        }
        public void setCustEmail(String custEmail) {
            this.custEmail = custEmail;
        }
        
    }

    DAO类:

    import java.lang.reflect.InvocationTargetException;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.SQLException;
    import java.util.HashMap;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Map;
    import org.apache.commons.beanutils.BeanUtils;
    public class Dao {
        
        public void updata(String sql,Object... args) {
            try(Connection con = JDBCTutorials.getConnection();
                    PreparedStatement pre = con.prepareStatement(sql)){
                for(int i=0;i<args.length;i++) {
                    pre.setObject(i+1, args);
                }
                pre.executeUpdate();
            }catch (SQLException e) {
                e.printStackTrace();
            }
        }
        
        @SuppressWarnings("deprecation")
        /**
         * 返回一条查询记录
         * @param rs
         * @return
         * @throws SQLException
         */
        public <T> T get(Class<T> dataClass,String sql,Object... args){
            List<T> list = new LinkedList<>();
            list = getForList(dataClass,sql,args);
            if(list.size() > 0) {
                return list.get(0);
            }else {
                return null;
            }
        }
        
        /**
         * 返回多条查询记录
         * @param rs
         * @return
         * @throws SQLException
         */
        @SuppressWarnings("deprecation")
        public <T> List<T> getForList(Class<T> dataClass,String sql,Object... args){
            //1.得到结果集
            List<T> list = new LinkedList<T>();
            
            try(Connection con = JDBCTutorials.getConnection();
                    PreparedStatement pre = con.prepareStatement(sql)){
                for(int i=0;i<args.length;i++) {
                    pre.setObject(i+1, args[i]);
                }
                try(ResultSet rs = pre.executeQuery()){
                    //2.处理结果集, 得到Map的List,其中一个Map对象对应着一条记录
                    //Map 的 Key 是 ReusltSet别名,value为列的值。
                    List<Map<String, Object>> mapList = handlerResultSetToMap(rs);
                    
                    //3.处理Map 中的List 变为 dataClass 的List
                    //Map的key 为 dataClass的属性名,value 为dataClass的属性值
                    list = transferMapListToLinkedList(dataClass, mapList);
                }catch (SQLException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }catch (SQLException e) {
                e.printStackTrace();
            }
            return list;
        }
    
        private <T> List<T> transferMapListToLinkedList(Class<T> dataClass,
                List<Map<String, Object>> mapList)
                throws InstantiationException, IllegalAccessException, InvocationTargetException {
            T entity = null;
            LinkedList<T> list = new LinkedList<T>();
            if(mapList.size()>0) {
                for(Map<String, Object> mt:mapList) {
                    entity = dataClass.newInstance();
                    for(Map.Entry<String, Object> m:mt.entrySet()) {
                        String proName = m.getKey();
                        Object value = m.getValue();
                        BeanUtils.setProperty(entity, proName, value);//填充entity的属性                
                    }
                    list.add(entity);
                }                    
            }
            return list;
        }
    
        private List<Map<String, Object>> handlerResultSetToMap(ResultSet rs) throws SQLException {
            List<Map<String,Object>> mapList = new LinkedList<Map<String,Object>>();
            List<String> columnLabel = getColumnLabels(rs);
            while(rs.next()) {
                Map<String,Object> mapz = new HashMap<String,Object>();
                for(String colName:columnLabel) {
                    Object colObject = rs.getObject(colName);
                    mapz.put(colName, colObject);
                }
                mapList.add(mapz);
            }
            return mapList;
        }
    
        public List<String> getColumnLabels(ResultSet rs) throws SQLException{
            List<String> list = new LinkedList<String>();
            ResultSetMetaData resultSetMetaData = rs.getMetaData();
            for(int i=0;i<resultSetMetaData.getColumnCount();i++) {
                list.add(resultSetMetaData.getColumnLabel(i+1));
            }
            return list;
        }
        
        /**
         * 返回某条记录的字段
         * @param sql
         * @param args
         * @return
         */
        public <E> E getForValue(String sql,Object... args) {
            try(Connection con = JDBCTutorials.getConnection();
                    PreparedStatement pre = con.prepareStatement(sql)){
                for(int i=0;i<args.length;i++) {
                    pre.setObject(i+1, args[i]);
                }
                try(ResultSet rs = pre.executeQuery()){
                    if(rs.next()) {
                        return (E)rs.getObject(1);
                    }
                }catch (SQLException e) {
                    e.printStackTrace();
                }
            }catch (SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    DaoTest类

    class DaoTest {
        Dao dao = new Dao();
        
        @Test
        void testUpdata() {
            String sql = "SELECT cust_id custID,cust_name custName FROM customers WHERE cust_id = ?;";
            Customers customers = dao.get(Customers.class, sql,10003);
            System.out.println("---");
            System.out.println(customers);
        }
    
        @Test
        void testGet() {
            String sql = "SELECT cust_id custID,cust_name custName FROM customers WHERE cust_id = ? OR cust_id = ?;";
            List<Customers> customers = dao.getForList(Customers.class, sql,10003,10004);
            for(Customers l:customers) {
                System.out.println(l);
            }
        }
        
        @Test
        void testGetValue() {
            String sql = "Select MAX(cust_id) FROM customers";
            int maxCustID = dao.getForValue(sql);
            System.out.println(maxCustID);
        }
    }

    日期:2018-10-18 基础教程写好,后续拓展待补:

    2018-10-19 14:20:15 更新拓展.

    2018-10-20 21:55:52 第二大部分即将完成,编写连接池概念与原理中

    2018-10-22 修正

    2018-10-23 13:57:55 完结撒花

     

  • 相关阅读:
    最大子列和问题(20 分)浙大版《数据结构(第2版)》题目集
    习题2.1 简单计算器(20 分)浙大版《数据结构(第2版)》题目集
    习题2.2 数组循环左移(20 分)浙大版《数据结构(第2版)》题目集
    习题2.3 数列求和-加强版(20 分)浙大版《数据结构(第2版)》题目集
    java之不同数据流应用举例
    java之java.io.File的相关方法
    java之注解
    java之枚举和注解
    java之泛型
    java之操作集合的工具类--Collections
  • 原文地址:https://www.cnblogs.com/--zz/p/9811818.html
Copyright © 2011-2022 走看看