欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳細(xì)說明關(guān)于Java的數(shù)據(jù)庫連接(JDBC)

 更新時間:2021年09月06日 15:22:57   作者:誰砍了我的二叉樹  
這篇文章主要介紹了詳細(xì)說明關(guān)于Java的數(shù)據(jù)庫連接JDBC,JDBC是用Java語言向數(shù)據(jù)庫發(fā)送SQL語句,需要的朋友可以參考下面文章內(nèi)容

Java的數(shù)據(jù)庫連接(JDBC)

1、什么是JDBC

JDBC(JavaDataBase Connectivity) 就是Java數(shù)據(jù)庫連接,說白了就是用Java語言來操作數(shù)據(jù)庫。原來我們操作數(shù)據(jù)庫是在控制臺使用SQL語句來操作數(shù)據(jù)庫,JDBC是用Java語言向數(shù)據(jù)庫發(fā)送SQL語句。

2、JDBC的原理

早期SUN公司的天才們想編寫一套可以連接天下所有數(shù)據(jù)庫的API,但是當(dāng)他們剛剛開始時就發(fā)現(xiàn)這是不可完成的任務(wù),因為各個廠商的數(shù)據(jù)庫服務(wù)器差異太大了。后來SUN開始與數(shù)據(jù)庫廠商們討論,最終得出的結(jié)論是,由SUN提供一套訪問數(shù)據(jù)庫的規(guī)范(就是一組接口),并提供連接數(shù)據(jù)庫的協(xié)議標(biāo)準(zhǔn),然后各個數(shù)據(jù)庫廠商會遵循SUN的規(guī)范提供一套訪問自己公司的數(shù)據(jù)庫服務(wù)器的API出現(xiàn)。SUN提供的規(guī)范命名為JDBC,而各個廠商提供的,遵循了JDBC規(guī)范的,可以訪問自己數(shù)據(jù)庫的API被稱之為驅(qū)動!JDBC是接口,而JDBC驅(qū)動才是接口的實現(xiàn),沒有驅(qū)動無法完成數(shù)據(jù)庫連接!每個數(shù)據(jù)庫廠商都有自己的驅(qū)動,用來連接自己公司的數(shù)據(jù)庫。

3、演示JDBC的使用

通過下載MySQL的驅(qū)動jar文件,將其添加到項目中間,在注冊驅(qū)動時要指定為已經(jīng)下載好的驅(qū)動。

package jdbc;

import com.mysql.jdbc.Driver;  //這是我們驅(qū)動的路徑

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class Jdbc01 {
    public static void main(String[] args) throws SQLException {

        //1.注冊驅(qū)動
        Driver driver = new Driver();

        //2.得到連接
        //jdbc:mysql:// 規(guī)定好的協(xié)議  localhost 連接的地址  3306 監(jiān)聽的端口 test_table 連接的數(shù)據(jù)庫
        String url = "jdbc:mysql://localhost:3306/test_table";
        Properties properties = new Properties();
        //user和password 規(guī)定好的不能隨意改
        properties.setProperty("user", "root");//
        properties.setProperty("password", "161142");
        Connection connect = driver.connect(url, properties); //相當(dāng)于網(wǎng)絡(luò)連接

        //3.執(zhí)行sql語句
        //String sql = "insert into actor values(null,'syj','女','2000-05-26','110')";
        String sql = "update actor set name = 'xhj' where id =  2";
        Statement statement = connect.createStatement();
        int rows = statement.executeUpdate(sql);    //返回影響的行數(shù)
        if (rows > 0) System.out.println("添加成功");
        else System.out.println("添加失敗");

        //4.關(guān)閉連接資源
        statement.close();
        connect.close();
    }
}

4、數(shù)據(jù)庫連接方式

public class JdbcConn {
    @Test    /* 第一種 */
    public void testConn01() throws SQLException {
        //獲取Driver實現(xiàn)類對象
        Driver driver = new Driver();

        String url = "jdbc:mysql://localhost:3306/test_table";
        Properties properties = new Properties();
        properties.setProperty("user", "root");
        properties.setProperty("password", "161142");
        Connection connect = driver.connect(url, properties);
        System.out.println(connect);
    }
    
    @Test    /* 第二種 */
    public void testConn02() throws Exception{
        //使用反射加載Driver類,動態(tài)加載,可以通過配置文件靈活使用各種數(shù)據(jù)庫
        Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
        Driver driver = (Driver) aClass.getDeclaredConstructor().newInstance();

        String url = "jdbc:mysql://localhost:3306/test_table";
        Properties properties = new Properties();
        properties.setProperty("user", "root");
        properties.setProperty("password", "161142");
        Connection connect = driver.connect(url, properties);
        System.out.println(connect);
    }
    
