使用JDBC構建簡單的資料訪問層

2016-01-17    分類:JAVA開發、程式設計開發、首頁精華4人評論發表於2016-01-17

本文由碼農網 – 段生原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃

以下是如何使用JDBC構建一個資料訪問層,包括資料轉換(將從資料庫中查詢的資料封裝到對應的物件中……),資料庫的建立,以及如何連線到資料庫。

本教程的目的是使用Java編寫的分離的層去訪問資料庫中的表,這一層通常稱為資料訪問層(DAL)

使用DAL的最大好處是通過直接使用一些類似insert()和find()的方法簡化了資料庫的訪問操作,而不是總是先做連結,再執行一些查詢。

該層在其內部處理所有與資料庫相關的呼叫和查詢。

建立資料庫

我們希望為使用者創造一個簡單的表,我們可以使用這些欄位來建立

id        int
name      varchar(200)
password  varchar(200)
age       int

資料傳輸物件

這一層應該包含一個簡單的類叫做資料傳輸物件(DTO)。這個類僅僅是一個與資料庫中的表相對應的簡單對映,表中的每一列對應類的一個成員變數。

我們的目的是使用簡單的Java物件,而不是處理SQL語句和其他與資料庫相關的命令來進行資料庫的增刪改查。

我們想要把表對映成java程式碼,只需要建立包含相同欄位的類(bean)即可

為了更好地封裝,除了建構函式我們應該宣告所有欄位變數為私有,創造訪問器(getter和setter),其中有一個是預設的建構函式。

public class User {
    private Integer id;
    private String name;
    private String pass;
    private Integer age;
}

為了正確地對映欄位,我們應該考慮資料庫中的NULL值。對於Java的原始的預設值,例如int型別,其預設值是0,所以我們應該提供可容納空值的新的資料型別。我們可以通過使用特殊的型別——封裝類,如Integer來代替 INT。

最後我們的類應該像這樣:

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又或者丟擲一個執行時異常。

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);
    }
}

我們也可以在類中包含一個主方法來測試連線。完整的類像這樣:

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();
    }
}

資料訪問物件

DAO層可以做CRUD操作。它可以對我們的表進行增刪改查。

我們的DAO層介面應該像這樣:

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。

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並且為了限制只能在類內部使用,其應該是私有的:

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;
}

我們上面的方法應該修改成新的方法:

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將更有用。

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的集合將會更好:

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

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;
}

刪除方法

刪除的方法是使用一個簡單的查詢像

DELETE FROM user WHERE ID = 7

帶上id引數傳送該查詢將刪除此記錄。如果成功刪除將返回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;
}

譯文連結:http://www.codeceo.com/article/jdbc-dal.html
英文原文:Building Simple Data Access Layer Using JDBC
翻譯作者:碼農網 – 段生
轉載必須在正文中標註並保留原文連結、譯文連結和譯者等資訊。]

相關文章