1.分析前一天案例中的重复代码
-
dao层的重复代码
-
定义必要的信息、获取数据库的连接、释放资源都是重复的代码!
-
而我们最终的核心功能仅仅只是执行一条sql语句而已啊!
-
所以我们可以抽取出一个JDBC模板类,来封装一些方法(update、query),专门帮我们执行增删改查的sql语句!
-
将之前那些重复的操作,都抽取到模板类中的方法里。就能大大简化我们的使用步骤!
-
2.自定义JDBC框架
2.1数据库的源信息
-
DataBaseMetaData(了解):数据库的源信息
-
java.sql.DataBaseMetaData:封装了整个数据库的综合信息
-
例如:
-
String getDatabaseProductName():获取数据库产品的名称
-
int getDatabaseProductVersion():获取数据库产品的版本号
-
-
-
ParameterMetaData:参数的源信息
-
java.sql.ParameterMetaData:封装的是预编译执行者对象中每个参数的类型和属性
-
这个对象可以通过预编译执行者对象中的getParameterMetaData()方法来获取
-
核心功能:
-
int getParameterCount():获取sql语句中参数的个数
-
-
-
ResultSetMetaData:结果集的源信息
-
java.sql.ResultSetMetaData:封装的是结果集对象中列的类型和属性
-
这个对象可以通过结果集对象中的getMetaData()方法来获取
-
核心功能:
-
int getColumnCount():获取列的总数
-
String getColumnName(int i):获取列名
-
-
2.2JDBCTemplate类增删改功能的编写
public class JDBCTemplate { private DataSource dataSource; private Connection con; private PreparedStatement pst; private ResultSet rs; public JDBCTemplate(DataSource dataSource) { this.dataSource = dataSource; } //专用于执行增删改sql语句的方法 public int update(String sql,Object...objs) { int result = 0; try{ con = dataSource.getConnection(); pst = con.prepareStatement(sql); //获取sql语句中的参数源信息 ParameterMetaData pData = pst.getParameterMetaData(); //获取sql语句中参数的个数 int parameterCount = pData.getParameterCount(); //判断参数个数是否一致 if(parameterCount != objs.length) { throw new RuntimeException("参数个数不匹配"); } //为sql语句中的?占位符赋值 for (int i = 0; i < objs.length; i++) { pst.setObject(i+1,objs[i]); } //执行sql语句 result = pst.executeUpdate(); } catch(Exception e) { e.printStackTrace(); } finally { //释放资源 DataSourceUtils.close(con,pst); } //返回结果 return result; } }
2.3JDBCTemplate类查询功能的编写
-
实体类
/* 学生实体类 */ public class Student { private Integer sid; private String name; private Integer age; private Date birthday; public Student() { } public Student(Integer sid, String name, Integer age, Date birthday) { this.sid = sid; this.name = name; this.age = age; this.birthday = birthday; } public Integer getSid() { return sid; } public void setSid(Integer sid) { this.sid = sid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public String toString() { return "Student{" + "sid=" + sid + ", name='" + name + '\'' + ", age=" + age + ", birthday=" + birthday + '}'; } }
-
ResultSetHandler接口
/* 用于处理结果集的接口 */ public interface ResultSetHandler<T> { //处理结果集的抽象方法。 <T> T handler(ResultSet rs); }
-
BeanHandler实现类
/* 实现类1:用于完成将查询出来的一条记录,封装到Student对象中 */ public class BeanHandler<T> implements ResultSetHandler<T> { //1.声明对象类型变量 private Class<T> beanClass; //2.有参构造对变量赋值 public BeanHandler(Class<T> beanClass) { this.beanClass = beanClass; } /* 将ResultSet结果集中的数据封装到beanClass类型对象中 */ @Override public T handler(ResultSet rs) { //3.声明对象 T bean = null; try{ //4.创建传递参数的对象 bean = beanClass.newInstance(); //5.判断是否有结果集 if(rs.next()) { //6.得到所有的列名 //6.1先得到结果集的源信息 ResultSetMetaData rsmd = rs.getMetaData(); //6.2还要得到有多少列 int columnCount = rsmd.getColumnCount(); //6.3遍历列数 for(int i = 1; i <= columnCount; i++) { //6.4得到每列的列名 String columnName = rsmd.getColumnName(i); //6.5通过列名获取数据 Object columnValue = rs.getObject(columnName); //6.6列名其实就是对象中成员变量的名称。于是就可以使用列名得到对象中属性的描述器(get和set方法) PropertyDescriptor pd = new PropertyDescriptor(columnName.toLowerCase(),beanClass); //6.7获取set方法 Method writeMethod = pd.getWriteMethod(); //6.8执行set方法,给成员变量赋值 writeMethod.invoke(bean,columnValue); } } } catch (Exception e) { e.printStackTrace(); } //7.将对象返回 return bean; } }
-
BeanListHandler实现类
/* 实现类2:用于将结果集封装到集合中 */ public class BeanListHandler<T> implements ResultSetHandler<T> { //1.声明对象变量 private Class<T> beanClass; //2.有参构造为变量赋值 public BeanListHandler(Class<T> beanClass) { this.beanClass = beanClass; } @Override public List<T> handler(ResultSet rs) { //3.创建集合对象 List<T> list = new ArrayList<>(); try{ //4.遍历结果集对象 while(rs.next()) { //5.创建传递参数的对象 T bean = beanClass.newInstance(); //6.得到所有的列名 //6.1先得到结果集的源信息 ResultSetMetaData rsmd = rs.getMetaData(); //6.2还要得到有多少列 int columnCount = rsmd.getColumnCount(); //6.3遍历列数 for(int i = 1; i <= columnCount; i++) { //6.4得到每列的列名 String columnName = rsmd.getColumnName(i); //6.5通过列名获取数据 Object columnValue = rs.getObject(columnName); //6.6列名其实就是对象中成员变量的名称。于是就可以使用列名得到对象中属性的描述器(get和set方法) PropertyDescriptor pd = new PropertyDescriptor(columnName.toLowerCase(),beanClass); //6.7获取set方法 Method writeMethod = pd.getWriteMethod(); //6.8执行set方法,给成员变量赋值 writeMethod.invoke(bean,columnValue); } //7.将对象保存到集合中 list.add(bean); } } catch (Exception e) { e.printStackTrace(); } //8.返回结果 return list; } }
-
ScalarHandler实现类
/* 实现类3:用于返回一个聚合函数的查询结果 */ public class ScalarHandler<T> implements ResultSetHandler<T> { @Override public Long handler(ResultSet rs) { //1.声明一个变量 Long value = null; try{ //2.判断是否有结果 if(rs.next()) { //3.获取结果集的源信息 ResultSetMetaData rsmd = rs.getMetaData(); //4.获取第一列的列名 String columnName = rsmd.getColumnName(1); //5.根据列名获取值 value = rs.getLong(columnName); } } catch(Exception e) { e.printStackTrace(); } //6.将结果返回 return value; } }
-
JDBCTemplate类
public class JDBCTemplate { private DataSource dataSource; private Connection con; private PreparedStatement pst; private ResultSet rs; public JDBCTemplate(DataSource dataSource) { this.dataSource = dataSource; } /* 专用于执行聚合函数sql语句的方法 */ public Long queryForScalar(String sql, ResultSetHandler<Long> rsh, Object...objs) { Long result = null; try{ con = dataSource.getConnection(); pst = con.prepareStatement(sql); //获取sql语句中的参数源信息 ParameterMetaData pData = pst.getParameterMetaData(); int parameterCount = pData.getParameterCount(); //判断参数个数是否一致 if(parameterCount != objs.length) { throw new RuntimeException("参数个数不匹配"); } //为sql语句中的?占位符赋值 for (int i = 0; i < objs.length; i++) { pst.setObject(i+1,objs[i]); } //执行sql语句 rs = pst.executeQuery(); //通过ScalarHandler方式对结果进行处理 result = rsh.handler(rs); } catch(Exception e) { e.printStackTrace(); } finally { //释放资源 DataSourceUtils.close(con,pst,rs); } //将结果返回 return result; } /* 专用于查询所有记录sql语句的方法 */ public <T> List<T> queryForList(String sql, ResultSetHandler<T> rsh, Object...objs) { List<T> list = new ArrayList<>(); try{ con = dataSource.getConnection(); pst = con.prepareStatement(sql); //获取sql语句中的参数源信息 ParameterMetaData pData = pst.getParameterMetaData(); int parameterCount = pData.getParameterCount(); //判断参数个数是否一致 if(parameterCount != objs.length) { throw new RuntimeException("参数个数不匹配"); } //为sql语句中的?占位符赋值 for (int i = 0; i < objs.length; i++) { pst.setObject(i+1,objs[i]); } //执行sql语句 rs = pst.executeQuery(); //通过BeanListHandler方式对结果进行处理 list = rsh.handler(rs); } catch(Exception e) { e.printStackTrace(); } finally { //释放资源 DataSourceUtils.close(con,pst,rs); } //将结果返回 return list; } /* 专用于执行查询一条记录sql语句的方法 */ public <T> T queryForObject(String sql, ResultSetHandler<T> rsh, Object...objs) { T obj = null; try{ con = dataSource.getConnection(); pst = con.prepareStatement(sql); //获取sql语句中的参数源信息 ParameterMetaData pData = pst.getParameterMetaData(); int parameterCount = pData.getParameterCount(); //判断参数个数是否一致 if(parameterCount != objs.length) { throw new RuntimeException("参数个数不匹配"); } //为sql语句中的?占位符赋值 for (int i = 0; i < objs.length; i++) { pst.setObject(i+1,objs[i]); } //执行sql语句 rs = pst.executeQuery(); //通过BeanHandler方式对结果进行处理 obj = rsh.handler(rs); } catch(Exception e) { e.printStackTrace(); } finally { //释放资源 DataSourceUtils.close(con,pst,rs); } //将结果返回 return obj; } }
2.4测试自定义JDBC框架的使用
public class JDBCTemplateTest { //创建JDBCTemplate对象 JDBCTemplate template = new JDBCTemplate(DataSourceUtils.getDataSource()); @Test public void selectScalar() { //查询student表的记录条数 String sql = "SELECT COUNT(*) FROM student"; Long count = template.queryForScalar(sql, new ScalarHandler<Long>()); System.out.println(count); } @Test public void selectAll() { //查询所有学生信息 String sql = "SELECT * FROM student"; List<Student> list = template.queryForList(sql, new BeanListHandler<Student>(Student.class)); for(Student stu : list) { System.out.println(stu); } } @Test public void selectOne() { //查询张三这条记录 String sql = "SELECT * FROM student WHERE sid=?"; //通过BeanHandler将结果封装成一个Student对象 Student stu = template.queryForObject(sql, new BeanHandler<Student>(Student.class), 1); System.out.println(stu); } @Test public void insert() { //新增周七记录 String sql = "INSERT INTO student VALUES (?,?,?,?)"; Object[] params = {5,"周七",27,"2007-07-07"}; int result = template.update(sql, params); System.out.println(result); } @Test public void delete() { //删除周七这条记录 String sql = "DELETE FROM student WHERE sid=?"; int result = template.update(sql, 5); System.out.println(result); } @Test public void update() { //修改张三的年龄为33 String sql = "UPDATE student SET age=? WHERE name=?"; Object[] params = {33,"张三"}; int result = template.update(sql,params); System.out.println(result); } }