JDBC

連接數(shù)據(jù)庫的方式:
第一種方式:ODBC:開放數(shù)據(jù)庫連接是微軟公司開放服務結構中有關數(shù)據(jù)庫的一個組成部分,是數(shù)據(jù)庫訪問接口標準。ODBC是基于C語言實現(xiàn)的。提供了語言和數(shù)據(jù)庫進行交互的一致性的接口,便于語言和數(shù)據(jù)庫通信以及語言對數(shù)據(jù)庫的各種操作。
第二種方式:JDBC(本章重點)

在Java中,數(shù)據(jù)庫存取技術可分為如下幾類:
第一種:JDBC直接訪問數(shù)據(jù)庫
第二種 :JDO技術(Java Data Object)
第三種:第三方O/R工具,如Hibernate, Mybatis 等

JDBC是java訪問數(shù)據(jù)庫的基石,JDO, Hibernate等只是更好的封裝了JDBC。

什么是JDBC?
JDBC: Java Data Base Connectivity(java數(shù)據(jù)庫連接)
它是sun公司提供的一套java應用程序訪問數(shù)據(jù)庫的技術或規(guī)范。是一種用于執(zhí)行SQL語句的Java API,它統(tǒng)一和規(guī)范了應用程序與數(shù)據(jù)庫的連接、執(zhí)行SQL語句,并到得到返回結果等各類操作,可以為多種關系數(shù)據(jù)庫提供統(tǒng)一訪問,它由一組用Java語言編寫的類和接口組成。

JDBC的好處
1、減少了開發(fā)程序員的壓力,不用去記多套API
2、提高了維護性

如何使用?
第一步:導入jar包:
1.使用JDBC操作數(shù)據(jù)庫,需要導入JDBC的驅動包:mysql-connector-java-5.1.36-bin.jar。
2.在項目下新建libs文件夾,將jar包復制到libs文件夾下面
注意:如果是Dynamic Web Project(動態(tài)的web項目)話,則是把驅動jar放到WebContent(有的開發(fā)工具叫WebRoot)目錄中的WEB-INF目錄中的lib目錄下即可
3.右鍵–>Build Path–>Add to Build Path,這時,我們可以在項目的引用包中看到我們引用的jar包.

第二步:Java應用程序訪問數(shù)據(jù)庫的過程:
?、傺b載數(shù)據(jù)庫驅動程序;
  MySQL的驅動下載地址:http://dev.mysql.com/downloads/
  加載驅動:把驅動類加載到內(nèi)存
  注冊驅動:把驅動類的對象交給DriverManager管理,用于后面創(chuàng)建連接等使用。
  第一種方式:DriverManager.registerDriver(new Driver());//不建議使用
  第二種方式: Class.forName(“com.mysql.jdbc.Driver”);//通過反射,加載與注冊驅動類,解耦合(不直接依賴)
?、谕ㄟ^JDBC建立數(shù)據(jù)庫連接;
?、墼L問數(shù)據(jù)庫,執(zhí)行SQL語句;
?、軘嚅_數(shù)據(jù)庫連接。
 
java.sql包
javax.sql包
此類用于演示JDBC使用的簡單步驟

/**
 * 此類用于演示JDBC使用的簡單步驟
 * 前提:
 * ①需要將mysql-connector-java-5.1.37-bin.jar復制到項目的libs目錄
 * ②右擊mysql-connector-java-5.1.37-bin,Build Path——Add To buildPath
 *
 */
public class TestConnection {
    public static void main(String[] args) throws SQLException {
        // 1.加載驅動(準備工作)
        DriverManager.registerDriver(new Driver());
        // 2.獲取連接
        /*
         * 參數(shù)1:url
         * 格式:jdbc:mysql://主機名:端口號/庫名
         * 參數(shù)2:用戶名
         * 參數(shù)3:密碼
         */
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/customersDB", "root", "root");
        // 3.執(zhí)行增刪改查★
        //①獲取執(zhí)行sql語句的命令對象
        Statement statement = connection.createStatement();
        //②執(zhí)行sql語句
        int update = statement.executeUpdate("delete from customers where id=2");
        //③處理結果
        System.out.println(update>0?"success":"failure");
        // 4.關閉連接
        statement.close();
        connection.close();
    }
}


PreparedStatement的使用

