本教程的目的是使用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.manongjc.com/article/449.html

参考阅读:

  • Java GC专家系列2:Java 垃圾回收的监控
  • Java GC专家系列1:理解Java垃圾回收
  • 构建一个基于 Spring 的 RESTful Web Service
  • 使用JDBC构建简单的数据访问层的更多相关文章

    1. 同时支持EF+Dapper的混合仓储,助你快速搭建数据访问层

      背景 17年开始,公司开始向DotNet Core转型,面对ORM工具的选型,当时围绕Dapper和EF发生了激烈的讨论.项目团队更加关注快速交付,他们主张使用EF这种能快速开发的ORM工具:而在线业 ...

    2. 数据访问层DAL(数据库访问抽象类DataProvider)

      晒晒数据访问层DAL,看看你的项目数据访问层使用的是什么形式,数据访问性能比较 采用什么样的数据访问形式是软件编码很重要的一个环节,良好的数据访问形式不仅能够提搞代码的执行效率,协作能力,更重要的是对 ...

    3. 项目架构开发:数据访问层之Cache

      数据访问层简单介绍 数据访问层,提供整个项目的数据访问与持久化功能.在分层系统中所有有关数据访问.检索.持久化的任务,最终都将在这一层完成. 来看一个比较经典的数据访问层结构图 大概可以看出如下信息 ...

    4. 【Hades】ades是一个开源库,基于JPA和Spring构建,通过减少开发工作量显著的改进了数据访问层的实现

      几乎每个应用系统都需要通过访问数据来完成工作.要想使用领域设计方法,你就需要为实体类定义和构建资源库来实现领域对象的持久化.目前开发人员经常使用JPA来实现持久化库.JPA让持久化变得非常容易,但是仍 ...

    5. 1.1 DAL数据访问层

      分布式(Distributed)数据访问层(Data Access Layer),简称DAL,是利用MySQL Proxy.Memcached.集群等技术优点而构建的一个架构系统.主要目的是解决高并发 ...

    6. NHibernate:教你如何搭建数据访问层?

      NHibernate:教你如何搭建数据访问层? 什么是NHibernate NHibernate 是一个基于.net 的针对关系型数据库的对象持久化类库.NHibernate 来源于非常优秀的基于Ja ...

    7. 【原创】打造基于Dapper的数据访问层

      [原创]打造基于Dapper的数据访问层   前言 闲来无事,花几天功夫将之前项目里用到的一个数据访问层整理了出来.实现单个实体的增删改查,可执行存储过程,可输出返回参数,查询结果集可根据实际情况返回 ...

    8. ClownFish:比手写代码还快的通用数据访问层

      http://www.cnblogs.com/fish-li/archive/2012/07/17/ClownFish.html 阅读目录 开始 ClownFish是什么? 比手写代码还快的执行速度 ...

    9. 项目架构开发:数据访问层之Logger

      接上文 项目架构开发:数据访问层之Cache 本章我们继续ILogger的开发 ILogger.cs public interface ILogger { void Info(object messa ...

    随机推荐

    1. linux下安装svn

      linux下SVN服务器如何搭建和使用 | 浏览:12117 | 更新:2013-09-18 14:28 | 标签:linux linux下SVN服务器如何搭建和使用?说到SVN服务器,想必大家都知道 ...

    2. android学习笔记40——国际化和资源自适应

      国际化——Internationalization,简称I18N. 本地化——Localization,检查L10N. java国际化资源的思路: java提供国际化资源的思路,是将程序中的标签.提示 ...

    3. TX Textcontrol 使用总结三——禁用右键、模版合并

      一.Tx Textcontrol如何禁用右键快捷菜单? ==> 添加txContent_TextContextMenuOpening事件,实现方式如下所示: private void txCon ...

    4. 战胜忧虑<5>——运用亚里士多德法则

      运用亚里士多德法则 如果人们将忧虑的时间,用来寻找解决问题的答案,那忧虑就会在人们智慧的光芒下消失.那么当你面对忧虑时,应该怎么办理?答案是,我们一定要学会用下面三种分析问题的基本步骤来解决各种不同的 ...

    5. apidoc,一个相当不错的文档生成器

      http://apidocjs.com/ 例子:myapp目录下的MyCode.java /** * * @api {get} /company/list 获取公司信息 * @apiName 获取公司 ...

    6. jQuery-webcam(.NET)实现WEB摄像头监控

      jQuery-webcam是一个非常好用的摄像头监控工具,DEMO可官方下载地址http://www.xarg.org/project/jquery-webcam-plugin/ 1.下载解压后,jq ...

    7. html元素背景样式大小调整

      定义元素背景设置 background-size属性cover自适应填充背景,background-size: 100% 100%; background-size: 左右比例  上下比例: 再介绍几 ...

    8. int long long范围

      unsigned   int   0-4294967295   int   2147483648-2147483647 unsigned long 0-4294967295long   2147483 ...

    9. JavaScript事件基础知识总结【思维导图】

      另外附上来自Nicholas C.Zakas<JavaScript高级程序设计 第3版>中的跨浏览器兼容EventUtil对象. var EventUtil = { //注册事件 addH ...

    10. 【JavaScript】创建命名空间,Class,LOG

      JxUnderscore(function (J, _, root) { var isWindow, deepObject, Namespace, Class, LOG; /** * 一个对象是否为w ...