JDBC项目实践
这几天学习了JDBC的接口,从简单的连接,到不断地对JDBC的代码进行优化,最后到实体类,DAO类的设计,现在对这几天所学做一个总结:
首先是软件的系统组成:
数据库中有很多的表:Customer,Department,Order,Account等等,为了访问每个表,在java中建立相关的DAO,这些DAO构成数据访问层。java通过调用DAO,达到访问数据库的目的
下面是工程的创建步骤:
1:导入工具包以及配置文件
1.1:导入访问JDBC的驱动包:commons-dbcp2-2.1.1.jar,commons-logging-1.2.jar,commons-pool2-2.42.jar,ojdbc6.jar并对不同的包buildpath;
1.2: 创建Utils包,导入工具类DBUtils.java和配置文件db.properties,这两个工具类是JDBC的核心包,里面有连接数据库,断开连接的方法
DBUTils.java的源代码:
package utils; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; import org.apache.commons.dbcp2.BasicDataSource; public class DBUtils { private static String driver = null; private static String url = null; private static String user = null; private static String password = null; private static BasicDataSource ds = null; //静态块 static{ Properties props = new Properties(); try { //路径使用包路径 String path = "utils/db.properties"; props.load( DBUtils.class.getClassLoader() .getResourceAsStream(path)); driver = props.getProperty("driver"); url = props.getProperty("url"); user = props.getProperty("user"); password = props.getProperty("password"); //ds中已经有了几个创建好的连接 ds = new BasicDataSource();//创建连接池 ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(user); ds.setPassword(password); ds.setInitialSize( Integer.parseInt(props.getProperty("intialSize"))); } catch (Exception e) { e.printStackTrace(); } } /*创建连接*/ public static Connection getConnection() throws ClassNotFoundException, SQLException{ Connection conn = null; if(ds!=null){ conn = ds.getConnection(); } return conn; } /*关闭连接*/ public static void closeConnection(Connection conn) throws SQLException{ if(conn!=null) conn.close(); } } View Code
读取的配置文件db.properties,里面放了Oracle的驱动,url,用户user密码 格式是key = value
db.properties的源代码:
#key = value driver = oracle.jdbc.OracleDriver url = jdbc:oracle:thin:@localhost:1521:xe user = fengweijie password= 1070937053 #driver = com.mysql.jdbc.Driver #url = jdbc:mysql:localhost:3306/test?useUni intialSize = 10 View Code
完成之后项目截图:
2:创建实体包entity:里面存放的是数据库里面的表,例如部门表Dept,员工表Emp,根据表的数据类型创建Dept.java和Emp.java,并在Dept.java和Emp.java中添加get(),set()方法,以及tostring()方法;完成之后项目如图;
3:创建iDAO包:里面存放的是访问数据库的接口,以员工表和部门表为例,对应的是IEmp.java,Idept.java
4:创建DAO包:里面是实现IDAO的数据访问层,对应EmpDAO.java,Dept.java,用来实现访问数据库中对用的表
由于2,3,4步骤是体力活,所以一步到位,项目截图如图所示:
下面概述一下项目框架中的技巧:
由于在DAO中,每一个方法都需要获得连接数据库,以find函数为例,实现部门表的查找,每次都需要进行连接,查询,关闭,代码如下:
public void find(){ Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = DBUtils.getConnection(); //事务开始 conn.setAutoCommit(false); //业务逻辑 conn.commit(); } catch (Exception e) { try { conn.rollback(); } catch (SQLException sqkex) { // TODO Auto-generated catch block sqkex.printStackTrace(); } e.printStackTrace(); }finally { try { conn.setAutoCommit(true); if(conn !=null) conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
不同函数之间,例如按照部门编号查找,按照部门所处位置查找,等等,只是代码中的业务逻辑不同,其他的部分一致,而除了部门表以外,其他比如员工表也需要进行查询,也是业务逻辑不同,为了解决这个问题,需要写一个总的find方法,放在BaseDAO中
BaseDAO的源代码:
package DAO; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import utils.DBUtils; public abstract class BaseDAO<T> { /* * 所有find方法的三大差别 * 1:SQL语句不通 * 2:?参数有几个不确定,类型不确定 * 解决方法:类型不确定用:用object接住 * 个数不确定用数组解决 * Object[] params能接住所有的 * 3:返回值对象不确定,解决 泛型类 */ protected List<T> find(String sql,Object[] params)throws Exception{ List<T> l = new ArrayList<T>(); Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = DBUtils.getConnection(); pstmt = conn.prepareStatement(sql); //问题1:不知道set什么,set几次 //有Object[]params if(params!=null) for (int i = 0; i < params.length; i++) { pstmt.setObject(i+1, params[i]); } rs = pstmt.executeQuery(); while(rs.next()){ l.add(toEntity(rs)); } return l; } catch (Exception ex) { throw ex; }finally { if(rs!= null) rs.close(); if(pstmt != null) pstmt.close(); DBUtils.closeConnection(conn); } } /* * 因为while中的对象属性差异无法统一 * 完全交给子类自行完成 * */ public abstract T toEntity(ResultSet rs) throws Exception; } View Code
在BaseDAO 中,面临的问题有三:
1:SQL语句的不同,
2:SQL语句中的参数类型不能确定
3:返回的对象不能确定
解决的方法分别是:
1:SQL语句不同,定义String sql变量
2:SQL语句中的参数类型不确定,使用Object[]params接住所有的参数
3:返回值对象不确定,使用泛型,当其他的DAO继承BaseDAOI时候,将T改写为对应的类型即可;
因此find的生命定义为:protected List<T> find(String sql,Object[] params)throws Exception{}
find 函数中的经典代码:
1:在业务逻辑中填入参数:
//问题1:不知道set什么,set几次 //有Object[]params if(params!=null) for (int i = 0; i < params.length; i++) { pstmt.setObject(i+1, params[i]); }
2:返回结果:
while(rs.next()){ l.add(toEntity(rs)); }
因为在while中的数据类型差异太大,无法统一,完全交给子类处理,定义抽象方法:
public abstract T toEntity(ResultSet rs) throws Exception;
项目源代码下载地址: http://download.csdn.net/detail/generoius/9378231