/**
 * 一、向customers表中插入數(shù)據(jù),效果如下:
請輸入編號:55
請輸入姓名:上官紅
請輸入郵箱:shangguan@126.com
請輸入生日(要求按xxxx-xx-xx格式):1988-11-11
插入成功!
 */
public class TestPreparedStatementByUtils {
    //增刪改
    @Test
    public void test1() throws Exception {
        Scanner input = new Scanner(System.in);
        System.out.println("請輸入編號:");
        int id = input.nextInt();
        System.out.println("請輸入姓名:");
        String name = input.next();
        System.out.println("請輸入郵箱:");
        String email = input.next();
        System.out.println("請輸入生日:");
        String birth = input.next();
        //-----------------------------連接數(shù)據(jù)庫的步驟-----------------
        //1.獲取連接
        Connection connection = JDBCUtils.getConnection();
        //2、執(zhí)行插入
        PreparedStatement statement = connection.prepareStatement("insert into customers values(?,?,?,?,null)");
        statement.setInt(1, id);
        statement.setString(2, name);
        statement.setString(3, email);
        statement.setString(4, birth);
        int update = statement.executeUpdate();
        System.out.println(update>0?"插入成功":"插入失敗");
        //3.關閉
        JDBCUtils.close(null, statement, connection);
    }
    //查詢
    @Test
    public void test2() throws Exception {
//        請輸入編號:1
//        ---------------------------------------------------------------------------------
//        編號    姓名    郵箱    生日
//        1    汪峰    wf@126.com    2010-2-2
        Scanner input = new Scanner(System.in);
        System.out.println("請輸入編號:");
        int id = input.nextInt();
        //-----------------------------連接數(shù)據(jù)庫的步驟-----------------
        //1.獲取連接
        Connection connection = JDBCUtils.getConnection();
        //2、執(zhí)行查詢
        PreparedStatement statement = connection.prepareStatement(
                "select id,name,email,birth from customers where id = ?");
        statement.setInt(1, id);
        ResultSet set = statement.executeQuery();
        if(set.next()) {
            String name = set.getString(2);
            String email = set.getString(3);
            String birth = set.getString(4);
            System.out.println(id+"\t"+name+"\t"+email+"\t"+birth);
        }
        //3.關閉
        JDBCUtils.close(set, statement, connection);
    }
}

此類用于演示批處理和PreparedStatement與Statement之間的效率問題

/**
 * 此類用于演示批處理
 * 情況1:多條sql語句的批量執(zhí)行【較少使用】
 * Statement+批處理:提高了執(zhí)行的效率,并沒有減少編譯的次數(shù)
 * 情況2:一條sql語句的批量傳參【較多使用】
 * PreparedStatement+批處理:減少了執(zhí)行的次數(shù),也減少了編譯的次數(shù),大大提高效率
 * 相關API:
 *     addBatch()
 *     executeBatch()
 *     clearBatch()
 * 注意:
 *     ①需要在url添加reWriteBatchedStatement = true
 *   驅動類使用的版本:5.1.37、5.1.36但不能使用5.1.7(不支持批處理)
 *  ②插入時,使用values,而不是value!
 *案例:添加50000條管理員記錄
 */
public class TestBatch {
    //沒有使用批處理
    @Test
    public void testNoBatch() throws Exception {   
        //1.獲取連接
        Connection connection = JDBCUtils.getConnection();       
        //2.執(zhí)行插入         
        PreparedStatement statement = connection.prepareStatement("insert into admin values(?,?,?)");       
        for(int i=1;i<=50000;i++) {
            statement.setInt(1, i);
            statement.setString(2, "john"+i);
            statement.setString(3, "0000");               
            statement.executeUpdate();                               
        }                       
        //3.關閉
        JDBCUtils.close(null, statement, connection);                           
    }
    //使用批處理
    @Test
    public void testUseBatch() throws Exception {           
        //1.獲取連接
        Connection connection = JDBCUtils.getConnection();           
        //2.執(zhí)行插入           
        PreparedStatement statement = connection.prepareStatement("insert into admin values(?,?,?)");           
        for(int i=1;i<=50000;i++) {
            statement.setInt(1, i);
            statement.setString(2, "john"+i);
            statement.setString(3, "0000");              
            //添加到批處理包(放到框中)
            statement.addBatch();
            if(i%1000==0) {
                statement.executeBatch();//執(zhí)行批處理包的sql(將框中的蘋果們運到了樓上)
                statement.clearBatch();//清空批處理包的sql(卸貨)
            }
        }
        //3.關閉
        JDBCUtils.close(null, statement, connection);
    }
}

