前面我们已经知道了一些常用的JDBC操作,接下来我们继续深入,继续改进我们的DAO。
Java 之 JDBC (一)
总之就是不使用池的情况下:每次操作都需要进行连接数据库,连接中需要将Connection加载进内存中,验证用户名和密码等都需要话费时间。
1、 池就是一种容纳对象的容器 2、 连接池就是保存数据库连接对象的容器 3、 在连接池中我们会预先创建一定数量的连接对象,当需要数据库连接的时候,只要从数据库连接池中取出一个,使用完毕之后就再放回去,这些连接对象是以一种循环队列来存放的,取的时候从头开始,放回的时候放在尾部。 4、 通过设置最大连接数量来防止系统无止尽的与数据库连接 5、 连接池中可以设置监听机制,用来测试连接的数量 复制代码
连接池中的属性:
1、 连接池是使用 java.sql.DataSource接口来表示连接池的 2、 DataSource和jdbc一样,也是只提供一个接口,由第三方组织来提供,所以连接池不同的厂家,有不同的连接池 复制代码
以下代码就是获取数据库连接池,并获取连接对象。
1、项目目录下新建一个resource文件夹 2、编写db.properties文件 复制代码
文件内容为:
// 记录配置信息 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/mytest?rewriteBatchedStatements=true username=root password=zjj19970517 maxActive=8 复制代码
为什么要使用配置文件?
例子:
我们可以改写我们的utils类:(通过静态代码块执行获取连接池)
Druid地址
DruidDataSource的配置是兼容DBCP的。从DBCP迁移到DruidDataSource,只需要修改数据源的实现类就可以了。 复制代码
数据查询语言DQL 数据操纵语言DML 数据定义语言DDL 数据控制语言DCL。 复制代码
/** * 更新操作公共方法 * @param sql 预编译sql语句 * @param params 参数数组 * @return */ public int _executeUpdate(String sql, Object...params) { Connection conn = null; PreparedStatement ps = null; try { // 连接数据库 conn = JDBCUtils.getConnection(); // 创建预编译 ps = conn.prepareStatement(sql); // 设置参数 for(int i= 0 ; i < params.length; i++) { ps.setObject(i+1, params[i]); } // 执行更新 return ps.executeUpdate(); // 返回更新的行数 } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(conn, ps, null); } return -1; // 如果更新失败,返回-1 } 复制代码
使用如下:
/** * 存储学生 * @param stu */ public void save(Student stu) { String sql = "insert into student (name, age) values (? , ?)"; this._executeUpdate(sql, stu.getName(), stu.getAge()); //直接调用 } 复制代码
为了今后使用方便我们把 _executeUpdate
方法抽取出来,放入一个 CRUDTemplate
的模版类中。
package com.meils.jdbc.utils; import java.sql.Connection; import java.sql.PreparedStatement; /** * CRUD操作模版 * @author apple * */ public class CRUDTemplate { /** * 更新操作公共方法 * @param sql 预编译sql语句 * @param params 参数数组 * @return */ public static int _executeUpdate(String sql, Object...params) { Connection conn = null; PreparedStatement ps = null; try { // 连接数据库 conn = JDBCUtils.getConnection(); // 创建预编译 ps = conn.prepareStatement(sql); // 设置参数 for(int i= 0 ; i < params.length; i++) { ps.setObject(i+1, params[i]); } // 执行更新 return ps.executeUpdate(); // 返回更新的行数 } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(conn, ps, null); } return -1; // 如果更新失败,返回-1 } } 复制代码
新建一个包: com.meils.jdbc.handle
// IResultSetHandle.java package com.meils.jdbc.handle; import java.sql.ResultSet; import java.util.List; /** * 结果集处理接口 * @author apple * */ // 这里传入了类型,T为我们通过这个方法处理后要返回的类型 public interface IResultSetHandle<T>{ /** * 处理结果集 * @param rs 传入结果集 * @return 返回List集合 */ T handle(ResultSet rs); } 复制代码
在student的dao实现接口类中定义内部类
/** * 结果集处理 实现类 * @author apple * */ // 因为具体到某一个dao层的时候我们就知道了我们想要的类型了,所以传入<List<Student>> class StuResultSetHandle implements IResultSetHandle <List<Student>>{ @Override public List<Student> handle(ResultSet rs) { List<Student> list = new ArrayList<Student>(); try { while (rs.next()) { Student stu = new Student(); stu.setName(rs.getString("name")); stu.setAge(rs.getInt("age")); stu.setId(rs.getInt("id")); list.add(stu); } return list; // 返回集合 } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } } 复制代码
// CRUDTemplate.java package com.meils.jdbc.utils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import com.meils.jdbc.handle.IResultSetHandle; /** * CRUD操作模版 * @author apple * */ public class CRUDTemplate { /** * 更新操作公共方法 * @param sql 预编译sql语句 * @param params 参数数组 * @return */ public static int _executeUpdate(String sql, Object...params) { Connection conn = null; PreparedStatement ps = null; try { // 连接数据库 conn = JDBCUtils.getConnection(); // 创建预编译 ps = conn.prepareStatement(sql); // 设置参数 for(int i= 0 ; i < params.length; i++) { ps.setObject(i+1, params[i]); } // 执行更新 return ps.executeUpdate(); // 返回更新的行数 } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(conn, ps, null); } return -1; // 如果更新失败,返回-1 } /** * 查询 公共方法 * @param sql sql预编译语句 * @param rh 结果集处理的实现对象 * @param params 要给sql语句传入的参数 * @return 返回一个结果集 */ // 这里我们也使用范型,因为我们这里要返回结果集处理方法处理完毕之后的集合,但是处理完毕的结果集我们并不知道是什么类型,因此我们需要通过范型来设置变化的类型 public static <T>T _executeQuery(String sql, IResultSetHandle<T> rh, Object... params) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = JDBCUtils.getConnection(); ps = conn.prepareStatement(sql); for (int i = 0; i < params.length; i++) { ps.setObject(i + 1, params[i]); } rs = ps.executeQuery(); return rh.handle(rs); // 处理结果集 } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(conn, ps, rs); } return null; } } 复制代码
@Override public Student findOne(int id) { String sql = "select * from student where id = ?"; IResultSetHandle <List<Student>> result = new StuResultSetHandle(); List<Student> list = CRUDTemplate._executeQuery(sql,result,id); return list.size() == 1 ? list.get(0) : null; } 复制代码