    @Test    /* 第三種 */
    //DriverManager統(tǒng)一來管理Driver
    public void testConn03() throws Exception{
        //使用反射加載Driver類
        Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
        Driver driver = (Driver) aClass.getDeclaredConstructor().newInstance();

        //創(chuàng)建url和user和password
        String url = "jdbc:mysql://localhost:3306/test_table";
        String user = "root";
        String password = "161142";

        DriverManager.registerDriver(driver);   //注冊Driver驅(qū)動

        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);
    }
    
    @Test    /* 第四種 */
    public void testConn04() throws Exception{
        //使用反射加載Driver類
        Class.forName("com.mysql.jdbc.Driver");
        /* Class.forName("com.mysql.jdbc.Driver")在底層加載Driver時自動完成注冊驅(qū)動,簡化代碼
            //在底層加載Driver時會自動加載靜態(tài)代碼塊
            static {
                try {
                    DriverManager.registerDriver(new Driver());
                } catch (SQLException var1) {
                    throw new RuntimeException("Can't register driver!");
                }
            }
        */
        //Class.forName("com.mysql.jdbc.Driver");
        /*  Class.forName("com.mysql.jdbc.Driver");這句話也可以去掉
            mysql驅(qū)動5.1.6可以無需CLass.forName(“com.mysql.jdbc.Driver");
            從jdk1.5以后使用了jdbc4,不再需要顯示調(diào)用class.forName()注冊驅(qū)動而是自動調(diào)用驅(qū)動
            jar包下META-INF\services\java.sqI.Driver文本中的類名稱去注冊
            建議還是寫上,更加明確
        */
        //創(chuàng)建url和user和password
        String url = "jdbc:mysql://localhost:3306/test_table";
        String user = "root";
        String password = "161142";

        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);
    }
    
    @Test    /* 第五種(推薦使用) */
    public void testConn05() throws Exception{
        //在方式4的情況下,將信息放到配置文件里,利于后續(xù)可持續(xù)操作
        //獲取配置文件信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        //獲取相關(guān)信息
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");

        Class.forName(driver);  //加載Driver類,建議加上

        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);
    }
}

5、JDBC的查詢

使用ResultSet 記錄查詢結(jié)果
ResultSet: 底層使用ArrayList 存放每一行數(shù)據(jù)(二維字節(jié)數(shù)組,每一維表示一行中的一個數(shù)據(jù))
Resultment: 用于執(zhí)行靜態(tài)SQL語句并返回其生成的結(jié)果的對象,是一個接口,需要各個數(shù)據(jù)庫廠家來實現(xiàn)。(實際中我們一般不用這個)

public class jdbc03 {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");
        Class.forName(driver);
        Connection connection = DriverManager.getConnection(url, user, password);
        Statement statement = connection.createStatement();

        ResultSet resultSet = statement.executeQuery("select id,`name`,sex,borndate from actor;");

        while (resultSet.next()){ //resultSet.previous();//向上移動一行
            int id = resultSet.getInt(1);
            //int id = resultSet.getInt("id"); //也可以按照列明來獲取
            String name = resultSet.getString(2);
            String sex = resultSet.getString(3);
            Date date = resultSet.getDate(4);
            //Object object = resultSet.getObject(索引|列明); //對象形式操作(分情況考慮)
            System.out.println(id + "\t" + name + "\t" + sex + "\t" + date);
        }

        statement.close();
        connection.close();
    }
}

6、SQL注入

SQL注入: 是利用某些系統(tǒng)沒有對用戶輸入的數(shù)據(jù)進(jìn)行充分的檢查,而在用戶輸入數(shù)據(jù)中注入非法的SQL語句段或命令,惡意攻擊數(shù)據(jù)庫。
例如下列代碼實現(xiàn)了注入問題(而Statement就存在這個問題,所以實際開發(fā)過程中不用它)

create table admit(name varchar(32),password varchar(32));
insert into admit values('tom','1234');
select * from admit where name = 'tom' and password = '1234'; # 輸出 tom 1234
# 如果有人輸入 name 為 1' or   password 為  or '1' = '1
# 那么select 就變成
select * from admit where name = '1' or ' and password = ' or '1' = '1'; # 其中'1' = '1'永遠(yuǎn)成立

7、預(yù)處理查詢

使用PreparedStatement代替Statement就避免了注入問題,通過傳入**?** 代替拼接 (PreparedStatement接口繼承了Statement接口)

PreparedStatement的好處

  • 不再使用+拼接sql語句,減少語法錯誤
  • 有效的解決了sql注入問題!
  • 大大減少了編譯次數(shù),效率較高

7.1 查詢 已解決注入問題

public class jdbc04 {
    public static void main(String[] args) throws Exception {
        Scanner scanner = new Scanner(System.in);
        System.out.print("請輸入用戶名:");
        String name = scanner.nextLine();
        System.out.print("請輸入密碼:");
        String pwd = scanner.nextLine();

        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");
        Class.forName(driver);
        Connection connection = DriverManager.getConnection(url, user, password);

        //Statement statement = connection.createStatement();
        //preparedStatement是PreparedStatement實現(xiàn)類的對象
        PreparedStatement preparedStatement = connection.prepareStatement("select `name` ,`password` " +
                "from admit where name = ? and password = ?");
        preparedStatement.setString(1,name);    //?號下標(biāo)從1開始
        preparedStatement.setString(2,pwd);

        ResultSet resultSet = preparedStatement.executeQuery();
        if (resultSet.next()) System.out.println("登錄成功");
        else System.out.println("登陸失敗");

        preparedStatement.close();
        connection.close();
    }
}