Blob類型數(shù)據(jù)的讀寫

/**
 * 此類用于演示Blob類型數(shù)據(jù)的讀寫
 * 注意:只能使用PreparedStatement實現(xiàn)Blob類型的讀寫,不能使用Statement
 * 相關API:
 *     setBlob(占位符索引,InputStream)
 *     InputStream is =getBinaryStream(列索引)
 */
public class TestBlob {
    //測試Blob類型數(shù)據(jù)的寫入:修改小蒼的照片為指定照片
    @Test
    public void test1() throws Exception {
        //1.獲取連接
        Connection connection = JDBCUtils.getConnection();   
        //2.執(zhí)行修改
        PreparedStatement statement = connection.prepareStatement("update customers set photo = ? where name = ?");       
        statement.setBlob(1, new FileInputStream("E:\\beauty\\cang.jpg"));//★       
        statement.setString(2, "小蒼");
        int update = statement.executeUpdate();
        System.out.println(update>0?"插入成功":"插入失敗");       
        //3.關閉
        JDBCUtils.close(null, statement, connection);
    }
    //測試Blob類型數(shù)據(jù)的讀?。簩⑿∩n的圖片讀取到項目的根目錄下
    @Test
    public void test2() throws Exception {
        //1.獲取連接
        Connection connection = JDBCUtils.getConnection();       
        //2.執(zhí)行查詢
        PreparedStatement statement = connection.prepareStatement("select photo from customers where name = ?");
        statement.setString(1, "小蒼");
        ResultSet set = statement.executeQuery();       
        if(set.next()) {
//            Blob blob = set.getBlob(1);
//            InputStream binaryStream = blob.getBinaryStream();           
            InputStream inputStream = set.getBinaryStream(1);
            FileOutputStream fos = new FileOutputStream("src\\beauty.jpg");           
            //邊讀邊寫:復制圖片
            byte[] b = new byte[1024];
            int len;
            while((len=inputStream.read(b))!=-1) {
                fos.write(b, 0, len);               
            }
            fos.close();
            inputStream.close();
        }       
        //3.關閉連接資源       
        JDBCUtils.close(set, statement, connection);
    }
}


##JDBC常用的API

DriverManager驅動管理類
    registDriver 加載驅動【不建議使用】
    getConnection獲取連接【后期往往通過數(shù)據(jù)庫連接池獲取】

Connection連接接口
    createStatement()獲取命令對象
    prepareStatement(sql)獲取預編譯命令對象
    close

Statement命令對象接口
    executeUpdate(sql)執(zhí)行增刪改語句,返回受影響的行數(shù)
    executeQuery(sql)執(zhí)行查詢語句,返回ResultSet對象
    execute(sql)執(zhí)行任何sql語句,返回是否是結果集
    close

PreparedStatement預編譯命令對象
    executeUpdate()執(zhí)行增刪改語句,返回受影響的行數(shù)
    executeQuery()執(zhí)行查詢語句,返回ResultSet對象
    execute()執(zhí)行任何sql語句,返回是否是結果集
    setXX(占位符的索引,占位符的值):設置對應占位符的值為XX類型的變量(索引從1開始)
    setObject(占位符索引,占位符的值):設置對應占位符的值為Object類型的變量
    close

ResultSet結果集接口
    next()下移一行,指向當前行,返回指向的新行是否有數(shù)據(jù)
    getXX(columnIndex|columnName)根據(jù)列索引或列名獲取XX類型的值
    getObject(columnIndex|columnName)根據(jù)列索引或列名獲取Object類型的值   
    previous()上移一行,指向當前行,返回指向的新行是否有數(shù)據(jù)
    close


##德魯伊連接池的使用

###連接池的好處
1、提高效率
2、提高重用性
3、采用一套統(tǒng)一的管理機制,減少數(shù)據(jù)庫崩潰問題
###數(shù)據(jù)庫連接池的使用
javax.sql包下的DataSource是一個數(shù)據(jù)庫連接池接口。一些開源組織對它進行了實現(xiàn)。
多種開源的數(shù)據(jù)庫連接池:C3P0,DBCP,Druid,BoneCP,Proxool

