Unit02: JDBC核心API

    Unit02: JDBC核心API    

db.propertiesjava

注意:若是使用鏈接池,能夠在這個文件中增長對鏈接池的相關設置:sql

鏈接池參數,經常使用參數有:

  • 初始鏈接數
  • 最大鏈接數
  • 最小鏈接數
  • 每次增長的鏈接數
  • 超時時間
  • 最大空閒鏈接
  • 最小空閒鏈接
# db connection parameters
# key=value
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@192.168.201.227:1521:orcl
user=openlab
pwd=open123
# datasource parameters
initSize=1
maxSize=1

DBUtil.javaapache

說明:DBUtil是DBTool的升級版,採用了鏈接池來管理鏈接。數組

package util;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import org.apache.commons.dbcp.BasicDataSource;

/**
 *    1.DBUtil是DBTool的升級版
 *    2.採用了鏈接池來管理鏈接
 */
public class DBUtil {
    
    //DBCP鏈接池提供的實現類
    private static BasicDataSource ds;
    
    static {
        Properties p = new Properties();
        try {
            //1.讀取參數
            p.load(DBUtil.class.getClassLoader()
                .getResourceAsStream("db.properties"));
            String driver = p.getProperty("driver");
            String url = p.getProperty("url");
            String user = p.getProperty("user");
            String pwd = p.getProperty("pwd");
            String initSize = p.getProperty("initSize");
            String maxSize = p.getProperty("maxSize");
            //2.建立鏈接池(1次)
            ds = new BasicDataSource();
            //3.向鏈接池設置參數
            ds.setDriverClassName(driver);
            ds.setUrl(url);
            ds.setUsername(user);
            ds.setPassword(pwd);
            ds.setInitialSize(new Integer(initSize));
            ds.setMaxActive(new Integer(maxSize));
        } catch (IOException e) {
            //異常的處理原則:
            //1.記錄日誌(Log4j)
            e.printStackTrace();
            //2.能解決就解決(看開發規範)
            //3.解決不了向上拋給調用者
            //具體拋出哪一種類型的異常看開發規範
            throw new RuntimeException(
                "加載配置文件失敗", e);
        }
    }
    
    public static Connection getConnection() 
        throws SQLException {
        return ds.getConnection();
    }
    
    /**
     * 1.目前咱們使用鏈接都是鏈接池建立的
     * 2.鏈接池重寫了鏈接對象內部的close()
     * 3.目前close()內部的邏輯是歸還:
     *      - 清除鏈接對象內部包含的全部數據
     *      - 將鏈接對象狀態設置爲空閒態
     */
    public static void close(Connection conn) {
        if(conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
                throw new RuntimeException(
                    "關閉鏈接失敗", e);
            }
        }
    }

}

Test.javaoracle

說明:這個類用於測試DBUtil測試

package jdbc;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.junit.Test;

import util.DBUtil;

public class TestDay02 {
    
