经过对连接池的而学习,我们接下来我们将代码再次进行重构操作
ps:修改代码的位置都会使用注释表示出来啊
重构设计下-JDBC操作
1.修改dom.Impl包下的JDBCUtil使其使用连接池来获取对象
将原有代码
private static Properties p = new Properties();
static {
try {
//在静态代码块中对资源文件进行操作
//先创建ClassLoader类加载器对象,来获取db.properties
ClassLoader loader = Thread.currentThread().getContextClassLoader();
//字节流对象
InputStream in = loader.getResourceAsStream("db.properties");
//加载文件 Properties对象
p.load(in);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//加载驱动
try {
Class.forName(p.getProperty("driverClassName"));
} catch (ClassNotFoundException e) {
throw new RuntimeException("数据库加载驱动异常");
}
}
//提供一个连接方法
public static Connection getConn() {
try {
//获取连接对象
return DriverManager.getConnection(p.getProperty("url"),p.getProperty("username"), p.getProperty("password"));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//连接失败:
throw new RuntimeException("数据库连接异常");
}
替换原有为连接池代码
//1.先创建连接池对象
private static DataSource ds;
//druid连接池加载
static {
try {
Properties p = new Properties();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream in = loader.getResourceAsStream("druid.properties");
//加载文件
p.load(in);
//创建对象
ds = DruidDataSourceFactory.createDataSource(p);
}catch(Exception e) {
e.printStackTrace();
}
}
//获取连接对象
public static Connection getConnection() {
try {
return ds.getConnection();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
throw new RuntimeException("连接异常");
}
2.修改dom.Impl包下的StudentDAOImpl类里面的增删改查中的连接对象获取方式使用连接池获取
将conn = JDBCUtil.getConn();替换为conn = JDBCUtil.getConnection(); 使用这个处理连接方式
3.针对于DML操作(增删改)来说,不同的是:
SQL不同:不同操作都需要SQL,仅仅是SQL内容不同.
占位符参数不同:不同的操作都需要设置占位符参数,仅仅是占位符参数的个数和类型不同.
所以我们将dom.Impl包下的StudentDAOImpl类插入,删除,更改的代码进行修改
将插入
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JDBCUtil.getConn();
//获取预编译对象
ps = conn.prepareStatement(sql);
//赋值
ps.setString(1, student.getName());
ps.setInt(2, student.getAge());
//执行SQL 不要有参数
int rows = ps.executeUpdate();
if (rows == 1) {
System.out.println("插入成功");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
JDBCUtil.close(conn, ps, null);
}
将删除
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JDBCUtil.getConn();
ps = conn.prepareStatement(sql);
ps.setInt(1, id);
int rows = ps.executeUpdate();
if (rows == 1) {
System.out.println("删除成功");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
JDBCUtil.close(conn, ps, null);
}
将更新
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JDBCUtil.getConn();
ps = conn.prepareStatement(sql);
ps.setString(1, student.getName());
ps.setInt(2, student.getAge());
ps.setLong(3, id);
int rows = ps.executeUpdate();
if (rows == 1) {
System.out.println("更新成功");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
JDBCUtil.close(conn, ps, null);
}
在dom.Impl包下将JDBCUtil类添加一个通用的增删改
/**
* 封装一个通用的DML操作
* @param sql DML操作具体的SQL,可以insert,update,delete
* @param params SQL中占位符对应的参数 (使用可变参数的好处就是要么可以什么都不用传,要么可以穿多个参数可以方便使用,使用Object是可以接受任何参数)
* @return 受影响的行数
*/
public static int updata(String sql,Object...params) {
Connection conn = null;
PreparedStatement ps = null;
try {
//这里使用连接池的方式获取连接对象
conn = JDBCUtil.getConnection();
ps = conn.prepareStatement(sql);
//设置占位符参数
//通过循环的方式将参数都设置进去
for(int i = 0;i<params.length;i++) {
//参数因为是使用的Objcet类型所以在设置参数的时候就要使用setObject
ps.setObject(i+1, params[i]);
}
//返回得到的设置参数
return ps.executeUpdate();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
JDBCUtil.close(conn, ps, null);
}
return 0; //失败参数
}
然后在dom.Impl包下将StudentDAOImpl类修改
/*
* 插入 插入数据
*/
@Override
public void save(Student student) {
String sql = "insert into t_student(name,age)values(?,?)";
Object[] params = {student.getName(),student.getAge()};
if(JDBCUtil.updata(sql, params)>0) {
System.out.println("数据库数插入除成功");
}
}
/*
* 删除
*/
@Override
public void delete(int id) {
String sql = "delete from t_student where id = ?";
if (JDBCUtil.updata(sql, id) > 0) {
System.out.println("数据库数据删除成功");
}
}
/*
* 更新
*/
@Override
public void update(int id, Student student) {
String sql = "update t_Student set name = ?,age = ? where id = ?";
Object[] params = {student.getName(),student.getAge(),id};
if(JDBCUtil.updata(sql, params) > 0) {
System.out.println("数据库数据更新成功");
}
}
4.根据第3问题的做法同样可以将DQL操作进行修改
所以我们将dom.Impl包下的StudentDAOImpl类查找的代码进行修改
将查询所有:
// 创建一个集合对象 用来存储 查询结果
List<Student> list = new ArrayList<>();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JDBCUtil.getConn();
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()) {
Student stu = new Student();
// 因为数据库表中的列所对应的值是是可以出现null
// 这里在做描述类的时候,建议将数据类型使用包装类这样既可以兼容null也可以兼容基本类型
stu.setId(rs.getLong("id"));
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
list.add(stu);
}
if (list.size() != 0) {
return list;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.close(conn, ps, rs);
}
查询一个结果:
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JDBCUtil.getConn();
ps = conn.prepareStatement(sql);
ps.setLong(1, id);
rs = ps.executeQuery();
// 将结果集中的对象取出来
while (rs.next()) {
Student stu = new Student();
stu.setId(rs.getLong("id"));
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
return stu;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
JDBCUtil.close(conn, ps, rs);
}
在dom.Impl包下将JDBCUtil类添加一个通用的查找
/**
* DQL操作模板
* @param sql DQL操作具体的SQL,select
* @param params SQL中占位对应参数
* @return 查询结果
*/
public static List<Student> query(String sql,Object... params){
// 创建一个集合对象 用来存储 查询结果
List<Student> list = new ArrayList<>();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//这里使用连接池的方式获取连接对象
conn = JDBCUtil.getConnection();
ps = conn.prepareStatement(sql);
//设置占位符参数
//通过循环的方式将参数都设置进去
for(int i = 0;i<params.length;i++) {
//参数因为是使用的Objcet类型所以在设置参数的时候就要使用setObject
ps.setObject(i+1, params[i]);
}
rs = ps.executeQuery();
while (rs.next()) {
Student stu = new Student();
// 因为数据库表中的列所对应的值是是可以出现null
// 这里在做描述类的时候,建议将数据类型使用包装类这样既可以兼容null也可以兼容基本类型
stu.setId(rs.getLong("id"));
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
list.add(stu);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.close(conn, ps, rs);
}
return list;
}
然后在dom.Impl包下将StudentDAOImpl类修改
/*
* 查询
*/
@Override
public List<Student> list() {
// SQL语句
String sql = "select * from t_student";
return JDBCUtil.query(sql);
}
/*
* 单独查询
*/
@Override
public Student get(int id) {
String sql = "select * from t_student where id= ?";
List<Student> list = JDBCUtil.query(sql, id);
//判断时候取回值,若取会值就返回,没有就是null
return list.size() == 1 ? list.get(0) : null;
}
ps:写上面这些代码时为了让你们明白是从什么位置开始修改,修改成样式,下面的修改就直接体现咋代码中了
5.抽取的DQL操作模板,仅仅只能适用于操作t_student表和Student对象.
如果现在需要操作另一张表(t_teacher),把t_teacher表中的每一行数据封装成Teacher对象.
此时JDBCUtil的query方法再不再通用.
我们不应该把处理结果集的代码放入到JDBCUtil中,因为针对于不同的表处理结果集的方式是不一样的.(因为表的列是不同的)
因为不同DAO处理不同的表(处理不同的结果集),所以我们应该把处理结果集的行为交给每一个DAO的实现类,不应该存放在JDBCUtil中.
所以会先指定处理结果集的规范:
1.在dao包中创建一个接口IResultSetHandler来做通用结果集
2.声明StudentResultSetHandler类来实现这个结果集
ps:StudentResultSetHandler类其实不需要单独声明成一个类,因为这个类就是为了StudentDAOImpl这个类实现的,所以,可以作为当前类的内部类
在dom.Impl包下修改JDBCUtil和StudentDAOImpl类
到这里为止我们将JDBC的封装已经做完了,剩余的让大家上的让其通用可以参考通用结果集处理的办法
ps:在实际开发中我们会这对具体的表做到具体的业务,要做单万物都通的话我们还需要用到更多的技术反射,泛型和内省(Introspector)
这里的JDBCUtil其实就是市面上的-->BDUtil只不过我们封装的更加具体而已,并且是DAO的概念给了大家
最后下一周的Linux要好好学习,我们Hadoop见.......