###德魯伊使用方式一:

    //創(chuàng)建一個數(shù)據(jù)庫連接池
    DruidDataSource dds = new DruidDataSource();
    //設置連接參數(shù)   
    dds.setUrl("jdbc:mysql://localhost:3306/customersDB");
    dds.setUsername("root");
    dds.setPassword("root");
    dds.setDriverClassName("com.mysql.jdbc.Driver");   
    //設置池子中的初始化連接數(shù)
    dds.setInitialSize(5);
    //設置池子中的最大連接數(shù)
    dds.setMaxActive(10);
    //設置池子中的最小連接數(shù)
    dds.setMinIdle(5);       
    //獲取連接   
    Connection connection = dds.getConnection();   
    System.out.println("connected!");


###德魯伊使用方式二:

    Properties properties = new Properties();    properties.load(this.getClass().getClassLoader().getResourceAsStream("druid.properties"));   
    //1、獲取連接池
    DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
    //2、獲取連接
    Connection connection = dataSource.getConnection();
    System.out.println(connection);   
    //3.關閉連接
    connection.close();

 

druid.properties

#key=value
driverClassName=com.mysql.jdbc.Driver
#url=jdbc:mysql://localhost:3306/bookstore?rewriteBatchedStatements=true
url=jdbc:mysql://localhost:3306/customersDB
username=root
password=root
initialSize=10
minIdle=5
maxActive=20
maxWait=5000

  

