首页 > php教程 > php手册 > 使用JDBC构建简单的数据访问层

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

WBOY
发布: 2016-06-01 09:46:43
原创
1400 人浏览过

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

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

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

 

创建数据库

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

<code class="language-html">id        int
name      varchar(200)
password  varchar(200)
age       int</code>
登录后复制

 

数据传输对象

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

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

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

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

<code class="language-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="language-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="language-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="language-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="language-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="language-sql">SELECT * FROM user WHERE id=7</code>
登录后复制

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

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

<code class="language-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="language-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="language-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="language-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="language-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="language-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="language-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="language-sql">DELETE FROM user WHERE ID = 7</code>
登录后复制

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

<code class="language-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>
登录后复制

 

相关标签:
来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门推荐
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板