java 使用JDBC構(gòu)建簡單的數(shù)據(jù)訪問層實(shí)例詳解
本教程的目的是使用Java編寫的分離的層去訪問數(shù)據(jù)庫中的表,這一層通常稱為數(shù)據(jù)訪問層(DAL)
使用DAL的最大好處是通過直接使用一些類似insert()和find()的方法簡化了數(shù)據(jù)庫的訪問操作,而不是總是先做鏈接,再執(zhí)行一些查詢。
該層在其內(nèi)部處理所有與數(shù)據(jù)庫相關(guān)的調(diào)用和查詢。
創(chuàng)建數(shù)據(jù)庫
我們希望為用戶創(chuàng)造一個(gè)簡單的表,我們可以使用這些字段來創(chuàng)建
id int
name varchar(200)
password varchar(200)
age int
數(shù)據(jù)傳輸對象
這一層應(yīng)該包含一個(gè)簡單的類叫做數(shù)據(jù)傳輸對象(DTO)。這個(gè)類僅僅是一個(gè)與數(shù)據(jù)庫中的表相對應(yīng)的簡單映射,表中的每一列對應(yīng)類的一個(gè)成員變量。
我們的目的是使用簡單的Java對象,而不是處理SQL語句和其他與數(shù)據(jù)庫相關(guān)的命令來進(jìn)行數(shù)據(jù)庫的增刪改查。
我們想要把表映射成java代碼,只需要?jiǎng)?chuàng)建包含相同字段的類(bean)即可
為了更好地封裝,除了構(gòu)造函數(shù)我們應(yīng)該聲明所有字段變量為私有,創(chuàng)造訪問器(getter和setter),其中有一個(gè)是默認(rèn)的構(gòu)造函數(shù)。
public class User { private Integer id; private String name; private String pass; private Integer age; }
為了正確地映射字段,我們應(yīng)該考慮數(shù)據(jù)庫中的NULL值。對于Java的原始的默認(rèn)值,例如int類型,其默認(rèn)值是0,所以我們應(yīng)該提供可容納空值的新的數(shù)據(jù)類型。我們可以通過使用特殊的類型——封裝類,如Integer來代替 INT。
最后我們的類應(yīng)該像這樣:
public class User { private Integer id; private String name; private String pass; private Integer age; public User() { } public User(String name, String pass, Integer age) { this.name = name; this.pass = pass; this.age = age; } public User(Integer id, String name, String pass, Integer age) { this.id = id; this.name = name; this.pass = pass; this.age = age; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } 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 getPass() { return pass; } public void setPass(String pass) { this.pass = pass; } }
一個(gè)好的做法是,提供默認(rèn)的空構(gòu)造函數(shù),一個(gè)完整的構(gòu)造函數(shù)和一個(gè)沒有id參數(shù)的完整構(gòu)造函數(shù)。
連接數(shù)據(jù)庫
我們可以使用一個(gè)中間類來方便連接到數(shù)據(jù)庫,在這個(gè)類中,我們將提供數(shù)據(jù)庫的連接參數(shù)如數(shù)據(jù)庫JDBC, URL,用戶名和密碼,并將這些變量定義成final的(從properties 或者 xml配置文件中獲取這些數(shù)據(jù)將會(huì)更好)
提供一個(gè)方法返回一個(gè)Connection對象或者當(dāng)連接失敗時(shí)返回一個(gè)null又或者拋出一個(gè)運(yùn)行時(shí)異常。
public static final String URL = "jdbc:mysql://localhost:3306/testdb"; public static final String USER = "testuser"; public static final String PASS = "testpass"; /** * 獲取connection對象 * @return Connection 對象 */ public static Connection getConnection() { try { DriverManager.registerDriver(new Driver()); return DriverManager.getConnection(URL, USER, PASS); } catch (SQLException ex) { throw new RuntimeException("Error connecting to the database", ex); } }
我們也可以在類中包含一個(gè)主方法來測試連接。完整的類像這樣:
import com.mysql.jdbc.Driver; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; /** * Connect to Database * @author hany.said */ public class ConnectionFactory { public static final String URL = "jdbc:mysql://localhost:3306/testdb"; public static final String USER = "testuser"; public static final String PASS = "testpass"; /** * Get a connection to database * @return Connection object */ public static Connection getConnection() { try { DriverManager.registerDriver(new Driver()); return DriverManager.getConnection(URL, USER, PASS); } catch (SQLException ex) { throw new RuntimeException("Error connecting to the database", ex); } } /** * Test Connection */ public static void main(String[] args) { Connection connection = connectionFactory.getConnection(); } }
數(shù)據(jù)訪問對象
DAO層可以做CRUD操作。它可以對我們的表進(jìn)行增刪改查。
我們的DAO層接口應(yīng)該像這樣:
public interface UserDao { User getUser(); Set<User> getAllUsers(); User getUserByUserNameAndPassword(); boolean insertUser(); boolean updateUser(); boolean deleteUser(); }
查找用戶
用戶可以通過像ID,姓名或郵箱等任何唯一字段來查詢。在這個(gè)例子中,我們使用ID來查找用戶。第一步是通過連接器類來創(chuàng)建一個(gè)connection,然后執(zhí)行SELECT語句以獲得其ID為7的用戶,我們可以使用這條語句查詢用戶:
SELECT * FROM user WHERE id=7
就在這里,我們做了一個(gè)動(dòng)態(tài)的語句來從參數(shù)中獲取ID。
通過執(zhí)行這個(gè)查詢,得到一個(gè)結(jié)果集,其中保存有用戶或null。我們可以通過Resultset的next()方法來檢測是否有值。如果返回true,我們將繼續(xù)利用data getters從ResultSet中獲取用戶數(shù)據(jù)。當(dāng)我們將所有的數(shù)據(jù)封裝到user中后,我們返回它。如果不存在此ID的用戶或其他任何異常發(fā)生(如無效的SQL語句)這個(gè)方法會(huì)返回null。
public User getUser(int id) { Connection connection = connectionFactory.getConnection(); try { Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM user WHERE id=" + id); if(rs.next()) { User user = new User(); user.setId( rs.getInt("id") ); user.setName( rs.getString("name") ); user.setPass( rs.getString("pass") ); user.setAge( rs.getInt("age") ); return user; } } catch (SQLException ex) { ex.printStackTrace(); } return null; }
使用單獨(dú)的方法來從結(jié)果集中提取數(shù)據(jù)將會(huì)更方便,因?yàn)樵诤芏喾椒ㄖ形覀儗?huì)調(diào)用它。
這個(gè)新方法將拋出SQLException并且為了限制只能在類內(nèi)部使用,其應(yīng)該是私有的:
private User extractUserFromResultSet(ResultSet rs) throws SQLException { User user = new User(); user.setId( rs.getInt("id") ); user.setName( rs.getString("name") ); user.setPass( rs.getString("pass") ); user.setAge( rs.getInt("age") ); return user; }
我們上面的方法應(yīng)該修改成新的方法:
public User getUser(int id) { Connection connection = connectionFactory.getConnection(); try { Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM user WHERE id=" + id); if(rs.next()) { return extractUserFromResultSet(rs); } } catch (SQLException ex) { ex.printStackTrace(); } return null; }
登陸方法
登陸操作類似。我們希望提供用戶和密碼替代ID,這將不會(huì)影響參數(shù)列表和查詢語句。如果用戶名和密碼是正確的,這個(gè)方法會(huì)返回一個(gè)有效的用戶,否則為null。因?yàn)橛泻芏嗟膮?shù),使用PreparedStatement將更有用。
public User getUserByUserNameAndPassword(String user, String pass) { Connector connector = new Connector(); Connection connection = connector.getConnection(); try { PreparedStatement ps = connection.prepareStatement("SELECT * FROM user WHERE user=? AND pass=?"); ps.setString(1, user); ps.setString(2, pass); ResultSet rs = ps.executeQuery(); if(rs.next()) { return extractUserFromResultSet(rs); } } catch (SQLException ex) { ex.printStackTrace(); } return null; }
查詢所有用戶的方法
這個(gè)方法將會(huì)返回所有的用戶,所以我們應(yīng)該將它們存在一個(gè)類似數(shù)組的容器中返回來。但是,因?yàn)槲覀儾恢烙卸嗌贄l記錄。 使用例如Set或者List的集合將會(huì)更好:
public Set getAllUsers() { Connector connector = new Connector(); Connection connection = connector.getConnection(); try { Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM user"); Set users = new HashSet(); while(rs.next()) { User user = extractUserFromResultSet(rs); users.add(user); } return users; } catch (SQLException ex) { ex.printStackTrace(); } return null; }
插入方法
Insert方法將采取用戶作為參數(shù),并使用PreparedStatement對象來執(zhí)行SQL update語句。executeUpdate 方法返回受影響的行數(shù)。如果我們添加單行,意味著該方法應(yīng)該返回1,如果是這樣,我們返回true,否則,我們返回false
public boolean insertUser(User user) { Connector connector = new Connector(); Connection connection = connector.getConnection(); try { PreparedStatement ps = connection.prepareStatement("INSERT INTO user VALUES (NULL, ?, ?, ?)"); ps.setString(1, user.getName()); ps.setString(2, user.getPass()); ps.setInt(3, user.getAge()); int i = ps.executeUpdate(); if(i == 1) { return true; } } catch (SQLException ex) { ex.printStackTrace(); } return false; }
更新方法
更新方法和插入方法類似。唯一變化的是SQL語句
public boolean updateUser(User user) { Connector connector = new Connector(); Connection connection = connector.getConnection(); try { PreparedStatement ps = connection.prepareStatement("UPDATE user SET name=?, pass=?, age=? WHERE id=?"); ps.setString(1, user.getName()); ps.setString(2, user.getPass()); ps.setInt(3, user.getAge()); ps.setInt(4, user.getId()); int i = ps.executeUpdate(); if(i == 1) { return true; } } catch (SQLException ex) { ex.printStackTrace(); } return false; }
刪除方法
刪除的方法是使用一個(gè)簡單的查詢像
DELETE FROM user WHERE ID = 7
帶上id參數(shù)發(fā)送該查詢將刪除此記錄。如果成功刪除將返回1
public boolean deleteUser(int id) { Connector connector = new Connector(); Connection connection = connector.getConnection(); try { Statement stmt = connection.createStatement(); int i = stmt.executeUpdate("DELETE FROM user WHERE id=" + id); if(i == 1) { return true; } } catch (SQLException ex) { ex.printStackTrace(); } return false; }
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
- 使用JDBC從數(shù)據(jù)庫中查詢數(shù)據(jù)的方法
- java jdbc連接mysql數(shù)據(jù)庫實(shí)現(xiàn)增刪改查操作
- jdbc鏈接遠(yuǎn)程數(shù)據(jù)庫進(jìn)行修改url操作
- java實(shí)現(xiàn)jdbc批量插入數(shù)據(jù)
- JDBC鏈接mysql插入數(shù)據(jù)后顯示問號(hào)的原因及解決辦法
- JSP使用JDBC連接MYSQL數(shù)據(jù)庫的方法
- Java編程中使用JDBC API連接數(shù)據(jù)庫和創(chuàng)建程序的方法
- 在Java的Spring框架的程序中使用JDBC API操作數(shù)據(jù)庫
- JDBC程序更新數(shù)據(jù)庫中記錄的方法
- Java中使用JDBC操作數(shù)據(jù)庫簡單實(shí)例
- JSP中使用JDBC訪問SQL Server 2008數(shù)據(jù)庫示例
- Java使用JDBC連接數(shù)據(jù)庫的實(shí)現(xiàn)方法
相關(guān)文章
SpringCloud?Nacos服務(wù)分級(jí)存儲(chǔ)模型詳解
Nacos服務(wù)分級(jí)存儲(chǔ)模型是Nacos存儲(chǔ)服務(wù)注冊信息和配置信息的核心模型之一,本文將對?Nacos?服務(wù)分級(jí)存儲(chǔ)模型進(jìn)行深入解析,感興趣的朋友一起看看吧2024-02-02加速spring/springboot應(yīng)用啟動(dòng)速度詳解
這篇文章主要介紹了加速spring/springboot應(yīng)用啟動(dòng)速度詳解,本文通過實(shí)例代碼給大家介紹的非常詳細(xì)對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07Intellij IDEA 2018配置Java運(yùn)行環(huán)境的方法步驟
這篇文章主要介紹了Intellij IDEA 2018配置Java運(yùn)行環(huán)境的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09mybatis自動(dòng)建表的實(shí)現(xiàn)方法
這篇文章主要介紹了mybatis自動(dòng)建表的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11springboot+element-ui實(shí)現(xiàn)多文件一次上傳功能
這篇文章主要介紹了springboot+element-ui多文件一次上傳功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06詳解Java多態(tài)對象的類型轉(zhuǎn)換與動(dòng)態(tài)綁定
這篇文章主要介紹了詳解Java多態(tài)對象的類型轉(zhuǎn)換與動(dòng)態(tài)綁定,是Java入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-09-09Maven依賴管理之parent與dependencyManagement深入分析
首先我們來說說parent標(biāo)簽,其實(shí)這個(gè)不難解釋,就是父的意思,pom也有繼承的。比方說我現(xiàn)在有A,B,C,A是B,C的父級(jí)?,F(xiàn)在就是有一個(gè)情況B,C其實(shí)有很多jar都是共同的,其實(shí)是可以放在父項(xiàng)目里面,這樣,讓B,C都繼承A就方便管理了2022-10-10