    /**
     * 1.測試DBUtil
     * 2.執行DQL
     *     查詢部門ID爲1的員工
     */
    @Test
    public void test1() {
        //假設頁面傳入的查詢條件是
        int deptno = 1;
        
        Connection conn = null;
        try {
            conn = DBUtil.getConnection();
            System.out.println(conn);
            Statement smt = conn.createStatement();
            String sql = 
                "select * from emps_lhh "
                + "where deptno="+deptno;
            ResultSet rs = smt.executeQuery(sql);
            while(rs.next()) {
                System.out.println(rs.getInt("empno"));
                System.out.println(rs.getString("ename"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
            //測試代碼能夠適當簡化異常處理
        } finally {
            DBUtil.close(conn);
        }
    }

    /**
     * 演示如何使用PS執行DML
     */
    @Test
    public void test2() {
        //假設頁面傳入的數據是
        String ename = "曹操";
        String job = "丞相";
        int mgr = 0;
        Date hiredate = 
            Date.valueOf("2017-01-22");
        Double sal = 8000.0;
        Double comm = 9000.0;
        int deptno = 3;
        
        Connection conn = null;
        try {
            conn = DBUtil.getConnection();
            //寫sql時條件用?代替
            String sql = 
                "insert into emps_lhh values("
                + "emps_seq_lhh.nextval,"
                + "?,?,?,?,?,?,?)";
            //建立PS並傳入sql,PS會馬上發送此sql
            PreparedStatement ps = 
                conn.prepareStatement(sql);
            //先設置條件:給?賦值
            //ps.set類型(?的序號,?的值)
            ps.setString(1, ename);
            ps.setString(2, job);
            ps.setInt(3, mgr);
            ps.setDate(4, hiredate);
            ps.setDouble(5, sal);
            ps.setDouble(6, comm);
            ps.setInt(7, deptno);
            //發送參數,執行SQL(計劃)
            ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn);
        }
    }
    
    /**
     * 演示如何使用PS執行DQL
     */
    @Test
    public void test3() {
        //假設頁面傳入的查詢條件是
        int empno = 1;
        
        Connection conn = null;
        try {
            conn = DBUtil.getConnection();
            String sql = 
                "select * from emps_lhh "
                + "where empno=?";
            PreparedStatement ps = 
                conn.prepareStatement(sql);
            ps.setInt(1, empno);
            ResultSet rs = ps.executeQuery();
            if(rs.next()) {
                System.out.println(rs.getString("ename"));
                System.out.println(rs.getString("job"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn);
        }
        
    }
    
    /**
     * 使用PS執行查詢語句,能夠避免注入攻擊
     */
    @Test
    public void test4() {
        //假設頁面傳入的參數是
        String user = "zhangsan";
        String pwd = "a' or 'b'='b";
        
        Connection conn = null;
        try {
            conn = DBUtil.getConnection();
            String sql = 
                "select * from users_lhh "
                + "where username=? "
                + "and password=?";
            PreparedStatement ps = 
                conn.prepareStatement(sql);
            ps.setString(1, user);
            ps.setString(2, pwd);
            ResultSet rs = ps.executeQuery();
            if(rs.next()) {
                System.out.println("登陸成功");
            } else {
                System.out.println("帳號或密碼錯誤");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn);
        }
    }

}

 Test.javaurl

  1. 演示如何從ResultSetMetaData中讀取結果集相關的描述信息.
  2. 模擬轉帳業務.
  3. 批量添加員工(共108個,每批加50個)
  4. 添加部門及員工數據,添加員工時須要獲取到部門的ID
package jdbc;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

import org.junit.Test;

import util.DBUtil;

public class TestDay03 {

    /**
     * 演示如何從ResultSetMetaData
     * 中讀取結果集相關的描述信息.
     */
    @Test
    public void test1() {
        //假設頁面傳入的查詢條件是
        int empno = 1;
        
        Connection conn = null;
        try {
            conn = DBUtil.getConnection();
            String sql = 
                "select * from emps_lhh "
                + "where empno=?";
            PreparedStatement ps = 
                conn.prepareStatement(sql);
            ps.setInt(1, empno);
            ResultSet rs = ps.executeQuery();
            //獲取結果集元數據,它是一個對象,
            //內部封裝了對結果集的描述信息.
            ResultSetMetaData md = rs.getMetaData();
            //多少列
            System.out.println(md.getColumnCount());
            //第1列的列名
            System.out.println(md.getColumnName(1));
            //第1列的類型的編號(常量)
            System.out.println(md.getColumnType(1));
            //第1列的類型的名稱
            System.out.println(md.getColumnTypeName(1));
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn);
        }
    }

    /**
     * 模擬轉帳業務.
     * 
     * 假設此時用戶已經登陸了網銀,
     * 而且已經輸入了收款方帳號和
     * 轉帳的金額,點擊了轉帳.
     * 
     * 轉帳的步驟:
     * 1.驗證收款方帳號是否存在(查詢)
     * 2.驗證付款方餘額是否夠用(查詢)
     * 3.將付款方餘額-N元(修改)
     * 4.將收款方餘額+N元(修改)
     */
    @Test
    public void test2() {
        //假設用戶輸入的信息以下
        //付款方帳號
        String payId = "00001";
        //收款方帳號
        String recId = "00002";
        //轉帳的金額
        double mny = 1000.0;
        
        //轉帳是一個完整的業務流程,必須保證
        //它的完整性,即該流程應處於一個事務
        //以內,因此建立一個鏈接.
        Connection conn = null;
        try {
            conn = DBUtil.getConnection();
            //取消自動提交事務
            conn.setAutoCommit(false);
            //1.查詢收款方帳號並驗證
            String sql = 
                "select * from accounts_lhh "
                + "where id=?";
            PreparedStatement ps = 
                conn.prepareStatement(sql);
            ps.setString(1, recId);
            ResultSet rs = ps.executeQuery();
            if(!rs.next()) {
                throw new SQLException("收款方帳號不存在");
            }
            double recMny = rs.getDouble("money");
            //2.查詢付款方餘額並驗證
            String sql2 = 
                "select * from accounts_lhh "
                + "where id=?";
            PreparedStatement ps2 = 
                conn.prepareStatement(sql2);
            ps2.setString(1, payId);
            ResultSet rs2 = ps2.executeQuery();
            double payMny = 0.0;
            if(rs2.next()) {
                payMny = rs2.getDouble("money");
                if(payMny<mny) {
                    throw new SQLException("餘額不足");
                }
            }
            //3.修改付款方餘額
            String sql3 = 
                "update accounts_lhh set "
                + "money=? where id=?";
            PreparedStatement ps3 = 
                conn.prepareStatement(sql3);
            ps3.setDouble(1, payMny-mny);
            ps3.setString(2, payId);
            ps3.executeUpdate();
            
            Integer.valueOf("斷電了");
            
            //4.修改收款方餘額
            String sql4 =
                "update accounts_lhh set "
                + "money=? where id=?";
            PreparedStatement ps4 = 
                conn.prepareStatement(sql4);
            ps4.setDouble(1, recMny+mny);
            ps4.setString(2, recId);
            ps4.executeUpdate();
            
            //轉帳是一個完整的過程,只須要在
            //整個流程完成後,提交一次事務便可.
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        } finally {
            DBUtil.close(conn);
        }
    }
    
    /**
     *    批量添加員工(共108個,每批加50個)
     */
    @Test
    public void test3() {
        //這是一個完整的業務,只建立
        //1個鏈接,提交1次事務
        Connection conn = null;
        try {
            conn = DBUtil.getConnection();
            conn.setAutoCommit(false);
            String sql = 
                "insert into emps_lhh values("
                + "emps_seq_lhh.nextval,"
                + "?,?,?,?,?,?,?)";
            PreparedStatement ps = 
                conn.prepareStatement(sql);
            for(int i=1;i<=108;i++) {
                //每次循環都將數據暫存到ps上
                ps.setString(1, "好漢"+i);
                ps.setString(2, "打劫");
                ps.setInt(3, 0);
                ps.setDate(4, 
                    Date.valueOf("2017-01-23"));
                ps.setDouble(5, 6000.0);
                ps.setDouble(6, 4000.0);
                ps.setInt(7, 9);
                ps.addBatch();
                //每循環50次發送一次數據
                if(i%50==0) {
                    ps.executeBatch();
                    //清空ps中的數據,以便於
                    //暫存下一輪的數據
                    ps.clearBatch();
                }
            }
            //循環結束後,爲了不有零頭(8),
            //再單獨批量發送一次數據.因爲這
            //是最後一次發送,因此不用清空ps了
            ps.executeBatch();
            conn.commit();
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        } finally {
            DBUtil.close(conn);
        }
    }
    
    /**
     * 添加部門及員工數據
     * 添加員工時須要獲取到部門的ID
     */
    @Test
    public void test4() {
        //假設頁面傳入的數據是
        //部門
        String dname = "財務部";
        String loc = "杭州";
        //員工
        String ename = "郭嘉";
        String job = "謀士";
        int mgr = 0;
        Date hiredate = 
            Date.valueOf("2017-01-23");
        double sal = 6000.0;
        double comm = 2000.0;
        
        Connection conn = null;
        try {
            conn = DBUtil.getConnection();
            conn.setAutoCommit(false);
            //增長部門
            String sql = 
                "insert into depts values("
                + "depts_seq.nextval,?,?)";
            //參數2是一個數組,聲明須要ps記住
            //的字段的名稱,ps在執行SQL時會
            //記住這些字段的值.
            PreparedStatement ps = 
                conn.prepareStatement(
                    sql, new String[]{"deptno"});
            ps.setString(1, dname);
            ps.setString(2, loc);
            ps.executeUpdate();
            //獲取部門ID
            //返回的結果集中存儲了一條數據,
            //該行數據包括咱們讓ps記錄的全部字段.
            ResultSet rs = ps.getGeneratedKeys();
            System.out.println("rs"+rs);  
            //rsorg.apache.commons.dbcp.DelegatingResultSet@27efef64
            rs.next();
            //獲取ps記錄的字段時必須使用序號
            int deptno = rs.getInt(1);
            System.out.println("deptno"+deptno);  //deptno 4
            //增長員工
            String sql2 = 
                "insert into emps values("
                + "emps_seq.nextval,"
                + "?,?,?,?,?,?,?)";
            PreparedStatement ps2 = 
                conn.prepareStatement(sql2);
            ps2.setString(1, ename);
            ps2.setString(2, job);
            ps2.setInt(3, mgr);
            ps2.setDate(4, hiredate);
            ps2.setDouble(5, sal);
            ps2.setDouble(6, comm);
            ps2.setInt(7, deptno);
            ps2.executeUpdate();
            conn.commit();
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        } finally {
            DBUtil.close(conn);
        }
    }
    
}
相關文章
相關標籤/搜索