事務

    @Test
    public void testTransaction() {       
        //1.獲取連接
        Connection connection = null;
        //事務使用步驟二:編寫事務的語句
                //2.執(zhí)行增刪改查
        PreparedStatement statement = null;
        try {
            connection = JDBCUtils.getConnection();           
            //事務使用步驟一:開啟事務
            connection.setAutoCommit(false);//取消了事務的自動提交+開啟事務       
            statement = connection.prepareStatement("update account set balance = ? where username = ?");               
            statement.setDouble(1, 995);
            statement.setString(2, "馮紹峰");
            statement.executeUpdate();           
            int i=1/0;           
            //操作2:趙麗穎的錢多5塊               
            statement.setDouble(1, 1005);
            statement.setString(2, "趙麗穎");
            statement.executeUpdate();                           
            //事務使用步驟三:結束事務
            connection.commit();//如果執(zhí)行到該處,說明上面操作沒有異常,則可以正常提交事務
        } catch (SQLException e) {
            try {
                connection.rollback();//如果執(zhí)行到該處,說明try塊操作有異常,則需要回滾!
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }
        finally {           
            //3.關閉連接
            try {
                JDBCUtils.close(null, statement, connection);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


批處理

//使用批處理
@Test
public void testUseBatch() throws Exception {   
    //1.獲取連接
    Connection connection = JDBCUtils.getConnection();
    //2.執(zhí)行插入
    PreparedStatement statement = connection.prepareStatement("insert into admin values(?,?,?)");   
    for(int i=1;i<=50000;i++) {
        statement.setInt(1, i);
        statement.setString(2, "john"+i);
        statement.setString(3, "0000");           
        //添加到批處理包(放到框中)
        statement.addBatch();
        if(i%1000==0) {
            statement.executeBatch();//執(zhí)行批處理包的sql(將框中的蘋果們運到了樓上)
            statement.clearBatch();//清空批處理包的sql(卸貨)
        }
    }
    //3.關閉
    JDBCUtils.close(null, statement, connection);
}


自己動手封裝一個BasicDao

/**
 * 自己動手封裝一個BasicDao
 *  功能:
 *  1、通用的增刪改
 *      針對于任何表的增刪改語句
 *  2、通用的查詢單條(返回的是一行信息)
 *      針對于任何表的任何查詢單條的記錄
 *      返回類型:T 對象
 *      orm思想:一個表映射成一個類,一條記錄映射成一個對象,一個字段映射成一個屬性
 *      參數(shù):Class clazz,String sql,Object...objects
 *  3、通用的查詢多條(返回的是多行信息)
 *      針對于 任何表的任何查詢多條的記錄
 *      返回類型:List<T>
 *      參數(shù):Class clazz,String sql,Object...objects
 */
public class BasicDaoBySelf {
    /**
     * 功能:針對于任何表的查詢多條
     * @param clazz
     * @param sql
     * @param objects
     * @return List<T>
     */
    public <T> List<T> queryMulti(Class<T> clazz,String sql,Object...objects){
        Connection connection  = null;
        PreparedStatement statement = null;
        ResultSet set = null;
        try {
            connection  = JDBCUtils.getConnection();
            statement = connection.prepareStatement(sql);
            for (int i = 0; i < objects.length; i++) {
                statement.setObject(i+1, objects[i]);
            }
            set = statement.executeQuery();
            ResultSetMetaData metaData = set.getMetaData();
            List<T> list = new ArrayList<>();//集合
            int columnCount = metaData.getColumnCount();
            while(set.next()) {
                T t = clazz.newInstance();
                for(int i=1;i<=columnCount;i++) {
                    //獲取屬性名(列名)
                    String fieldName = metaData.getColumnLabel(i);
                    //獲取屬性值(列的值)
                    Object value = set.getObject(i);
                    Field field = clazz.getDeclaredField(fieldName);
                    field.setAccessible(true);
                    field.set(t, value);
                }
                list.add(t);
            }
            return list;
        }catch(Exception e) {
            throw new RuntimeException(e);
        }finally {
            JDBCUtils.close(set, statement, connection);
        }
    }
    /**
     * 功能:執(zhí)行任何表的查詢單條記錄的sql語句
     * @param clazz 表針對的類的Class對象
     * @param sql 待執(zhí)行的sql
     * @param objects 占位符
     * @return T 類型的對象(表中的一條記錄以對象的形式返回)
     * @throws Exception
     */
    public<T> T querySingle(Class<T> clazz,String sql,Object...objects)  {
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet set = null;
        try {
            //1.獲取連接
             connection = JDBCUtils.getConnection();
            //2.執(zhí)行查詢
            statement = connection.prepareStatement(sql);
            for (int i = 0; i < objects.length; i++) {
                statement.setObject(i+1, objects[i]);
            }
            set = statement.executeQuery();
            /*
             * 一、元數(shù)據(jù)結果集的使用
             * ResultSet:保存結果集的數(shù)據(jù)
             * 元數(shù)據(jù)結果集:解剖ResultSet的結構
             * 二、反射的使用
             * 封裝對象:
             * 正常的方式:
             * ①調用無參構造創(chuàng)建對象
             * 類名 對象名  = new 類名();
             * ②為對象的各個屬性賦值
             * 對象名.屬性名=值;
             * 反射的方式:
             * 創(chuàng)建對象:
             *     T t= clazz.newInstance();
             * 為屬性賦值:
             *     Field field = t.getDecalaredField(屬性名);
             *  field.setAccessible(true);
             *  field.set(t,value);
             * 三、泛型的使用
             */
            //獲取元數(shù)據(jù)結果集
            ResultSetMetaData metaData = set.getMetaData();
            //結果集的列數(shù)
            int columnCount = metaData.getColumnCount();
            if(set.next()) {
                T t= clazz.newInstance();
                for(int i=1;i<=columnCount;i++) {//遍歷列數(shù)
                    String columnLabel = metaData.getColumnLabel(i);//根據(jù)列索引獲取列名或別名(屬性名)
                    Object value = set.getObject(i);//拿到該列的值(各個屬性的值)
                    Field field = clazz.getDeclaredField(columnLabel);
                    field.setAccessible(true);
                    field.set(t,value);
                }
                return t;
            }
            return null;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        finally {
            JDBCUtils.close(set, statement, connection);
        }
    }
    /**
     * 功能:通用的增刪改語句
     * @param sql 待執(zhí)行的sql,里面可能有占位符
     * @param objects 占位符的值
     * @return 受影響的行數(shù)
     * @throws SQLException
     * @throws Exception
     */
    public int update(String sql,Object...objects) {
        //1.獲取連接
        Connection connection= null;
        PreparedStatement statement = null;
        try {
            connection = JDBCUtils.getConnection();
            //2.執(zhí)行sql
            statement = connection.prepareStatement(sql);
            for(int i=0;i<objects.length;i++) {
                statement.setObject(i+1, objects[i]);
            }
            int update = statement.executeUpdate();
            return update;
        }  catch (Exception e) {
            throw new RuntimeException(e);//將編譯異常轉換成運行異常
        }
        finally {
            //3.關閉
            JDBCUtils.close(null, statement, connection);
        }
    }
}


00000000000000000000000000000000000000000000000000000000000000000000
使用JDBCUTils工具類自己寫一個增刪改,查詢單條,多條記錄,查詢單個值的通用方法

/**
 * 此類用于演示DBUTils的使用
 * QueryRunner
 *         update
 *         query
 * ResultSetHandler
 *         BeanHandler
 *         BeanListHandler
 *         ScalarHandler
 */
public class BasicDaoByUtils<T> {
    QueryRunner qr = new QueryRunner();
    /**
     * 通用的增刪改
     * @param sql
     * @param objects
     * @return
     */
    public int update(String sql,Object...objects) {
        Connection connection  = null;
        try {
            connection  = JDBCUtils.getConnection();
            return  qr.update(connection, sql, objects);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        finally {
            JDBCUtils.close(null, null, connection);
        }
    }
    /**
     * 功能:查詢單條
     * @param clazz
     * @param sql
     * @param objects
     * @return
     */
    public T querySingle(Class<T> clazz,String sql,Object...objects) {
        Connection connection  = null;
        try {
            connection  = JDBCUtils.getConnection();           
            return qr.query(connection, sql, new BeanHandler<T>(clazz),objects);       
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        finally {
            JDBCUtils.close(null, null, connection);
        }
    }   
    /**
     * 功能:查詢多條
     * @param clazz
     * @param sql
     * @param objects
     * @return
     */
    public List<T> queryMulti(Class<T> clazz,String sql,Object...objects) {
        Connection connection  = null;
        try {
            connection  = JDBCUtils.getConnection();           
            return qr.query(connection, sql, new BeanListHandler<T>(clazz),objects);           
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        finally {
            JDBCUtils.close(null, null, connection);
        }
    }
    /**
     * 功能:查詢單個值
     * @param sql
     * @param objects
     * @return
     */   
    public Object scalar(String sql,Object...objects) {
        Connection connection  = null;
        try {
            connection  = JDBCUtils.getConnection();           
            return qr.query(connection, sql, new ScalarHandler(),objects);           
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        finally {
            JDBCUtils.close(null, null, connection);
        }
    }
}


JDBCUtils工具類

/**
 * jdbc工具類
 */
public class JDBCUtils {
    static DataSource dataSource;
    static {
        try {
            Properties properties = new Properties();
            properties.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
             dataSource = DruidDataSourceFactory.createDataSource(properties);
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
    //使用druid獲取連接
    public static Connection getConnection() throws Exception  {
        return dataSource.getConnection();
    }
    //使用c3p0獲取連接
    public static Connection getConnection2() throws SQLException {
        ComboPooledDataSource cpds = new ComboPooledDataSource("hello");
        return cpds.getConnection();
    }
    //釋放連接資源
    public static void close(ResultSet set,Statement statement,Connection connection){
        try {
            if(set!=null)
                set.close();
            if(statement!=null)
                statement.close();
            if(connection!=null)
                connection.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }           
    }
}


測試工具類的使用情況

/**
 * 此類用于測試工具類的使用
 */
public class TestDBUtils {
    @Test
    public void test1() {
        BasicDaoByUtils<Admin> bd = new BasicDaoByUtils<>();
        int update = bd.update("update admin set username = ? where id =?", "小花",2);
        System.out.println(update>0?"success":"failure");
    }       
    @Test
    public void test2() {
        BasicDaoByUtils<Admin> bd = new BasicDaoByUtils<>();
//        Admin querySingle = bd.querySingle(Admin.class, "select * from Admin where id=?", 2);//Admin自己新建的實體類
//        System.out.println(querySingle);
        List<Admin> list = bd.queryMulti(Admin.class, "select * from Admin where id<?", 10);
        for (Admin admin : list) {
            System.out.println(admin);
        }
        Object scalar = bd.scalar("select count(*) from admin");
        System.out.println(scalar);
    }
}


00000000000000000000000000000000000000000000000000000000000000000000
JDBC相關的API
一、Connection接口:

1.createStatement():創(chuàng)建數(shù)據(jù)庫連接
2.prepareStatement(String sql):創(chuàng)建預處理語句
3.prepareCall(String sql):創(chuàng)建可調用語句
4.getAutoCommit():獲取自動提交的模式
5.setAutoCommit():設置自動提交的模式
6.commit():提交所執(zhí)行的SQL語句
7.rollback():回滾所執(zhí)行的SQL語句
8.getMetaData():獲取一個DatabaseMetaData對象,該對象包含了有關數(shù)據(jù)庫的基本信息
9.close():關閉數(shù)據(jù)庫連接
10.isClose():判斷數(shù)據(jù)庫連接是否超時或被顯示關閉


二、Statement接口:

1.execute(String sql):執(zhí)行SQL語句,如果返回值是結果集則為true,否則為false
2.executeQuery(String sql):執(zhí)行SQL語句,返回值為ResultSet
3.executeUpdate(String sql):執(zhí)行SQL語句,返回值為所影響的行數(shù)
4.addBatch(String sql):向當前Statement對象的命令列表中添加新的批處理SQL語句
5.clearBatch():清空當前Statement對象的命令列表
6.executeBatch():執(zhí)行當前Statement對象的批處理語句,返回值為每個語句所影響的函數(shù)數(shù)組
7.getConnection():返回創(chuàng)建了該Statement對象的Connection對象
8.getQueryTimeout():獲取等待處理結果的時間
9.setQueryTimeout():設置等待處理結果的時間


三、ResultSet接口:

1.first()/beforeFirst():將游標移動到ResultSet中第一條記錄(的前面)
2.last()/afterLast():將游標移動到ResultSet中最后一條記錄(的后面)
3.absolute(int column):將游標移動到相對于第一行的指定行,負數(shù)則為相對于最后一條記錄
4.relative(int rows):將游標移動到相對于當前行的第幾行,正為向下,負為向上
5.next():將游標下移一行
6.previous():將游標上移一行
7.insertRow():向當前ResultSet和數(shù)據(jù)庫中被插入行處插入一條記錄
8.deleteRow():將當前ResultSet中的當前行和數(shù)據(jù)庫中對應的記錄刪除
9.updateRow():用當前ResultSet中已更新的記錄更新數(shù)據(jù)庫中對應的記錄
10.cancelUpdate():取消當前對ResultSet和數(shù)據(jù)庫中所做的操作
11.findColumn(String columnName):返回當前ResultSet中與指定列名對應的索引
12.getRow():返回ResultSet中的當前行號
13.refreshRow():更新當前ResultSet中的所有記錄
14.getMetaData():返回描述ResultSet的ResultSetMetaData對象
15.isAfterLast(): 是否到了結尾
16.isBeforeFirst(): 是否到了開頭
17.isFirst():是否第一條記錄   
18.isLast(): 是否最后一條記錄
19.wasNull():檢查列值是否為NULL值,如果列的類型為基本類型,且數(shù)據(jù)庫中的值為0,那么這項檢查就很重要。由于數(shù)據(jù)庫NULL也返回0,所以0值和數(shù)據(jù)庫的NULL不能區(qū)分。如果列的類型為對象,可以簡單地將返回值與null比較  
20.close():關閉當前ResultSet


DBUtils用的最多的莫過于其結果集的處理,畢竟僅僅得到一個ResultSet屁用沒有。而結果集的處理正是依賴于ResultSetHandler 接口及其實現(xiàn)類。
ResultSetHandler的各個實現(xiàn)類:

ArrayHandler:把結果集中的第一行數(shù)據(jù)轉成對象數(shù)組。
ArrayListHandler:把結果集中的每一行數(shù)據(jù)都轉成一個對象數(shù)組,再存放到List中。
BeanHandler:將結果集中的第一行數(shù)據(jù)封裝到一個對應的JavaBean實例中。
BeanListHandler:將結果集中的每一行數(shù)據(jù)都封裝到一個對應的JavaBean實例中,存放到List里。//重點
MapHandler:將結果集中的第一行數(shù)據(jù)封裝到一個Map里,key是列名,value就是對應的值。//重點
MapListHandler:將結果集中的每一行數(shù)據(jù)都封裝到一個Map里,然后再存放到List
ColumnListHandler:將結果集中某一列的數(shù)據(jù)存放到List中。
KeyedHandler(name):將結果集中的每一行數(shù)據(jù)都封裝到一個Map里(List),再把這些map再存到一個map里,其key為指定的列。
ScalarHandler:將結果集第一行的某一列放到某個對象中。

四、ResultSetMetaData接口:

1.getColumnCount():返回ResultSet中列的數(shù)目
2.getColumnName():返回列在數(shù)據(jù)庫中的名稱
3.getColumnType():返回列的SQL類型
4.isReadOnly():表示該數(shù)據(jù)項是否為只讀值
5.isNullable():表示該列是否可以存儲NULL