7.2 插入,更新,刪除

public class jdbc05 {
    public static void main(String[] args) throws Exception {
        Scanner scanner = new Scanner(System.in);
        System.out.print("請輸入用戶名:");
        String name = scanner.nextLine();
        System.out.print("請輸入密碼:");
        String pwd = scanner.nextLine();

        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");
        Class.forName(driver);
        Connection connection = DriverManager.getConnection(url, user, password);

        //添加
        String sql1 = "insert into admit values(?,?)";
        //修改
        String sql2 = "update admit set name = ? where name = ? and password = ?";
        //刪除
        String sql3 = "delete from admit where name = ? and password = ?";
        PreparedStatement preparedStatement = connection.prepareStatement(sql3);
        //preparedStatement.setString(1,name+"plas");    //?號下標(biāo)從1開始
        //preparedStatement.setString(2,name);
        //preparedStatement.setString(3,pwd);

        preparedStatement.setString(1,name);
        preparedStatement.setString(2,pwd);

        int rows = preparedStatement.executeUpdate();
        if (rows > 0) System.out.println("操作成功");
        else System.out.println("操作失敗");

        preparedStatement.close();
        connection.close();
    }
}

8、工具類開發(fā)

由于在進(jìn)行數(shù)據(jù)庫操作時,有些步驟是重復(fù)的,如連接,關(guān)閉資源等操作。
工具類

package utils;
import java.sql.*;
import java.io.FileInputStream;
import java.util.Properties;
public class JDBCUtils {
    private static String user;     //用戶名
    private static String password; //密碼
    private static String url;      //連接數(shù)據(jù)庫的url
    private static String driver;   //驅(qū)動
    
    //靜態(tài)代碼塊進(jìn)行行初始化
    static {
        try {
            Properties properties = new Properties();
            properties.load(new FileInputStream("src\\mysql.properties"));
            user = properties.getProperty("user");
            password = properties.getProperty("password");
            url = properties.getProperty("url");
            driver = properties.getProperty("driver");
        } catch (Exception e) {
            //實際開發(fā)過程中(將編譯異常,改成運(yùn)行異常,用戶可以捕獲異常,也可以默認(rèn)處理該異常)
            throw new RuntimeException(e);
        }
    }
    //連接
    public static Connection getConnection(){
        try {
            return DriverManager.getConnection(url,user,password);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    //關(guān)閉資源
    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);
        }
    }
}

應(yīng)用:

public class JdbcUtilsTest {
    @Test  //測試select操作
    public void testSelect() {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        try {
            //得到連接
            connection = JDBCUtils.getConnection();

            //設(shè)置sql
            String sql = "select * from actor where id = ?";

            //創(chuàng)建PreparedStatement
            preparedStatement = connection.prepareStatement(sql);

            //占位賦值
            preparedStatement.setInt(1,2);

            //執(zhí)行
            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                /* 也可以這樣寫
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                String sex = resultSet.getString("sex");
                Date date = resultSet.getDate("borndate");
                String phone = resultSet.getString("phone");
                 */
                int id = resultSet.getInt(1);
                String name = resultSet.getString(2);
                String sex = resultSet.getString(3);
                Date date = resultSet.getDate(4);
                String phone = resultSet.getString(5);
                System.out.println(id + "\t" + name + "\t" + sex + "\t" + date + "\t" + phone);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(resultSet, preparedStatement, connection);
        }
    }

    @Test  //測試DML操作
    public void testDML() {
        Connection connection = null;
        PreparedStatement preparedStatement = null;

        try {
            //得到連接
            connection = JDBCUtils.getConnection();

            //設(shè)置sql
            String sql = "update actor set name = ?,sex = ? where id = ?";

            //創(chuàng)建PreparedStatement
            preparedStatement = connection.prepareStatement(sql);

            //占位符賦值
            preparedStatement.setString(1, "sxy");
            preparedStatement.setString(2, "男");
            preparedStatement.setInt(3, 2);

            //執(zhí)行
            preparedStatement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(null, preparedStatement, connection);
        }
    }
}

9、JDBC事務(wù)

public class Jdbc06 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            connection = JDBCUtils.getConnection();
            connection.setAutoCommit(false);//關(guān)閉自動提交(開啟事務(wù))

            //第一個動作
            String sql = "update actor set phone = phone - 10 where id = 2";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.executeUpdate();

            //int i = 1/0;  異常

            //第二個動作
            sql = "update actor set phone = phone + 10 where id = 1";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.executeUpdate();

            //提交事務(wù)
            connection.commit();

        } catch (Exception e) {
            System.out.println("有異常存在,撤銷sql服務(wù)");
            try {
                connection.rollback();  //回滾到事務(wù)開始的地方
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            JDBCUtils.close(null, preparedStatement, connection);
        }

    }
}

10、批處理

