【Mybatis源碼解析】- JDBC連接數據庫的原理和操作


JDBC連接數據庫的原理和操作

JDBC即Java DataBase Connectivity,java數據庫連接;JDBC 提供的API可以讓JAVA通過API方式訪問關系型數據庫,執行SQL語句,獲取數據;常見關系型數據庫如Oracle、MySQL、SQLServer等;對於非關系型數據庫如Redis、mongonDB等就顯得無力;關系型數據庫最典型的數據結構是表,易於維護,靈活使用(使用表結構,支持SQL語言的簡單及復雜表及多表之間的查詢),非關系型數據庫嚴格上不是一種數據庫,應該是一種數據結構化存儲方法的集合(文檔型、鍵值對型、列式數據庫、圖形數據庫),相對於關系型數據庫(讀寫性能比較差,效率低,靈活度低、高並發處理顯得雞肋);非關系型數據庫優點多多,速度快、高拓展、低成本(就數據結構復雜,其他都比較簡單,學習難度就有點大)。
JDBC是一種規范,它提供的接口,是一套完整的、可移植的訪問底層數據庫的程序。

JDBC連接數據庫步驟

  1. 在開發環境中加載指定的數據庫驅動。例如在mysql使用環境中,則需要下載mysql對應的驅動程序mysql-connector-java-xxx.java
  2. 在應用中加載驅動。例如使用Class.forName()的方式將驅動類加載到內存中;
  3. 創建數據庫連接對象。在接口Driver中定義了相應的連接方式;
  4. 創建Statement對象。Statement類的主要是用於執行靜態 SQL語句並返回它所生成結果的對象。通過Connection對象的createStatement()方法可以創建一個Statement對象。例如:Statement statament = connection.createStatement()
  5. 調用Statement對象的相關方法執行相對應的 SQL 語句;
  6. 關閉數據庫連接:使用完數據庫或者不需要訪問數據庫時,通過Connection.close() 方法及時關閉數據連接。

示例

1、數據准備

現在mysql數據庫中創建person表,並插入需要的數據

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for blog
-- ----------------------------
DROP TABLE IF EXISTS `person`;
CREATE TABLE `person` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `nickname` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
    `mobile` varchar(11) COLLATE utf8mb4_general_ci DEFAULT NULL,
    `age` int(2) DEFAULT NULL,
    `email` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

-- ----------------------------
-- Records of blog
-- ----------------------------
BEGIN;
INSERT INTO `person` VALUES (1, 'wujiwen',  '13011111111', 20, 'jiwenwu@outlook.com');
INSERT INTO `person` VALUES (2, 'mybatis', '13100000000', 10, 'service@mybatis.com');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

2、引入mysql驅動

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.21</version>
</dependency>

3、使用JDBC連接數據庫

按照上面的步驟,我們先將特定廠商Mysql的驅動加載到內存中,然后通過Driver實例獲取數據庫連接

private final String url = "jdbc:mysql://127.0.0.1:3306/mybatis";
private final String user = "root";
private final String password = "passw0rd";
private final String mysqlDriver = "com.mysql.cj.jdbc.Driver";

public Connection getConnectionByProperties() throws Exception {
	  Properties properties = new Properties();
	  properties.put("user",user);
	  properties.put("password",password);
	  // 加載驅動實例
	  Driver driver = ((Driver) Class.forName(mysqlDriver).newInstance());
	  // 獲取鏈接
	  return driver.connect(url,properties);
}

public Connection getConnectionByUserPassword() throws Exception {
	  // 加載驅動實例
		Class.forName(mysqlDriver);
		// 通過DriverManager獲取
	  return DriverManager.getConnection(url, user, password);
}

當使用Class.forName(mysqlDriver)加載驅動類到內存中的時候,同時會執行這個驅動類中的靜態代碼塊,創建一個Driver實例;然后調用DriverManager 進行注冊DriverDriverManager 作為 Driver 的管理器,它在第一次被調用的時候,它會被加載到內存中,然后執行其定義的靜態代碼段,在靜態代碼段中,有一個 loadInitialDrivers() 靜態方法,用於加載配置在jdbc.drivers 系統屬性內的驅動DriverDriverManager來統一管理操作Driver和獲取Connection對象;

4、增刪改查

列舉最簡單的sql操作示例

