电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

Spring JDBC的使用詳解

瀏覽:16日期:2023-07-16 08:01:19
JDBC介紹

從這篇文章開始,我們將會介紹SpringBoot另外一個核心的技術,即數據庫訪問技術,提到數據訪問,學習Java的同學瞬間能就想起JDBC技術,JDBC 是 Java Database Connectivity 的全稱,是Java語言中用來規范客戶端程序如何來訪問數據庫的應用程序接口,提供了諸如查詢和更新數據庫中數據的一套標準的API,這套標準不同的數據庫廠家之間共同準守,并提供各自的具體實現。如圖所示:

Spring JDBC的使用詳解

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

DriverManager

DriverManager主要負責加載不同數據庫廠家提供的驅動程序包(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中有個重要的方法 connect,來提供Connection對象

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

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

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

Connection

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

Connection對象提供了一組重載的方法來創建Statement和PreparedStatement,Statement和PreparedStatement是SQL執行的載體,另外Connection對象還會涉及事務相關的操作。

Connection對象最核心的幾個方法如下:

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

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

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

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

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

通過Statement或PreparedStatement執行SQL語句,我們引出了另外一個對象即為ResultSet對象,代碼如下:

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

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

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

JDBC訪問數據庫流程

對于開發人員而言,通過JDBC的API是Java訪問數據庫的主要途徑,下面用代碼來展示下訪問數據庫的一個整體流程:

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

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

JDBC給我們提供了DataSource接口來實現Connection的復用,核心代碼如下:

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

作為一種基礎組件,不需要開發人員自己實現 DataSource,因為業界已經存在了很多優秀的實現方案,如 DBCP、C3P0 、Druid 、Hikari等

SpringBoot默認HikariDataSource作為DataSource的實現,現在我們SpringBoot為例,看下SpringBoot如何通過JDBC來操作數據庫的,在進行數據庫操作之前,我們首先需要先配置DataSource,SpringBoot配置DataSource非常簡單,只需要在配置文件中添加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配好后,我們在本地的數據庫服務中,創建一個test數據庫,并且執行以下DDL創建user表

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

接下來我們創建一個實體類,實體類中屬性和user表中字段一一對應

@Datapublic class User { /** * 主鍵 */ private Integer id; /** * 用戶名 */ private String username; /** * 密碼 */ private String password; /** * 創建時間 */ private Date createTime;}

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

我們再定義一個UserDao接口,

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

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

接下來將通過代碼形式來展示下SpringBoot是如何通過JDBC API對數據庫進行CRUD操作的。我們來定義UserDao的具體實現類命名為:UserRawJdbcDao實現以下方法:

新增數據

@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; }查詢數據

@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通過調用原生的JDBC的API完成對user表的CRUD操作,這代碼對有代碼潔癖的同學簡直不能忍,有大量共性的代碼,如創建Connection、Statement、ResultSet、資源的釋放和異常的處理。這部分封裝和優化SpringBoot已經處理過了,SpringBoot提供了JdbcTemplate模板工具類實現數據訪問,它簡化了JDBC API的使用方法。

使用JdbcTemplate操縱數據庫

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

新增數據

@Overridepublic Integer insert(User user){ // 創建 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 實體中 if (keyHolder.getKey() != null) {user.setId(keyHolder.getKey().intValue()); } // 返回影響行數 return count;}查詢數據

@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); }小結

通過對比我們發現使用JdbcTemplate模板工具類可以大大減少JDBC訪問數據庫的代碼復雜度,作為開發人員我們應該只關心業務邏輯的具體實現過程,對JDBC底層對象的創建,資源的釋放,異常的捕獲,應該交給框架統一維護和管理。

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

項目源碼

github:github.com/dragon8844/…

以上就是Spring JDBC的使用詳解的詳細內容,更多關于Spring JDBC的使用的資料請關注好吧啦網其它相關文章!

