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


本教程的目的是从用Java编写的单独层(通常称为数据访问层(DAL))管理数据库中表的访问。

DAL的最大好处是,它通过诸如insert()和find()之类的某些方法调用简化了数据库访问操作,而不是进行连接并执行一些查询

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

Database Creation 我们想为用户创建一个简单的表,我们可以使用这些字段来创建它

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

Data Transfer Object 该层应包含一个称为数据传输对象(DTO)的简单类,该对象只是到表的简单映射,表中的每一列都是该类中的成员变量。

我们的目标是命令该层使用简单的Java对象创建,修改,删除或搜索实体,而不是处理SQL语句和其他与数据库相关的命令。

我们想将此表映射到我们的Java代码,我们可以通过创建一个包含相同字段的简单类(bean)来实现。

为了使它更加封装,我们应该将所有字段变量声明为private,并除了构造函数外还创建acessor(Setters和Getters),其中之一是默认构造函数。

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

为了正确地映射字段,我们应该考虑数据库中的NULL值。Java基本类型的默认值在int的情况下是一个类似于0的值,因此我们应该提供一个可以容纳null值的新数据类型。我们可以通过使用特殊类型的对象(如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参数的完整的构造函数。

Connecting to Database 我们可以通过在该类中创建一个用于连接数据库的中央类来简化连接数据库的工作, 我们将提供连接参数(如数据库JDBC URL,用户名和密码)作为最终变量(最好从属性或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";
​
/**
 * 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);
    }
}

我们还可以包括一个main方法来测试整个类的连接:

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

Data Access Object 该DAO可以执行CRUD操作,它可以从表中创建,检索,更新数据,删除。

我们的DAO的界面应如下所示:

public interface UserDao {
    User getUser();
    Set<User> getAllUsers();
    User getUserByUserNameAndPassword();
    boolean insertUser();
    boolean updateUser();
    boolean deleteUser();
}

Retreive User 可以通过任何唯一字段(例如id或name或mail)来吸引用户。在这种方法中,我们通过用户ID搜索用户。第一步是从连接器类创建连接,然后执行select语句以获取ID为7的用户,我们可以使用以下语句进行查询:

SELECT * FROM user WHERE id=7

刚才我们做了一个动态语句,它从方法参数中获取id

通过执行此查询,我们得到一个保存用户或null的结果集,我们可以使用Resultset中的next()方法进行检查。如果返回true,我们将继续使用数据获取器从结果集中获取用户数据。在向用户填充所有数据之后,我们将返回它。如果没有用户使用此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;
}

Login Method 登录将类似。我们想为用户提供id的ans传递实例,这会影响参数列表和查询语句。如果用户名和密码正确,此方法将返回有效用户,否则返回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;
}

Select All Method 此方法将返回所有用户,因此我们应该在方便的容器(如数组)中将其返回,但是由于我们无法期望返回的行数而已。最好使用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 Method insert方法将用户作为参数,并使用PreparedStatement对象执行SQL更新语句。 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;
}

update method update方法类似于插入方法,唯一的变化是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 method delete方法将使用一个简单的查询,例如 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;
}


原文链接:https://codingdict.com/