public class Jdbc07 {
    @Test   //普通處理5000條插入數(shù)據(jù)   執(zhí)行時間169839
    public void test01() {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            connection = JDBCUtils.getConnection();
            String sql = "insert into actor(id,`name`,sex) values (?,?,'男')";
            preparedStatement = connection.prepareStatement(sql);
            long begin = System.currentTimeMillis();
            for (int i = 0; i < 5000; i++) {
                preparedStatement.setString(1, 3 + i + "");
                preparedStatement.setString(2, "sxy" + (i + 1));
                preparedStatement.executeUpdate();
            }
            long end = System.currentTimeMillis();
            System.out.println(end - begin);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(null, preparedStatement, connection);
        }
    }

    @Test   //批處理   執(zhí)行時間429
    public void test02() {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            connection = JDBCUtils.getConnection();
            String sql = "insert into actor(id,`name`,sex) values (?,?,'男')";
            preparedStatement = connection.prepareStatement(sql);
            long begin = System.currentTimeMillis();
            for (int i = 0; i < 5000; i++) {
                preparedStatement.setString(1, 3 + i + "");
                preparedStatement.setString(2, "sxy" + (i + 1));
                
                //將sql語句加入批處理包中
                preparedStatement.addBatch();
                /*
                    preparedStatement.addBatch()在底層把每一條數(shù)據(jù)加入到ArrayList
                    執(zhí)行過程:檢查本條sql中的語法問題 -> 把本條sql語句加入到ArrayList -> 每1000條執(zhí)行一次
                    批處理優(yōu)點(diǎn):減少了編譯次數(shù),又減少了運(yùn)行次數(shù),效率大大提高
                    還需要在properties配置文件中將url加上?rewriteBatchedStatements=true
                    url=jdbc:mysql://localhost:3306/test_table?rewriteBatchedStatements=true
                */
                
                //當(dāng)有1000條時,在進(jìn)行處理
                if ((i + 1) % 1000 == 0) {
                    preparedStatement.executeBatch();
                    //清空批處理包
                    preparedStatement.clearBatch();
                }
            }
            long end = System.currentTimeMillis();
            System.out.println(end - begin);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(null, preparedStatement, connection);
        }
    }
}

11、數(shù)據(jù)庫連接池

由于有很多用戶連接數(shù)據(jù)庫,而數(shù)據(jù)庫連接數(shù)量又是有限制的,而且就算連接并且關(guān)閉也是很耗時,所以就有了引入了數(shù)據(jù)庫連接池可以很好的來解決這個問題。下面是普通連接數(shù)據(jù)庫連接并且關(guān)閉5000次所耗時間6249毫秒,可以發(fā)下時間相對很長。

public class ConQuestion {
    public static void main(String[] args) {
        //看看連接-關(guān)閉 connection 會耗用多久
        long start = System.currentTimeMillis();
        System.out.println("開始連接.....");
        for (int i = 0; i < 5000; i++) {
            //使用傳統(tǒng)的jdbc方式,得到連接
            Connection connection = JDBCUtils.getConnection();
            //做一些工作,比如得到PreparedStatement ,發(fā)送sql
            //..........
            //關(guān)閉
            JDBCUtils.close(null, null, connection);

        }
        long end = System.currentTimeMillis();
        System.out.println("傳統(tǒng)方式5000次 耗時=" + (end - start));//傳統(tǒng)方式5000次 耗時=6249
    }
}

11.1 數(shù)據(jù)庫連接池基本介紹

  • 預(yù)先在緩沖池中放入一定數(shù)量的連接,當(dāng)需要建立數(shù)據(jù)庫連接時,只需從“緩沖池”中取出一個,使用完畢之后再放回去。
  • 數(shù)據(jù)庫連接池負(fù)責(zé)分配,管理和釋放數(shù)據(jù)庫連接,它允許應(yīng)用程序重復(fù)使用一個現(xiàn)有的數(shù)據(jù)庫連接,而不是重新建立一個。
  • 當(dāng)應(yīng)用程序向連接池請求的連接數(shù)超過最大連接數(shù)量時,這些請求將被加入到等待隊列中。

11.2 JDBC的數(shù)據(jù)庫連接池使用

JDBC的數(shù)據(jù)庫連接池使用javax.sql.DataSource來表示,DataSource只是一個接口,該接口通常由第三方提供實現(xiàn)。

11.3 數(shù)據(jù)庫連接池的種類

  • C3P0 數(shù)據(jù)庫連接池,速度相對較慢,穩(wěn)定性不錯(hibernate,spring)。(用的較多)
  • DBCP數(shù)據(jù)庫連接池,速度相對c3p0較快,但不穩(wěn)定。
  • Proxool數(shù)據(jù)庫連接池,有監(jiān)控連接池狀態(tài)的功能,穩(wěn)定性較c3p0差一點(diǎn)。
  • BoneCP 數(shù)據(jù)庫連接池,速度快。
  • Druid (德魯伊)是阿里提供的數(shù)據(jù)庫連接池,集DBCP,C3P0,Proxool優(yōu)點(diǎn)于身的數(shù)據(jù)庫連接池。(應(yīng)用最廣)

11.4 C3P0連接池

利用C3P0連接池再次嘗試連接5000次數(shù)據(jù)庫 可以發(fā)現(xiàn)耗時方式一僅僅花了456毫秒,第二種通過配置文件操作也是花了419毫秒差不多的時間,值得說的是這個連接池連接配置文件不能是我們自己寫,官方有給定的模板(c3p0.config.xml)。

