自定义JDBC框架:
定义必要的信息、获取数据库的连接、释放资源都是重复的代码,在操作JDBC时通常都是执行SQL语句就可以了,所以需要抽取出来一个模板类来封装一些方法(Update、Query),专门执行增删改查的SQL语句,简化使用步骤。
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):获取列名
查询的方法:
- 查询一条记录并封装对象的方法:queryForObject()
- 查询多条记录并封装到集合的方法:queryForList()
- 查询聚合函数并返回单条数据的方法:queryForScalar()
JDBCTemplate类增删改功能的编写
public class JDBCTemplate {// 1. 定义参数变量:数据源、连接对象、执行者对象、结果集对象private DataSource dataSource;private Connection connection;private PreparedStatement ps;private ResultSet resultSet;// 2. 通过有参构造为数据赋值public JDBCTemplate(DataSource dataSource) {this.dataSource = dataSource;}// 3. 定义Update方法,参数:sql语句、sql语句中的参数public int update(String sql, Object... objects) {// 4. 定义int变量,用于接收增删改后影响的行数int result = 0;try {// 5. 通过数据获取一个数据库连接connection = dataSource.getConnection();// 6. 通过数据库连接对象获取执行者对象,并对sql语句进行预编译ps = connection.prepareStatement(sql);// 7. 通过执行者对象获取参数的源信息对象ParameterMetaData parameterMetaData = ps.getParameterMetaData();// 8. 通过参数源信息对象获取参数的个数int count = parameterMetaData.getParameterCount();// 9. 判断参数数量是否一致if (count != objects.length) {throw new RuntimeException("参数个数不匹配");}// 10. 为sql语句占位符赋值for (int i = 0; i < objects.length; i++) {ps.setObject(i + 1, objects[i]);}// 11. 执行sql语句并接收结果result = ps.executeUpdate();} catch (SQLException sqlException) {sqlException.printStackTrace();} finally {// 12. 释放资源DataSourceUtils.close(connection, ps);}// 13. 返回结果return result;}
}
JDBCTemplate类查询功能的编写:
- 实体类
/*学生实体类*/
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;}@Overridepublic 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类型对象中*/@Overridepublic 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;}@Overridepublic 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> {@Overridepublic 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;}
}
测试自定义JDBC框架的使用:
public class JDBCTemplateTest {//创建JDBCTemplate对象JDBCTemplate template = new JDBCTemplate(DataSourceUtils.getDataSource());@Testpublic void selectScalar() {//查询student表的记录条数String sql = "SELECT COUNT(*) FROM student";Long count = template.queryForScalar(sql, new ScalarHandler<Long>());System.out.println(count);}@Testpublic 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);}}@Testpublic 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);}@Testpublic 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);}@Testpublic void delete() {//删除周七这条记录String sql = "DELETE FROM student WHERE sid=?";int result = template.update(sql, 5);System.out.println(result);}@Testpublic void update() {//修改张三的年龄为33String sql = "UPDATE student SET age=? WHERE name=?";Object[] params = {33,"张三"};int result = template.update(sql,params);System.out.println(result);}
}