java 使用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; }
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!