public class C3P0_ {
    @Test   //方式一: 相關(guān)參數(shù),在程序中指定user,url,password等
    public void testC3P0_1() throws Exception {
        //創(chuàng)建一個數(shù)據(jù)源對象
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();

        //通過配合文件獲取相關(guān)連接信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");

        //給數(shù)據(jù)源(comboPooledDataSource)設(shè)置相關(guān)參數(shù)
        //連接管理是由comboPooledDataSource(連接池)來管理的
        comboPooledDataSource.setDriverClass(driver);   //設(shè)置驅(qū)動
        comboPooledDataSource.setJdbcUrl(url);
        comboPooledDataSource.setUser(user);
        comboPooledDataSource.setPassword(password);

        //初始化數(shù)據(jù)源的連接數(shù)
        comboPooledDataSource.setInitialPoolSize(10);
        //數(shù)據(jù)庫連接池最大容量,如果還有連接請求,那么就會將該請求放入等待隊列中
        comboPooledDataSource.setMaxPoolSize(50);

        //測試連接池的效率, 測試對mysql 5000次操作
        long start = System.currentTimeMillis();
        for (int i = 0; i < 5000; i++) {
            //getConnection()這個方法就是重寫了DataSource接口的方法
            Connection connection = comboPooledDataSource.getConnection();
            connection.close();
        }
        long end = System.currentTimeMillis();
        //c3p0 5000連接mysql 耗時=456
        System.out.println("c3p0 5000連接mysql 耗時=" + (end - start));
        comboPooledDataSource.close();
    }
    
    
    //第二種方式 使用配置文件模板來完成
    //將C3P0 提供的 c3p0.config.xml 拷貝到 src目錄下
    //該文件指定了連接數(shù)據(jù)庫和連接池的相關(guān)參數(shù)
    @Test
    public void testC3P0_02() throws SQLException {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("sxy");
        //測試5000次連接mysql
        long start = System.currentTimeMillis();
        for (int i = 0; i < 5000; i++) {
            Connection connection = comboPooledDataSource.getConnection();
            connection.close();
        }
        long end = System.currentTimeMillis();
        //c3p0的第二種方式(5000) 耗時=419
        System.out.println("c3p0的第二種方式(5000) 耗時=" + (end - start));

    }
}

11.5 Druid連接池

在使用Druid連接池連接數(shù)據(jù)庫500000次耗時643毫秒,而C3P0500000次連接耗時2373毫秒,很顯然Druid連接速度更快。

public class Druid_ {
    @Test
    public void testDruid() throws Exception {
        //1.加入Druid jar包
        //2.加入 配置文件 druid.properties 放到src目錄下
        //3.創(chuàng)建Properties對象
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\druid.properties"));

        //4.創(chuàng)建一個指定參數(shù)的數(shù)據(jù)庫連接池
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);

        long start = System.currentTimeMillis();
        for (int i = 0; i < 500000; i++) {
            Connection connection = dataSource.getConnection();
            connection.close();
        }
        long end = System.currentTimeMillis();
        //Druid的500000次創(chuàng)建 耗時=643
        System.out.println("Druid的500000次創(chuàng)建 耗時=" + (end - start));
    }
}

對應(yīng)的工具類

public class JDBCUtilsByDruid {
    private static DataSource ds;