public int insert(Connection connection) throws SQLException {
        try {
            Statement statement = connection.createStatement();
            return statement.executeUpdate("insert into `person` (nickname,mobile,age,email) values ('insert', '13100000000', 14, 'insert@mybatis.com');");
        }catch (Exception e){
            try {
                connection.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            connection.close();
        }
        return 0;
    }

    public int update(Connection connection) throws SQLException {
        try {
            Statement statement = connection.createStatement();
            return statement.executeUpdate("update `person` set mobile = '12000000000' where id = 4;");
        }catch (Exception e){
            try {
                connection.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            connection.close();
        }
        return 0;
    }

    public int delete(Connection connection) throws SQLException {
        try {
            Statement statement = connection.createStatement();
            return statement.executeUpdate("delete `person`  where id = 4;");
        }catch (Exception e){
            try {
                connection.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            connection.close();
        }
        return 0;
    }

    public List<Person> listPerson(Connection connection) throws SQLException {
        List<Person> personList = new ArrayList<>();
        try {
            Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery("select  * from `person`;");
            while (resultSet.next()){
                Person person = new Person();
								// 指定列名方式獲取
                Integer id = resultSet.getInt("id");
								// 指定列索引方式獲取,startIndex = 1
                String nickname = resultSet.getString(2);
                String mobile = resultSet.getString("mobile");
                Integer age = resultSet.getInt(4);
                String email = resultSet.getString("email");
                person.setId(id);
                person.setNickname(nickname);
                person.setMobile(mobile);
                person.setAge(age);
                person.setEmail(email);
                personList.add(person);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            connection.close();
        }
        return personList;
    }

JDBC簡化方案

原生方式不僅硬編碼多而且非常的不靈活,對於結果的封裝處理也比較麻煩。這時候也出現了一些比較好用的簡化操作方案,例如常見的Hibernate,DBUtils,Mybatis。本文將簡單的介紹一下DBUtils是如何簡化數據的查詢和操作的。

DBUtils

該組件嚴格上說不是一款持久化框架,更多的可以理解成一款簡化操作工具集合,將原生JDBC的很多動態化操作進行了封裝,方便了使用

核心功能介紹

  • QueryRunner類,提供了對sql語句的各種api
  • ResultSetHandler接口,用於定義查詢操作后,如何對結果進行封裝
  • DbUtils工具類,里面封裝了很多關閉資源及處理事務的方法

示例

    private final String url = "jdbc:mysql://127.0.0.1:3306/mybatis";
    private final String user = "root";
    private final String password = "passw0rd";
    private final String mysqlDriver = "com.mysql.cj.jdbc.Driver";

    public Connection getConnection() throws Exception {
        Class.forName(mysqlDriver);
        return DriverManager.getConnection(url, user, password);
    }

    public int insert(Connection connection) throws SQLException {
        QueryRunner runner = new QueryRunner();
        String sql = "insert into `person` (nickname,mobile,age,email) values (?,?,?,?);";
        Object[] params = {"dbutils", "12000000000", 10, "dbutils@dbutils.com"};
        return runner.update(connection, sql, params);
    }

    public int update(Connection connection) throws SQLException {
        QueryRunner runner = new QueryRunner();
        String sql = "update `person` set mobile = '00000000000' where id  = ?";
        Object params = 5;
        return runner.update(connection,sql,params);
    }

    public int delete(Connection connection) throws SQLException{
        QueryRunner runner = new QueryRunner();
        String sql = "delete `person` where id  = ?";
        Object params = 5;
        return runner.update(connection,sql,params);
    }
    // 查詢單個對象
    public Person getPerson(Connection connection) throws SQLException {
        QueryRunner runner = new QueryRunner();
        String sql = "select * from `person` where id = ? ";
        Object params = 1;
        return runner.query(connection,sql,new BeanHandler<>(Person.class),params);
    }
    // 查詢集合對象
    public List<Person> listPerson(Connection connection) throws SQLException {
        QueryRunner runner = new QueryRunner();
        String sql = "select * from `person`";
        return runner.query(connection,sql,new BeanListHandler<>(Person.class));
    }

這時候我們會發現動態sql的編寫也比較簡單了,參數的設置比較靈活,特別是對於查詢結果的封裝變得容易多了。

但是還有很多不足的地方,例如如果將nickname修改成username,這種情況就無法准確的對應的bean結果集。我們也可以對其進行改造,添加相應的別名方式處理。

相對於Hibernate的龐大和繁瑣,我們更推薦Mybatis去處理。MyBatis 免除了幾乎所有的 JDBC 代碼以及設置參數和獲取結果集的工作。MyBatis 可以通過簡單的 XML 或注解來配置和映射原始類型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 對象)為數據庫中的記錄。

后續將簡單演示mybatis是如何處理這些問題的,並了解這背后的相關原理及實現方式。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM