本教程的目的是使用Java編寫的分離的層去訪問數據庫中的表,這一層通常稱為數據訪問層(DAL)
使用DAL的最大好處是通過直接使用一些類似insert()和find()的方法簡化了數據庫的訪問操作,而不是總是先做鏈接,再執行一些查詢。
該層在其內部處理所有與數據庫相關的調用和查詢。
創建數據庫
我們希望為用戶創造一個簡單的表,我們可以使用這些字段來創建
id int
name varchar(200)
password varchar(200)
age int
數據傳輸對象
這一層應該包含一個簡單的類叫做數據傳輸對象(DTO)。這個類僅僅是一個與數據庫中的表相對應的簡單映射,表中的每一列對應類的一個成員變量。
我們的目的是使用簡單的Java對象,而不是處理SQL語句和其他與數據庫相關的命令來進行數據庫的增刪改查。
我們想要把表映射成java代碼,只需要創建包含相同字段的類(bean)即可
為了更好地封裝,除了構造函數我們應該聲明所有字段變量為私有,創造訪問器(getter和setter),其中有一個是默認的構造函數。
1
2
3
4
5
6
|
public class User { private Integer id; private String name; private String pass; private Integer age; } |
為了正確地映射字段,我們應該考慮數據庫中的NULL值。對于Java的原始的默認值,例如int類型,其默認值是0,所以我們應該提供可容納空值的新的數據類型。我們可以通過使用特殊的類型——封裝類,如Integer來代替 INT。
最后我們的類應該像這樣:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
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; } } |
一個好的做法是,提供默認的空構造函數,一個完整的構造函數和一個沒有id參數的完整構造函數。
連接數據庫
我們可以使用一個中間類來方便連接到數據庫,在這個類中,我們將提供數據庫的連接參數如數據庫JDBC, URL,用戶名和密碼,并將這些變量定義成final的(從properties 或者 xml配置文件中獲取這些數據將會更好)
提供一個方法返回一個Connection對象或者當連接失敗時返回一個null又或者拋出一個運行時異常。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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); } } |
我們也可以在類中包含一個主方法來測試連接。完整的類像這樣:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
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 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(); } } |
數據訪問對象
DAO層可以做CRUD操作。它可以對我們的表進行增刪改查。
我們的DAO層接口應該像這樣:
1
2
3
4
5
6
7
8
|
public interface UserDao { User getUser(); Set<User> getAllUsers(); User getUserByUserNameAndPassword(); boolean insertUser(); boolean updateUser(); boolean deleteUser(); } |
查找用戶
用戶可以通過像ID,姓名或郵箱等任何唯一字段來查詢。在這個例子中,我們使用ID來查找用戶。第一步是通過連接器類來創建一個connection,然后執行SELECT語句以獲得其ID為7的用戶,我們可以使用這條語句查詢用戶:
SELECT * FROM user WHERE id=7
就在這里,我們做了一個動態的語句來從參數中獲取ID。
通過執行這個查詢,得到一個結果集,其中保存有用戶或null。我們可以通過Resultset的next()方法來檢測是否有值。如果返回true,我們將繼續利用data getters從ResultSet中獲取用戶數據。當我們將所有的數據封裝到user中后,我們返回它。如果不存在此ID的用戶或其他任何異常發生(如無效的SQL語句)這個方法會返回null。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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 ; } |
使用單獨的方法來從結果集中提取數據將會更方便,因為在很多方法中我們將會調用它。
這個新方法將拋出SQLException并且為了限制只能在類內部使用,其應該是私有的:
1
2
3
4
5
6
7
8
|
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; } |
我們上面的方法應該修改成新的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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,這將不會影響參數列表和查詢語句。如果用戶名和密碼是正確的,這個方法會返回一個有效的用戶,否則為null。因為有很多的參數,使用PreparedStatement將更有用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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 ; } |
查詢所有用戶的方法
這個方法將會返回所有的用戶,所以我們應該將它們存在一個類似數組的容器中返回來。但是,因為我們不知道有多少條記錄。 使用例如Set或者List的集合將會更好:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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方法將采取用戶作為參數,并使用PreparedStatement對象來執行SQL update語句。executeUpdate 方法返回受影響的行數。如果我們添加單行,意味著該方法應該返回1,如果是這樣,我們返回true,否則,我們返回false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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語句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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 ; } |
刪除方法
刪除的方法是使用一個簡單的查詢像
DELETE FROM user WHERE ID = 7
帶上id參數發送該查詢將刪除此記錄。如果成功刪除將返回1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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 ; } |
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!