    //在靜態(tài)代碼塊完成 ds初始化
    static {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("src\\druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //編寫getConnection方法
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    //關(guān)閉連接:在數(shù)據(jù)庫連接池技術(shù)中,close不是真的斷掉連接,而是把使用的Connection對象放回連接池
    public static void close(ResultSet resultSet, Statement statement, Connection connection) {
        try {
            if (resultSet != null) resultSet.close();
            if (statement != null) statement.close();
            if (connection != null) connection.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

使用工具類:

public class TestUtilsByDruid {
    @Test
    public void testSelect() {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            //得到連接
            connection = JDBCUtilsByDruid.getConnection();
            System.out.println(connection.getClass());
            //connection 的運(yùn)行類型 class com.alibaba.druid.pool.DruidPooledConnection
            //設(shè)置sql
            String sql = "select * from actor where id = ?";
            //創(chuàng)建PreparedStatement
            preparedStatement = connection.prepareStatement(sql);
            //占位賦值
            preparedStatement.setInt(1, 2);
            //執(zhí)行
            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                int id = resultSet.getInt(1);
                String name = resultSet.getString(2);
                String sex = resultSet.getString(3);
                Date date = resultSet.getDate(4);
                String phone = resultSet.getString(5);
                System.out.println(id + "\t" + name + "\t" + sex + "\t" + date + "\t" + phone);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtilsByDruid.close(resultSet, preparedStatement, connection);
        }
    }
}

12、Apache-DBUtils

由于resultSet存放數(shù)據(jù)集合,在connection關(guān)閉時,resultSet結(jié)果集無法使用。所以為了使用這些數(shù)據(jù),也有JDBC官方提供的文件Apache-DBUtils來存放數(shù)據(jù)。

12.1 ArrayList模擬

ArrayList模擬Apache-DBUtils

Actor類 用來保存Actor表中的數(shù)據(jù)用的。

public class Actor { //Javabean, POJO, Domain對象
    private Integer id;
    private String name;
    private String sex;
    private Date borndate;
    private String phone;
    public Actor() { //一定要給一個無參構(gòu)造器[反射需要]
    }

    public Actor(Integer id, String name, String sex, Date borndate, String phone) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.borndate = borndate;
        this.phone = phone;
    }

    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getSex() { return sex; }
    public void setSex(String sex) { this.sex = sex; }
    public Date getBorndate() { return borndate; }
    public void setBorndate(Date borndate) { this.borndate = borndate; }
    public String getPhone() { return phone; }
    public void setPhone(String phone) { this.phone = phone; }

    @Override
    public String toString() {
        return "\nActor{" + "id=" + id + ", name='" + name + '\'' +
                ", sex='" + sex + '\'' + ", borndate=" + borndate +
                ", phone='" + phone + '\'' + '}';
    }
}

用ArrayList來存放數(shù)據(jù)

public class LikeApDB {

    @Test
    public /*也可以返回ArrayList<Actor>*/void testSelectToArrayList() {
        Connection connection = null;
        String sql = "select * from actor where id >= ?";
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        ArrayList<Actor> list = new ArrayList<>();
        try {
            connection = JDBCUtilsByDruid.getConnection();
            System.out.println(connection.getClass());
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1, 1);
            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");//getName()
                String sex = resultSet.getString("sex");//getSex()
                Date borndate = resultSet.getDate("borndate");
                String phone = resultSet.getString("phone");
                //把得到的 resultSet 的記錄,封裝到 Actor對象,放入到list集合
                list.add(new Actor(id, name, sex, borndate, phone));
            }

            System.out.println("list集合數(shù)據(jù)=" + list);
            for(Actor actor : list) {
                System.out.println("id=" + actor.getId() + "\t" + actor.getName());
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //關(guān)閉資源
            JDBCUtilsByDruid.close(resultSet, preparedStatement, connection);
        }
        //因為ArrayList 和 connection 沒有任何關(guān)聯(lián),所以該集合可以復(fù)用.
        //return  list;
    }
}

12.2 Apache-DBUtils 

 基本介紹

commons-dbutils是 Apache組織提供的一個開源JDBC工具類庫,它是對JDBC的封裝,使用dbutils能極大簡化jdbc編碼的工作量。

DbUtils類

  • QueryRunner類:該類封裝了SQL的執(zhí)行,是線程安全的??梢詫崿F(xiàn)增,刪,改,查,批處理
  • 使用QueryRunner類實現(xiàn)查詢。
  • ResultSetHandler接口:該接口用于處理 java.sql.ResultSet,將數(shù)據(jù)按要求轉(zhuǎn)換為另一種形式

應(yīng)用實例

使用Apache-DBUtils工具+數(shù)據(jù)庫連接池(Druid)方式,完成對一個表的增刪改查。

package datasourse;

import ApDB.Actor;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
public class DBUtils_Use {
    @Test       //查詢多條數(shù)據(jù)
    public void testQueryMany() throws Exception {
        //1.得到連接(Druid)
        Connection connection = JDBCUtilsByDruid.getConnection();
        //2.使用 DBUtils 類和接口,先引入 DBUtils jar文件 ,放到src目錄下
        //3.創(chuàng)建QueryRunner
        QueryRunner queryRunner = new QueryRunner();
        //4.執(zhí)行相應(yīng)的方法,返回ArrayList結(jié)果集
        String sql = "select * from actor where id >= ?";
        //String sql = "select id,`name` from actor where id >= ?";
        /*
        (1) query 方法就是執(zhí)行sql 語句,得到resultSet ---封裝到 --> ArrayList 集合中
        (2) 返回集合
        (3) connection: 連接
        (4) sql : 執(zhí)行的sql語句
        (5) new BeanListHandler<>(Actor.class): 在將resultSet -> Actor 對象 -> 封裝到 ArrayList
            底層使用反射機(jī)制 去獲取Actor 類的屬性,然后進(jìn)行封裝
        (6) 1 就是給 sql 語句中的? 賦值,可以有多個值,因為是可變參數(shù)Object... params
        (7) 底層得到的resultSet ,會在query 關(guān)閉, 關(guān)閉PreparedStatement
         */
        List<Actor> query =
                queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class), 1);
        /**
         * 分析 queryRunner.query方法源碼分析
         * public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
         *         PreparedStatement stmt = null;//定義PreparedStatement
         *         ResultSet rs = null;//接收返回的 ResultSet
         *         Object result = null;//返回ArrayList
         *
         *         try {
         *             stmt = this.prepareStatement(conn, sql);//創(chuàng)建PreparedStatement
         *             this.fillStatement(stmt, params);//對sql 進(jìn)行 ? 賦值
         *             rs = this.wrap(stmt.executeQuery());//執(zhí)行sql,返回resultset
         *             result = rsh.handle(rs);//返回的resultset --> arrayList[result] [使用到反射,對傳入class對象處理]
         *         } catch (SQLException var33) {
         *             this.rethrow(var33, sql, params);
         *         } finally {
         *             try {
         *                 this.close(rs);//關(guān)閉resultset
         *             } finally {
         *                 this.close((Statement)stmt);//關(guān)閉preparedstatement對象
         *             }
         *         }
         *
         *         return result;
         *     }
         */
        for (Actor actor : query) {
            System.out.print(actor);
        }
        JDBCUtilsByDruid.close(null,null,connection);
    }

    @Test               //查詢單條記錄
    public void testQuerySingle() throws SQLException {
        Connection connection = JDBCUtilsByDruid.getConnection();
        QueryRunner queryRunner = new QueryRunner();
        String sql = "select * from actor where id = ?";
        //已知查詢的是單行,所以就用BeanHandler,返回一個對應(yīng)的對象
        Actor query = queryRunner.query(connection, sql, new BeanHandler<>(Actor.class), 2);
        System.out.print(query);
        JDBCUtilsByDruid.close(null,null,connection);
    }

    @Test               //查詢單行單列(某個信息)  返回一個Object對象
    public void testQuerySingleObject() throws SQLException {
        Connection connection = JDBCUtilsByDruid.getConnection();
        QueryRunner queryRunner = new QueryRunner();
        String sql = "select `name` from actor where id = ?";
        //已知查詢的是單行單列,所以就用BeanHandler,返回一個Object
        Object query = queryRunner.query(connection, sql, new ScalarHandler(), 1);
        System.out.println(query);
        JDBCUtilsByDruid.close(null,null,connection);
    }

    @Test       //演示DML操作(insert,update,delete)
    public void testDML() throws SQLException {
        Connection connection = JDBCUtilsByDruid.getConnection();
        QueryRunner queryRunner = new QueryRunner();

        //String sql = "update actor set phone = ? where id = ?";
        //int affectedRow = queryRunner.update(connection, sql, "110", 2);

        String sql = "insert into actor values(?,?,?,?,?)";
        int affectedRow = queryRunner.update(connection, sql, 3, "xhj", "女", "2000-05-26", "110");

        //String sql = "delete from actor where id = ?";
        //int affectedRow = queryRunner.update(connection, sql, 5004);

        System.out.println(affectedRow > 0 ? "OK" : "NO");
        JDBCUtilsByDruid.close(null,null,connection);
    }
}

13、BasicDao

引入問題

  • SQL語句是固定,不能通過參數(shù)傳入,通用性不好,需要進(jìn)行改進(jìn),更方便執(zhí)行增刪改查
  • 對于select 操作,如果有返回值,返回類型不能固定,需要使用泛型
  • 將來的表很多,業(yè)務(wù)需求復(fù)雜,不可能只靠一個JAVA類完成。

所以在實際開發(fā)中,也有解決辦法 —BasicDao

13.1 BasicDAO類

public class BasicDAO<T> {  //泛型指定具體的類型
    private QueryRunner queryRunner = new QueryRunner();

    //開發(fā)通用的DML,針對任意表
    public int update(String sql,Object... parameter){
        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            return queryRunner.update(connection, sql, parameter);
        } catch (SQLException e) {
            throw new RuntimeException(e);//將編譯異常轉(zhuǎn)化成運(yùn)行異常,可以被捕獲,也可以被拋出
        }finally {
            JDBCUtilsByDruid.close(null,null,connection);
        }
    }

    /**                     返回多個對象(多行結(jié)果)
     *
     * @param sql       sql語句,可以存在?
     * @param clazz     傳入一個類的class對象   例如Actor.class
     * @param parameter 傳入?號具體的值,可以有多個
     * @return          根據(jù)類似Actor.class類型,返回對應(yīng)的ArrayList集合
     */
    public List<T> QueryMultiply(String sql,Class<T> clazz, Object... parameter){
        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            return queryRunner.query(connection,sql,new BeanListHandler<T>(clazz),parameter);
        } catch (SQLException e) {
            throw new RuntimeException(e);//將編譯異常轉(zhuǎn)化成運(yùn)行異常,可以被捕獲,也可以被拋出
        }finally {
            JDBCUtilsByDruid.close(null,null,connection);
        }
    }
    //返回單個對象(單行數(shù)據(jù))
    public T querySingle(String sql,Class<T> clazz,Object... parameter){
        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            return queryRunner.query(connection,sql,new BeanHandler<T>(clazz),parameter);
        } catch (SQLException e) {
            throw new RuntimeException(e);//將編譯異常轉(zhuǎn)化成運(yùn)行異常,可以被捕獲,也可以被拋出
        }finally {
            JDBCUtilsByDruid.close(null,null,connection);
        }
    }
    //返回單個對象的單個屬性(單行中的單列)
    public Object queryScalar(String sql,Object... parameter){
        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            return queryRunner.query(connection,sql,new ScalarHandler(),parameter);
        } catch (SQLException e) {
            throw new RuntimeException(e);//將編譯異常轉(zhuǎn)化成運(yùn)行異常,可以被捕獲,也可以被拋出
        }finally {
            JDBCUtilsByDruid.close(null,null,connection);
        }
    }
}

13.2 domain中的類

public class Actor { //Javabean, POJO, Domain對象
    private Integer id;
    private String name;
    private String sex;
    private Date borndate;
    private String phone;
    public Actor() { //一定要給一個無參構(gòu)造器[反射需要]
    }