標簽: Spring
相關文章:
主站蜘蛛池模板: 包装盒厂家_纸盒印刷_礼品盒定制-济南恒印包装有限公司 | 耐高温风管_耐高温软管_食品级软管_吸尘管_钢丝软管_卫生级软管_塑料波纹管-东莞市鑫翔宇软管有限公司 | 游泳池设备安装工程_恒温泳池设备_儿童游泳池设备厂家_游泳池水处理设备-东莞市君达泳池设备有限公司 | 无缝钢管-聊城无缝钢管-小口径无缝钢管-大口径无缝钢管 - 聊城宽达钢管有限公司 | 超细粉碎机|超微气流磨|气流分级机|粉体改性设备|超微粉碎设备-山东埃尔派粉碎机厂家 | 深圳展厅设计_企业展馆设计_展厅设计公司_数字展厅设计_深圳百艺堂 | 飞行者联盟-飞机模拟机_无人机_低空经济_航空技术交流平台 | 超声波焊接机_超音波熔接机_超声波塑焊机十大品牌_塑料超声波焊接设备厂家 | 东莞市超赞电子科技有限公司 全系列直插/贴片铝电解电容,电解电容,电容器 | 深圳宣传片制作-企业宣传视频制作-产品视频拍摄-产品动画制作-短视频拍摄制作公司 | 提升海外网站流量,增加国外网站访客UV,定制海外IP-访客王 | 捷码低代码平台 - 3D数字孪生_大数据可视化开发平台「免费体验」 | 岛津二手液相色谱仪,岛津10A液相,安捷伦二手液相,安捷伦1100液相-杭州森尼欧科学仪器有限公司 | 聚天冬氨酸,亚氨基二琥珀酸四钠,PASP,IDS - 远联化工 | 并离网逆变器_高频UPS电源定制_户用储能光伏逆变器厂家-深圳市索克新能源 | 打包箱房_集成房屋-山东佳一集成房屋有限公司 | 上海公司注册-代理记账-招投标审计-上海昆仑扇财税咨询有限公司 上海冠顶工业设备有限公司-隧道炉,烘箱,UV固化机,涂装设备,高温炉,工业机器人生产厂家 | 不锈钢管件(不锈钢弯头,不锈钢三通,不锈钢大小头),不锈钢法兰「厂家」-浙江志通管阀 | 冷藏车厂家|冷藏车价格|小型冷藏车|散装饲料车厂家|程力专用汽车股份有限公司销售十二分公司 | Maneurop/美优乐压缩机,活塞压缩机,型号规格,技术参数,尺寸图片,价格经销商 | 南京展台搭建-南京展会设计-南京展览设计公司-南京展厅展示设计-南京汇雅展览工程有限公司 | 直齿驱动-新型回转驱动和回转支承解决方案提供商-不二传动 | 温州中研白癜风专科_温州治疗白癜风_温州治疗白癜风医院哪家好_温州哪里治疗白癜风 | 知名电动蝶阀,电动球阀,气动蝶阀,气动球阀生产厂家|价格透明-【固菲阀门官网】 | 石家庄律师_石家庄刑事辩护律师_石家庄取保候审-河北万垚律师事务所 | 全自动定氮仪-半自动凯氏定氮仪厂家-祎鸿仪器 | 锂电混合机-新能源混合机-正极材料混料机-高镍,三元材料混料机-负极,包覆混合机-贝尔专业混合混料搅拌机械系统设备厂家 | 电镀整流器_微弧氧化电源_高频电解电源_微弧氧化设备厂家_深圳开瑞节能 | 公交驾校-北京公交驾校欢迎您! 工作心得_读书心得_学习心得_找心得体会范文就上学道文库 | 结晶点测定仪-润滑脂滴点测定仪-大连煜烁| 细砂提取机,隔膜板框泥浆污泥压滤机,螺旋洗砂机设备,轮式洗砂机械,机制砂,圆锥颚式反击式破碎机,振动筛,滚筒筛,喂料机- 上海重睿环保设备有限公司 | 超高频感应加热设备_高频感应电源厂家_CCD视觉检测设备_振动盘视觉检测设备_深圳雨滴科技-深圳市雨滴科技有限公司 | 广东护栏厂家-广州护栏网厂家-广东省安麦斯交通设施有限公司 | 复盛空压机配件-空气压缩机-复盛空压机(华北)总代理 | 欧美日韩国产一区二区三区不_久久久久国产精品无码不卡_亚洲欧洲美洲无码精品AV_精品一区美女视频_日韩黄色性爱一级视频_日本五十路人妻斩_国产99视频免费精品是看4_亚洲中文字幕无码一二三四区_国产小萍萍挤奶喷奶水_亚洲另类精品无码在线一区 | 上海小程序开发-上海小程序制作公司-上海网站建设-公众号开发运营-软件外包公司-咏熠科技 | elisa试剂盒-PCR试剂盒「上海谷研实业有限公司」| 大型多片锯,圆木多片锯,方木多片锯,板材多片锯-祥富机械有限公司 | 美国HASKEL增压泵-伊莱科elettrotec流量开关-上海方未机械设备有限公司 | 订做不锈钢_不锈钢定做加工厂_不锈钢非标定制-重庆侨峰金属加工厂 | 粉末冶金注射成型厂家|MIM厂家|粉末冶金齿轮|MIM零件-深圳市新泰兴精密科技 |