目錄
创建数据库
数据传输对象
连接数据库
数据访问对象
查找用户
登陆方法
查询所有用户的方法
插入方法
更新方法
删除方法
首頁 php教程 php手册 使用JDBC构建简单的数据访问层

使用JDBC构建简单的数据访问层

Jun 01, 2016 am 09:46 AM
java jdbc

本教程的目的是使用Java编写的分离的层去访问数据库中的表,这一层通常称为数据访问层(DAL)

使用DAL的最大好处是通过直接使用一些类似insert()和find()的方法简化了数据库的访问操作,而不是总是先做链接,再执行一些查询。

该层在其内部处理所有与数据库相关的调用和查询。

 

创建数据库

我们希望为用户创造一个简单的表,我们可以使用这些字段来创建

<code class="html">id        int
name      varchar(200)
password  varchar(200)
age       int</code>
登入後複製

 

数据传输对象

这一层应该包含一个简单的类叫做数据传输对象(DTO)。这个类仅仅是一个与数据库中的表相对应的简单映射,表中的每一列对应类的一个成员变量。

我们的目的是使用简单的Java对象,而不是处理SQL语句和其他与数据库相关的命令来进行数据库的增删改查。

我们想要把表映射成java代码,只需要创建包含相同字段的类(bean)即可

为了更好地封装,除了构造函数我们应该声明所有字段变量为私有,创造访问器(getter和setter),其中有一个是默认的构造函数。

<code class="java">public class User {
    private Integer id;
    private String name;
    private String pass;
    private Integer age;
}</code>
登入後複製

为了正确地映射字段,我们应该考虑数据库中的NULL值。对于Java的原始的默认值,例如int类型,其默认值是0,所以我们应该提供可容纳空值的新的数据类型。我们可以通过使用特殊的类型——封装类,如Integer来代替 INT。

最后我们的类应该像这样:

<code class="java">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;
    }
}</code>
登入後複製

一个好的做法是,提供默认的空构造函数,一个完整的构造函数和一个没有id参数的完整构造函数。

 

连接数据库

我们可以使用一个中间类来方便连接到数据库,在这个类中,我们将提供数据库的连接参数如数据库JDBC, URL,用户名和密码,并将这些变量定义成final的(从properties 或者 xml配置文件中获取这些数据将会更好)

提供一个方法返回一个Connection对象或者当连接失败时返回一个null又或者抛出一个运行时异常。

<code class="java">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);
    }
}</code>
登入後複製

我们也可以在类中包含一个主方法来测试连接。完整的类像这样:

<code class="java">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();
    }
}</code>
登入後複製

 

数据访问对象

DAO层可以做CRUD操作。它可以对我们的表进行增删改查。

我们的DAO层接口应该像这样:

<code class="java">public interface UserDao {
    User getUser();
    Set<user> getAllUsers();
    User getUserByUserNameAndPassword();
    boolean insertUser();
    boolean updateUser();
    boolean deleteUser();
}</user></code>
登入後複製

 

查找用户

用户可以通过像ID,姓名或邮箱等任何唯一字段来查询。在这个例子中,我们使用ID来查找用户。第一步是通过连接器类来创建一个connection,然后执行SELECT语句以获得其ID为7的用户,我们可以使用这条语句查询用户:

<code class="sql">SELECT * FROM user WHERE id=7</code>
登入後複製

就在这里,我们做了一个动态的语句来从参数中获取ID。

通过执行这个查询,得到一个结果集,其中保存有用户或null。我们可以通过Resultset的next()方法来检测是否有值。如果返回true,我们将继续利用data getters从ResultSet中获取用户数据。当我们将所有的数据封装到user中后,我们返回它。如果不存在此ID的用户或其他任何异常发生(如无效的SQL语句)这个方法会返回null。

<code class="java">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;
}</code>
登入後複製

使用单独的方法来从结果集中提取数据将会更方便,因为在很多方法中我们将会调用它。

这个新方法将抛出SQLException并且为了限制只能在类内部使用,其应该是私有的:

<code class="java">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;
}</code>
登入後複製

我们上面的方法应该修改成新的方法:

<code class="java">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;
}</code>
登入後複製

 

登陆方法

登陆操作类似。我们希望提供用户和密码替代ID,这将不会影响参数列表和查询语句。如果用户名和密码是正确的,这个方法会返回一个有效的用户,否则为null。因为有很多的参数,使用PreparedStatement将更有用。

<code class="java">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;
}</code>
登入後複製

 

查询所有用户的方法

这个方法将会返回所有的用户,所以我们应该将它们存在一个类似数组的容器中返回来。但是,因为我们不知道有多少条记录。 使用例如Set或者List的集合将会更好:

<code class="java">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;
}</code>
登入後複製

 

插入方法

Insert方法将采取用户作为参数,并使用PreparedStatement对象来执行SQL update语句。executeUpdate 方法返回受影响的行数。如果我们添加单行,意味着该方法应该返回1,如果是这样,我们返回true,否则,我们返回false

<code class="java">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;
}</code>
登入後複製

 

更新方法

更新方法和插入方法类似。唯一变化的是SQL语句

<code class="java">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;
}</code>
登入後複製

 

删除方法

删除的方法是使用一个简单的查询像

<code class="sql">DELETE FROM user WHERE ID = 7</code>
登入後複製

带上id参数发送该查询将删除此记录。如果成功删除将返回1

<code class="java">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;
}</code>
登入後複製

 

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Java 中的平方根 Java 中的平方根 Aug 30, 2024 pm 04:26 PM

Java 中的平方根指南。下面我們分別透過例子和程式碼實作來討論平方根在Java中的工作原理。

Java 中的完美數 Java 中的完美數 Aug 30, 2024 pm 04:28 PM

Java 完美數指南。這裡我們討論定義,如何在 Java 中檢查完美數?

Java 中的隨機數產生器 Java 中的隨機數產生器 Aug 30, 2024 pm 04:27 PM

Java 隨機數產生器指南。在這裡,我們透過範例討論 Java 中的函數,並透過範例討論兩個不同的生成器。

Java中的Weka Java中的Weka Aug 30, 2024 pm 04:28 PM

Java 版 Weka 指南。這裡我們透過範例討論簡介、如何使用 weka java、平台類型和優點。

Java 中的史密斯數 Java 中的史密斯數 Aug 30, 2024 pm 04:28 PM

Java 史密斯數指南。這裡我們討論定義,如何在Java中檢查史密斯號?帶有程式碼實現的範例。

Java Spring 面試題 Java Spring 面試題 Aug 30, 2024 pm 04:29 PM

在本文中,我們保留了最常被問到的 Java Spring 面試問題及其詳細答案。這樣你就可以順利通過面試。

突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

Java 中的時間戳至今 Java 中的時間戳至今 Aug 30, 2024 pm 04:28 PM

Java 中的時間戳記到日期指南。這裡我們也結合範例討論了介紹以及如何在java中將時間戳記轉換為日期。

See all articles