    public Actor(Integer id, String name, String sex, Date borndate, String phone) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.borndate = borndate;
        this.phone = phone;
    }

    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getSex() { return sex; }
    public void setSex(String sex) { this.sex = sex; }
    public Date getBorndate() { return borndate; }
    public void setBorndate(Date borndate) { this.borndate = borndate; }
    public String getPhone() { return phone; }
    public void setPhone(String phone) { this.phone = phone; }

    @Override
    public String toString() {
        return "\nActor{" + "id=" + id + ", name='" + name + '\'' +
                ", sex='" + sex + '\'' + ", borndate=" + borndate +
                ", phone='" + phone + '\'' + '}';
    }
}

ActorDAO類繼承BasicDAO類,這樣的類可以有很多。

public class ActorDAO extends BasicDAO<Actor> {
}

13.3 測試類

public class TestDAO {
    @Test//測試ActorDAO對actor表的操作
    public void testActorDAO() {
        ActorDAO actorDAO = new ActorDAO();
        //1.查詢多行
        List<Actor> actors = actorDAO.QueryMultiply("select * from actor where id >= ?", Actor.class, 1);
        System.out.println(actors);

        //2.查詢單行
        Actor actor = actorDAO.querySingle("select * from actor where id = ?", Actor.class, 1);
        System.out.println(actor);

        //3.查詢單行單個數(shù)據(jù)
        Object o = actorDAO.queryScalar("select name from actor where id = ?", 1);
        System.out.println(o);

        //4.DML操作   當(dāng)前演示update
        int affectedRow = actorDAO.update("update actor set phone = ? where id = ?", "120", 3);
        System.out.println(affectedRow > 0 ? "OK" : "NO");
    }
}

到此這篇關(guān)于詳細(xì)說明關(guān)于Java的數(shù)據(jù)庫連接(JDBC)的文章就介紹到這了,更多相關(guān)Java的數(shù)據(jù)庫連接(JDBC)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中JUC包(java.util.concurrent)下的常用子類

    Java中JUC包(java.util.concurrent)下的常用子類

    相信大家已經(jīng)對并發(fā)機(jī)制中出現(xiàn)的很多的常見知識點(diǎn)進(jìn)行了總結(jié),下面這篇文章主要給大家介紹了關(guān)于Java中JUC包(java.util.concurrent)下的常用子類的相關(guān)資料,文中通過圖文以及示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12
  • Java中接口和抽象類的區(qū)別詳解

    Java中接口和抽象類的區(qū)別詳解

    這篇文章主要介紹了Java中接口和抽象類的區(qū)別詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Java初級必看的數(shù)據(jù)類型與常量變量知識點(diǎn)

    Java初級必看的數(shù)據(jù)類型與常量變量知識點(diǎn)

    這篇文章主要給大家介紹了關(guān)于Java初級必看的數(shù)據(jù)類型與常量變量知識點(diǎn)的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • SpringBoot實現(xiàn)列表數(shù)據(jù)導(dǎo)出為Excel文件

    SpringBoot實現(xiàn)列表數(shù)據(jù)導(dǎo)出為Excel文件

    這篇文章主要為大家詳細(xì)介紹了在Spring?Boot框架中如何將列表數(shù)據(jù)導(dǎo)出為Excel文件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下
    2024-02-02
  • Spring boot項目中異常攔截設(shè)計和處理詳解

    Spring boot項目中異常攔截設(shè)計和處理詳解

    這篇文章主要介給大家紹了關(guān)于Spring boot項目中異常攔截設(shè)計和處理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用spring boot具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起看看吧
    2018-12-12
  • Spring?BeanFactory工廠使用教程

    Spring?BeanFactory工廠使用教程

    Spring的本質(zhì)是一個bean工廠(beanFactory)或者說bean容器,它按照我們的要求,生產(chǎn)我們需要的各種各樣的bean,提供給我們使用。只是在生產(chǎn)bean的過程中,需要解決bean之間的依賴問題,才引入了依賴注入(DI)這種技術(shù)
    2023-02-02
  • SpringBoot創(chuàng)建JSP登錄頁面功能實例代碼

    SpringBoot創(chuàng)建JSP登錄頁面功能實例代碼

    這篇文章主要介紹了SpringBoot創(chuàng)建JSP登錄頁面功能實例代碼,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-04-04
  • JavaScript中HTML元素操作的實現(xiàn)

    JavaScript中HTML元素操作的實現(xiàn)

    本文主要介紹了JavaScript中HTML元素操作的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • Java使用synchronized修飾方法來同步線程的實例演示

    Java使用synchronized修飾方法來同步線程的實例演示

    synchronized下的方法控制多線程程序中的線程同步非常方便,這里就來看一下Java使用synchronized修飾方法來同步線程的實例演示,需要的朋友可以參考下
    2016-06-06
  • Java虛擬機(jī)常見內(nèi)存溢出錯誤匯總

    Java虛擬機(jī)常見內(nèi)存溢出錯誤匯總

    這篇文章主要匯總了Java虛擬機(jī)常見的內(nèi)存溢出錯誤,警示大家,避免出錯,感興趣的朋友可以了解下
    2020-09-09

最新評論