国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

Spring JDBC的使用詳解

發(fā)布時(shí)間:2021-07-17 21:51 來(lái)源:腳本之家 閱讀:0 作者:黑色的燈塔 欄目: 編程語(yǔ)言 歡迎投稿:712375056

目錄

        JDBC介紹

        從這篇文章開(kāi)始,我們將會(huì )介紹SpringBoot另外一個(gè)核心的技術(shù),即數據訪(fǎng)問(wèn)技術(shù),提到數據訪(fǎng)問(wèn),學(xué)習Java的同學(xué)瞬間能就想起JDBC技術(shù),JDBC 是 Java Database Connectivity 的全稱(chēng),是Java語(yǔ)言中用來(lái)規范客戶(hù)端程序如何來(lái)訪(fǎng)問(wèn)數據庫的應用程序接口,提供了諸如查詢(xún)和更新數據庫中數據的一套標準的API,這套標準不同的數據庫廠(chǎng)家之間共同準守,并提供各自的具體實(shí)現。如圖所示:

        這樣設計的好處,就是Java程序只需要和JDBC API交互,從而屏蔽了訪(fǎng)問(wèn)數據庫的復雜的實(shí)現,大大降低了Java程序訪(fǎng)問(wèn)數據庫的復雜度。對于日常開(kāi)發(fā)而言,我們只需要掌握JDBC API 規范中的幾個(gè)核心編程對象即可,這些對象包括DriverManger、Connection、Statement及ResultSet。

        DriverManager

        DriverManager主要負責加載不同數據庫廠(chǎng)家提供的驅動(dòng)程序包(Driver),并且根據不同的請求向Java程序返回數據庫連接(Connection)對象,先看下Driver接口的定義:

        public interface Driver {
            //獲取數據庫連接
            Connection connect(String url, java.util.Properties info)
                throws SQLException;
            boolean acceptsURL(String url) throws SQLException;
            DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info)
                                 throws SQLException;
            int getMajorVersion();
            int getMinorVersion();
            boolean jdbcCompliant();
            public Logger getParentLogger() throws SQLFeatureNotSupportedException;
        }
        

        Driver中有個(gè)重要的方法 connect,來(lái)提供Connection對象

        不同的數據庫對Driver,有具體的實(shí)現,以MySql為例:

        public class Driver extends NonRegisteringDriver implements java.sql.Driver {
            // 通過(guò) DriverManager 注冊 Driver
            static {
                try {
                    java.sql.DriverManager.registerDriver(new Driver());
                } catch (SQLException E) {
                    throw new RuntimeException("Can't register driver!");
                }
        	}
        	…
        }
        

        這里用到了DriverManager,DriverManager通過(guò) registerDriver來(lái)注冊不同數據庫的Driver,并且還提供了getConnection返回數據庫連接對象。

        Connection

        通過(guò)DriverManager可以獲取Connetion對象,Connection對象可以理解與數據庫連接的一種會(huì )話(huà)(Session),一個(gè)Connection對象代表一個(gè)數據庫的連接,負責完成與數據庫底層的通訊。

        Connection對象提供了一組重載的方法來(lái)創(chuàng )建Statement和PreparedStatement,Statement和PreparedStatement是SQL執行的載體,另外Connection對象還會(huì )涉及事務(wù)相關(guān)的操作。

        Connection對象最核心的幾個(gè)方法如下:

        public interface Connection  extends Wrapper, AutoCloseable {
        	//創(chuàng  )建 Statement
        	Statement createStatement() throws SQLException;
        	//創(chuàng  )建 PreparedStatement
        	PreparedStatement prepareStatement(String sql) throws SQLException;
        	//提交
        	void commit() throws SQLException;
        	//回滾
        	void rollback() throws SQLException;
        	//關(guān)閉連接
        	void close() throws SQLException;
        }
        

        Statement/PreparedStatement

        Statement和PreparedStatement是由Connection對象來(lái)創(chuàng )建的,用來(lái)執行靜態(tài)的SQL語(yǔ)句并且返回生成的結果集對象,這里存在兩種類(lèi)型,一種是普通的Statement,另外一種支持預編譯的PreparedStatement。

        所謂預編譯,是指數據庫的編譯器會(huì )對 SQL 語(yǔ)句提前編譯,然后將預編譯的結果緩存到數據庫中,下次執行時(shí)就可以通過(guò)替換參數并直接使用編譯過(guò)的語(yǔ)句,從而大大提高 SQL 的執行效率。

        以Statement為例,看下Statement最核心的方法:

        public interface Statement extends Wrapper, AutoCloseable {
        	//執行查詢(xún)語(yǔ)句
        	ResultSet executeQuery(String sql) throws SQLException; 
        	//執行更新語(yǔ)句
        	int executeUpdate(String sql) throws SQLException; 
        	//執行 SQL 語(yǔ)句
        	boolean execute(String sql) throws SQLException; 
        	//執行批處理
            int[] executeBatch() throws SQLException;
        }
        

        ResultSet

        通過(guò)Statement或PreparedStatement執行SQL語(yǔ)句,我們引出了另外一個(gè)對象即為ResultSet對象,代碼如下:

        public interface ResultSet extends Wrapper, AutoCloseable {
        	//獲取下一個(gè)結果
        	boolean next() throws SQLException;
        	//獲取某一個(gè)類(lèi)型的結果值
        	Value getXXX(int columnIndex) throws SQLException;
        	…
        }
        

        ResultSet對象提供了next()方法,用來(lái)對整個(gè)結果集遍歷操作,如果next()方法返回為true,說(shuō)明還有下一條記錄,

        我們可以調用 ResultSet 對象的一系列 getXXX() 方法來(lái)取得對應的結果值。

        JDBC訪(fǎng)問(wèn)數據庫流程

        對于開(kāi)發(fā)人員而言,通過(guò)JDBC的API是Java訪(fǎng)問(wèn)數據庫的主要途徑,下面用代碼來(lái)展示下訪(fǎng)問(wèn)數據庫的一個(gè)整體流程:

        String url = "jdbc:mysql://localhost:3306/test" ;
        String username = "root" ;
        String password = "root" ;
        
        //1.通過(guò)DriverManager獲取connection連接
        Connection connection = DriverManager.getConnection(url,username,password);
        
        //2.創(chuàng  )建preparedStatement
        PreparedStatement preparedStatement = connection.prepareStatement("select * from user");
        
        //3.執行SQL返回ResultSet
        ResultSet resultSet = preparedStatement.executeQuery();
        
        //4.遍歷resultSet結果集
        while (resultSet.next()){
            //resultSet.getString("1");
        }
        
        //5.釋放資源
        resultSet.close();
        preparedStatement.close();
        connection.close();
        

        配置數據源

        上面我們在介紹JDBC的時(shí)候,Connection對象是通過(guò)DriverManager獲取,Connection對象代表著(zhù)和數據庫的連接,每次通過(guò)DriverManager獲取比較耗時(shí),影響了系統的性能。那有沒(méi)有辦法能夠復用Connection對象呢,答案是肯定的

        JDBC給我們提供了DataSource接口來(lái)實(shí)現Connection的復用,核心代碼如下:

        public interface DataSource  extends CommonDataSource, Wrapper {
         
          Connection getConnection() throws SQLException;
         
          Connection getConnection(String username, String password)
            throws SQLException;
        }
        

        作為一種基礎組件,不需要開(kāi)發(fā)人員自己實(shí)現 DataSource,因為業(yè)界已經(jīng)存在了很多優(yōu)秀的實(shí)現方案,如 DBCP、C3P0 、Druid 、Hikari等

        SpringBoot默認HikariDataSource作為DataSource的實(shí)現,現在我們SpringBoot為例,看下SpringBoot如何通過(guò)JDBC來(lái)操作數據庫的,在進(jìn)行數據庫操作之前,我們首先需要先配置DataSource,SpringBoot配置DataSource非常簡(jiǎn)單,只需要在配置文件中添加DataSource的配置:

        spring:
          # datasource 數據源配置內容
          datasource:
            url: jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8
            driver-class-name: com.mysql.cj.jdbc.Driver
            username: root
            password: root
        

        使用JDBC操縱數據庫

        DataSource配好后,我們在本地的數據庫服務(wù)中,創(chuàng )建一個(gè)test數據庫,并且執行以下DDL創(chuàng )建user表

        CREATE TABLE `user` (
          `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
          `username` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用戶(hù)名',
          `password` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密碼',
          `create_time` datetime DEFAULT NULL COMMENT '創(chuàng  )建時(shí)間',
          PRIMARY KEY (`id`),
          UNIQUE KEY `idx_username` (`username`)
        ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
        

        接下來(lái)我們創(chuàng )建一個(gè)實(shí)體類(lèi),實(shí)體類(lèi)中屬性和user表中字段一一對應

        @Data
        public class User {
            /**
             * 主鍵
             */
            private Integer id;
            /**
             * 用戶(hù)名
             */
            private String username;
            /**
             * 密碼
             */
            private String password;
            /**
             * 創(chuàng  )建時(shí)間
             */
            private Date createTime;
        
        }
        

        注意:這里使用了Lombok的@Data注解來(lái)生成get/set方法。

        我們再定義一個(gè)UserDao接口,

        public interface UserDao {
            /**
             *  新增
             * @param user
             * @return
             */
            Integer insert(User user);
            /**
             *  根據ID查詢(xún)
             * @param id
             * @return
             */
            User selectById(Integer id);
            /**
             *  根據ID更新
             * @param user
             * @return
             */
            Integer updateById(User user);
            /**
             *  根據ID刪除
             * @param id
             * @return
             */
            Integer deleteById(Integer id);
        }
        

        這里之所以要抽離出一個(gè)UserDao一層有兩個(gè)原因:第一UserDao只封裝了對use表的數據庫操作,代碼易于維護和管理,第二我們可以基于UserDao接口提供不同的實(shí)現來(lái)訪(fǎng)問(wèn)數據庫,比如我們可以提供基于原生JDBC的實(shí)現,也可以用JDBCTemplate實(shí)現數據庫的訪(fǎng)問(wèn),還可以通過(guò)Mybatis等

        接下來(lái)將通過(guò)代碼形式來(lái)展示下SpringBoot是如何通過(guò)JDBC API對數據庫進(jìn)行CRUD操作的。我們來(lái)定義UserDao的具體實(shí)現類(lèi)命名為:UserRawJdbcDao實(shí)現以下方法:

        新增數據

        @Override
            public Integer insert(User user) {
              	final String SQL_INSERT = "INSERT INTO user(username, password, create_time) VALUES(?, ?, ?)";
                Connection connection = null;
                PreparedStatement statement = null;
                ResultSet rs = null;
                Integer count = 0;
                try{
                    connection = dataSource.getConnection();
                    statement = connection.prepareStatement(SQL_INSERT, Statement.RETURN_GENERATED_KEYS);
                    statement.setString(1,user.getUsername());
                    statement.setString(2,user.getPassword());
                    statement.setTimestamp(3,new Timestamp(user.getCreateTime().getTime()));
                    count = statement.executeUpdate();
                    rs = statement.getGeneratedKeys();
                    if(rs.next()){
                        user.setId(rs.getInt(1));
                    }
                }catch (SQLException e){
                    e.printStackTrace();
                }finally {
                    try {
                        if(rs != null){
                            rs.close();
                        }
                        if(statement != null){
                            statement.close();
                        }
                        if(connection != null){
                            connection.close();
                        }
        
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
        
                }
                return count;
            }
        

        查詢(xún)數據

        @Override
            public User selectById(Integer id) {
                final String SQL_SELECT_ID = "SELECT id,username,password,create_time FROM user WHERE id = ?";
                Connection connection = null;
                PreparedStatement statement = null;
                ResultSet rs = null;
                User user = null;
                try{
                    connection = dataSource.getConnection();
                    statement = connection.prepareStatement(SQL_SELECT_ID);
                    statement.setInt(1, id);
                    rs = statement.executeQuery();
                    if(rs.next()){
                        user = new User();
                        user.setId(rs.getInt("id"));
                        user.setUsername(rs.getString("username"));
                        user.setPassword(rs.getString("password"));
                        user.setCreateTime(rs.getTimestamp("create_time"));
                    }
                }catch (SQLException e){
                    e.printStackTrace();
                }finally {
                    try {
                        if(rs != null){
                            rs.close();
                        }
                        if(statement != null){
                            statement.close();
                        }
                        if(connection != null){
                            connection.close();
                        }
        
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                return user;
            }
        

        更新數據

        @Override
            public Integer updateById(User user) {
                final String SQL_UPDATE = "UPDATE user SET username = ?, password = ? WHERE id = ?";
                Connection connection = null;
                PreparedStatement statement = null;
                ResultSet rs = null;
                Integer count = 0;
        
                try{
                    connection = dataSource.getConnection();
                    statement = connection.prepareStatement(SQL_UPDATE);
                    statement.setString(1,user.getUsername());
                    statement.setString(2,user.getPassword());
                    statement.setInt(3,user.getId());
                    count = statement.executeUpdate();
                }catch (SQLException e){
                    e.printStackTrace();
                }finally {
                    try {
                        if(rs != null){
                            rs.close();
                        }
                        if(statement != null){
                            statement.close();
                        }
                        if(connection != null){
                            connection.close();
                        }
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                return count;
            }
        

        刪除數據

        @Override
            public Integer deleteById(Integer id) {
                final String SQL_DELETE = "DELETE FROM user WHERE id = ?";
                Connection connection = null;
                PreparedStatement statement = null;
                ResultSet rs = null;
                Integer count = 0;
                try{
                    connection = dataSource.getConnection();
                    statement = connection.prepareStatement(SQL_DELETE);
                    statement.setInt(1,id);
                    count = statement.executeUpdate();
                }catch (SQLException e){
                    e.printStackTrace();
                }finally {
                    try {
                        if(rs != null){
                            rs.close();
                        }
                        if(statement != null){
                            statement.close();
                        }
                        if(connection != null){
                            connection.close();
                        }
        
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                return count;
            }
        

        到此,SpringBoot通過(guò)調用原生的JDBC的API完成對user表的CRUD操作,這代碼對有代碼潔癖的同學(xué)簡(jiǎn)直不能忍,有大量共性的代碼,如創(chuàng )建Connection、Statement、ResultSet、資源的釋放和異常的處理。這部分封裝和優(yōu)化SpringBoot已經(jīng)處理過(guò)了,SpringBoot提供了JdbcTemplate模板工具類(lèi)實(shí)現數據訪(fǎng)問(wèn),它簡(jiǎn)化了JDBC API的使用方法。

        使用JdbcTemplate操縱數據庫

        同UserRawJdbcDao,我們再定義UserDao的另外一套實(shí)現類(lèi)命名為:UserJdbcDao,這套實(shí)現類(lèi)是通過(guò)JdbcTemplate完成對數據庫的操作,完成接口定義的方法如下:

        新增數據

         
        @Override
        public Integer insert(User user){
          
            // 創(chuàng  )建 KeyHolder 對象,設置返回的主鍵 ID
            KeyHolder keyHolder = new GeneratedKeyHolder();
            int count = jdbcTemplate.update(INSERT_PREPARED_STATEMENT_CREATOR_FACTORY.newPreparedStatementCreator(
                    Arrays.asList(user.getUsername(),user.getPassword(),user.getCreateTime())),keyHolder);
            // 設置 ID 主鍵到 entity 實(shí)體中
            if (keyHolder.getKey() != null) {
                user.setId(keyHolder.getKey().intValue());
            }
            // 返回影響行數
            return count;
        }
        

        查詢(xún)數據

          @Override
            public User selectById(Integer id){
                User result = jdbcTemplate.queryForObject("SELECT id, username, password, create_time FROM user WHERE id=?",
                        new BeanPropertyRowMapper<>(User.class), id);
                return result;
            }
        

        更新數據

          @Override
            public Integer updateById(User user) {
                return jdbcTemplate.update("UPDATE user SET username = ?, password = ? WHERE id = ?",
                        user.getUsername(),user.getPassword(),user.getId());
            }
        

        刪除數據

        @Override
            public Integer deleteById(Integer id){
                return jdbcTemplate.update("DELETE FROM user WHERE id = ?", id);
            }
        

        小結

        通過(guò)對比我們發(fā)現使用JdbcTemplate模板工具類(lèi)可以大大減少JDBC訪(fǎng)問(wèn)數據庫的代碼復雜度,作為開(kāi)發(fā)人員我們應該只關(guān)心業(yè)務(wù)邏輯的具體實(shí)現過(guò)程,對JDBC底層對象的創(chuàng )建,資源的釋放,異常的捕獲,應該交給框架統一維護和管理。

        雖然JdbcTemplate減少的我們訪(fǎng)問(wèn)數據庫的代碼量,不過(guò)使用也有一些問(wèn)題,比如:新增數據的時(shí)候默認無(wú)法返回生成主鍵的id,將SQL硬編碼到Java代碼中,如果SQL修改,需要重新編譯Java代碼,不利于系統的維護等。這時(shí)我們需要另外一個(gè)框架,它就是大名鼎鼎的Mybatis,下一篇我將會(huì )介紹SpringBoot如何整合Mybatis。

        項目源碼

        以上就是Spring JDBC的使用詳解的詳細內容,更多關(guān)于Spring JDBC的使用的資料請關(guān)注腳本之家其它相關(guān)文章!

        免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。

        久久精品国产自在天天线| 成人欧美一区二区三区在线观看| 欧美一区二区三区啪啪| 真实国产熟睡乱子伦视频| 中国少妇无码专区| 高清国产亚洲精品自在久久|