第1关:指定类型JDBC封装
任务描述
本关任务:按照要求封装一个JDBC
工具类。
相关知识
为了完成本关任务,你需要掌握JDBC
的基本使用,可参考上一个实训内容 Java高级特性 - JDBC(上)。
本章节将针对已知数据结构的某张表进行JDBC
的封装。
连接数据库
在增删改查的过程中,我们都离不开数据库的连接,因此我们可以将其操作封装成一个方法,方法无需参数,将连接对象作为返回值。
在方法中完成驱动加载和数据库连接即可使用:
privatestaticConnectiongetConnection() { //1.加载驱动//2.连接数据库Connectionconn=null; //返回连接对象returnconn; }
封装完后我们就可直接在增删改查中直接使用该方法了。
关闭数据库连接
同样每次连接完数据库我们都需要对相应资源进行释放,我们也将其封装为一个方法,方法参数为经常被使用到的对象,这些对象通常是ResultSet
, Statement
和Connection
,因此我们的关闭连接方法如下:
publicstaticvoidclose(ResultSetrs,PreparedStatementps,Connectionconn){ try { if(rs!=null) rs.close(); if(ps!=null) ps.close(); if(conn!=null) conn.close(); } catch (SQLExceptione) { e.printStackT\frace(); } }
新增数据
现我们数据库中已有的一张新闻表news
,结构如下:
字段名称 | 类型 | 备注 | 约束 |
id | int | 新闻编号 | 主键 |
title | varchar(60) | 新闻标题 | 无 |
author_name | varchar(30) | 作者名称 | 无 |
根据表结构我们创建一个News
对象:
publicclassNews { privateintid; privateStringtitle; privateStringanthor_name; publicNews(intid, Stringtitle, Stringanthor_name) { super(); this.id=id; this.title=title; this.anthor_name=anthor_name; } publicintgetId() { returnid; } publicvoidsetId(intid) { this.id=id; } ......//省略其他属性的get、set方法}
日常生活中我们每天都会看到很多新闻,因此我们需要往数据库中不断新增最新新闻,下面我们一起来对新增方法进行封装:
封装前我们先对方法进行构思,该方法需传递一个News
对象,无需返回值,因此方法的定义和实现思路如下:
publicvoidinsert(Newsnews) throwsSQLException { Connectionconn=getConnection();//拿到连接对象PreparedStatementps=null; //编写新增sql语句Stringsql=""; try{ ps=conn.prepareStatement(sql); //通过传入的news对象对预编译中 ? 进行赋值ps.setXXX(1,news.getXXX()); //执行新增sql语句ps.executeUpdate(); }catch(SQLExceptione){ e.printStackT\frace(); }finally{ //关闭连接close(null, ps, conn); } }
编程要求
在右侧编辑器补充代码,完成数据库连接、删除、更新以及查找方法。其中删除方法是通过用户传入新闻id
来进行删除。
注意:连接数据库名为mysql_db
,数据库用户为root
,密码为123123
。
测试说明
平台会对你编写的代码进行测试:
测试输入:无
预期输出:
News [id=1, title=岳云鹏的18岁,贾玲的18岁,沈腾的18岁,网友:不是来搞笑的?, anthor_name=光明网]
说明:测试文件中会向news
表中插入二条新闻数据,以便对你编写的方法进行检测,数据如下:
id | title | author_name |
1 | 岳云鹏的18岁,贾玲的18岁,沈腾的18岁,网友:不是来搞笑的? | 小明 |
2 | 假设飞行器每秒跑1光年,能飞到宇宙边缘吗?科学家说出答案 | 探索宇宙奥妙 |
开始你的任务吧,祝你成功!
实现代码
【JDBCUtils.java】
packagestep1; importjava.sql.Connection; importjava.sql.DriverManager; importjava.sql.PreparedStatement; importjava.sql.ResultSet; importjava.sql.SQLException; importjava.util.ArrayList; importjava.util.List; importtest.News; publicclassJDBCUtils { /*** 连接数据库*/privatestaticConnectiongetConnection() { Connectionconn=null; /********** Begin **********/Stringurl="jdbc:mysql://localhost:3306/mysql_db"; try { Class.forName("com.mysql.jdbc.Driver"); conn=DriverManager.getConnection(url, "root", "123123"); } catch (ClassNotFoundExceptione) { e.printStackTrace(); } catch (SQLExceptione) { e.printStackTrace(); } /********** End **********/returnconn; } /*** 更新数据方法* * @param news* @throws SQLException*/publicvoidupdate(Newsnews) throwsSQLException { Connectionconn=getConnection(); PreparedStatementps=null; /********** Begin **********/Stringsql="update news set title = ? ,author_name = ? where id = ? "; try { ps=conn.prepareStatement(sql); ps.setObject(1, news.getTitle()); ps.setObject(2, news.getAuthor_name()); ps.setObject(3, news.getId()); ps.execute(); } catch (SQLExceptione) { e.printStackTrace(); thrownewSQLException("更新数据失败"); } finally { close(null, ps, conn); } /********** End **********/ } /*** 查询所有数据* * @return* @throws SQLException*/publicList<News>findAll() throwsSQLException { Connectionconn=getConnection(); PreparedStatementps=null; ResultSetrs=null; Newsnews=null; List<News>newsList=newArrayList<News>(); /********** Begin **********/Stringsql="select * from news"; try { ps=conn.prepareStatement(sql); rs=ps.executeQuery(); while (rs.next()) { news=newNews(rs.getInt(1), rs.getString(2), rs.getString(3)); newsList.add(news); } } catch (SQLExceptione) { e.printStackTrace(); thrownewSQLException("查询所有数据失败"); } finally { close(rs, ps, conn); } /********** End **********/returnnewsList; } /*** 删除方法* * @param id* @throws SQLException*/publicvoiddelete(intid) throwsSQLException { Connectionconn=getConnection(); PreparedStatementps=null; /********** Begin **********/Stringsql="delete from news where id=?"; try { ps=conn.prepareStatement(sql); ps.setObject(1, id); ps.execute(); } catch (SQLExceptione) { e.printStackTrace(); thrownewSQLException(" 删除数据失败"); } finally { close(null, ps, conn); } /********** End **********/ } /*** 增加对象* * @param news* @throws SQLException*/publicvoidinsert(Newsnews) throwsSQLException { Connectionconn=getConnection(); PreparedStatementps=null; Stringsql="insert into news(id,title,author_name)values(?,?,?)"; try { ps=conn.prepareStatement(sql); ps.setInt(1, news.getId()); ps.setString(2, news.getTitle()); ps.setString(3, news.getAuthor_name()); ps.executeUpdate(); } catch (SQLExceptione) { e.printStackTrace(); thrownewSQLException("添加数据失败"); } finally { close(null, ps, conn); } } /*** 根据id查询对象* * @param id* @return* @throws SQLException*/publicNewsfindById(intid) throwsSQLException { Connectionconn=getConnection(); PreparedStatementps=null; ResultSetrs=null; Newsnews=null; Stringsql="select * from news where id=?"; try { ps=conn.prepareStatement(sql); ps.setInt(1, id); rs=ps.executeQuery(); if (rs.next()) { news=newNews(); news.setId(id); news.setTitle(rs.getString(2)); news.setAuthor_name(rs.getString(3)); } } catch (SQLExceptione) { e.printStackTrace(); thrownewSQLException("根据ID查询数据失败"); } finally { close(rs, ps, conn); } returnnews; } /*** 关闭数据库连接* * @param rs* @param ps* @param conn*/publicstaticvoidclose(ResultSetrs, PreparedStatementps, Connectionconn) { try { if (rs!=null) rs.close(); if (ps!=null) ps.close(); if (conn!=null) conn.close(); } catch (SQLExceptione) { e.printStackTrace(); } } }
【News.java】
packagetest; publicclassNews { privateintid; privateStringtitle; privateStringauthor_name; publicNews() { super(); } publicNews(intid, Stringtitle, Stringanthor_name) { super(); this.id=id; this.title=title; this.author_name=anthor_name; } publicintgetId() { returnid; } publicvoidsetId(intid) { this.id=id; } publicStringgetTitle() { returntitle; } publicvoidsetTitle(Stringtitle) { this.title=title; } publicStringgetAuthor_name() { returnauthor_name; } publicvoidsetAuthor_name(Stringauthor_name) { this.author_name=author_name; } publicStringtoString() { return"News [id="+id+", title="+title+", author_name="+author_name+"]"; } }
【Test1.java】
packagetest; importjava.sql.Connection; importjava.sql.DriverManager; importjava.sql.SQLException; importjava.sql.Statement; importjava.util.List; importstep1.JDBCUtils; publicclassTest1 { publicstaticvoidmain(String[] args) throwsSQLException { createTable(); JDBCUtilsjUtils=newJDBCUtils(); Newsnews1=newNews(1, "岳云鹏的18岁,贾玲的18岁,沈腾的18岁,网友:不是来搞笑的?", "小明"); Newsnews2=newNews(2, "假设飞行器每秒跑1光年,能飞到宇宙边缘吗?科学家说出答案", "探索宇宙奥秘"); jUtils.insert(news1); jUtils.insert(news2); // 修改数据news1.setAuthor_name("光明网"); jUtils.update(news1); // 删除数据jUtils.delete(2); // 获取表中数据List<News>findAll=jUtils.findAll(); for (inti=0; i<findAll.size(); i++) { System.out.println(findAll.get(i)); } // 检测update方法NewsfindById=jUtils.findById(1); if (!findById.toString().equals(news1.toString())) { System.out.println("数据修改失败,请检查update方法"); System.out.println("查询id为1的结果:"+findById); } // 检查delete方法NewsfindById2=jUtils.findById(2); if (findById2!=null) { System.out.println("数据删除失败,请检查delete方法"); System.out.println("查询id为2的结果:"+findById2); } } publicstaticvoidcreateTable() { try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundExceptione) { e.printStackTrace(); } Connectionconn=null; Statementstatement=null; Stringurl="jdbc:mysql://localhost:3306/"; try { conn=DriverManager.getConnection(url, "root", "123123"); statement=conn.createStatement(); statement.executeUpdate("drop database if exists mysql_db"); statement.executeUpdate("create database mysql_db"); statement.executeUpdate("use mysql_db"); Stringsql="create table news("+"id int primary key, "+"title varchar(60), "+"author_name varchar(30)"+")"; statement.executeUpdate(sql); } catch (SQLExceptione) { e.printStackTrace(); } finally { try { if (statement!=null) statement.close(); if (conn!=null) conn.close(); } catch (SQLExceptione) { e.printStackTrace(); } } } }
第2关:泛型JDBC封装
任务描述
本关任务:封装一个泛型类的JDBC
工具类。
相关知识
上一章节中我们对具体类(News)进行JDBC的封装,但是在一个项目中,数据库中的表远不止一个,难道我们需要对每一张表都进行封装吗?显然是不妥的,因此我们可以将JDBC工具类封装为一个泛型的。
在学习了反射( JAVA的重要机制——反射Reflection )之后,我们都知道反射机制的强大,利用反射可以获取到类的结构信息,动态调用属性和方法等等。因此,本章节我们采用反射对JDBC的增删改查进行泛型的封装。
为了完成本关任务,你需要掌握:反射的常用方法。
反射的常用方法
获取Class
的实例的三种方法
Classclass=类名.class; Classclass=Class.forName("全类名"); Classclass=对象.getClass();
获取对象的类名
StringclassName=class.getName();//获取结果为全类名StringclassName=class.getSimpleName();//获取简单类名
获取Field
Fieldfield=class.getField("属性名");//通过属性名获取public的属性Field[] fields=class.getFields();//获取所有用public修饰的属性Fieldfield=class.getDeclaredField("属性名");//获取的属性包括public和privateField[] field=c.getDeclaredFields();//获取所有属性包括public和private
获取Field
的信息
Stringname=field.getName();//获取属性名Class<?>type=filed.getType();//获取属性类型Objectvalue=field.get(obj);//获取obj对象field属性的值field.set(obj,value);//设置obj对象的field属性的值
设置private
修饰的属性为可访问
field.setAccessible(true);//默认为false只能对public修饰的操作,设置为true可对private修饰的操作
更新数据的泛型封装分析及实现
我们可以从sql
语句来进行分析,更新数据的sql
,大家都不陌生:update 表名 set column2=value2,columen3=value3 where column1=value1;
观察sql
语句我们可以将该方法设计为让用户传入一个Object
对象,然后利用反射获取对象中的所有属性对其进行修改,具体实现如下(注意Object
对象属性名称要求和数据库中表结构字段名以及类型一致):
publicstaticvoidupdate(Objectobj) { Connectionconn=getConnection();//获取连接对象PreparedStatementps=null; Class<?>c=obj.getClass();//获取obj的ClassStringBuffersb=newStringBuffer("update "+c.getSimpleName() +" set ");//利用StringBuffer进行修改SQL语句的构造Field[] field=c.getDeclaredFields();//通过反射获取对象的属性数组for(inti=1; i<field.length; i++) { if(i!=field.length-1) { //判断是否为最后一个属性,若不是则后增加逗号sb.append(field[i].getName()).append("=?,"); }else { //若为最后一个属性则添加 wheresb.append(field[i].getName()).append("=? where "); } } //默认第一个属性为主键,切更改时通过第一个属性进行更改sb.append(field[0].getName() +"=?"); try { ps=conn.prepareStatement(sb.toString()); for(inti=1; i<field.length; i++) { field[i].setAccessible(true);//设置可以访问私有属性ps.setObject(i, field[i].get(obj));//对预编译的SQL语句中的 ? 进行赋值 } field[0].setAccessible(true); ps.setObject(field.length, field[0].get(obj)); ps.execute();//执行sql语句 } catch (Exceptione) { e.printStackT\frace(); }finally { close(null,ps,conn);//关闭连接数据 } }
编程要求
根据更新数据的示例,在右侧编辑器补充代码,完成增加数据、删除数据、查询表中所有数据三个方法。
测试说明
测试输入:无
预期输出:
Student [id=2, name=李四, sex=男, age=20]
News [id=1, title=岳云鹏的18岁,贾玲的18岁,沈腾的18岁,网友:不是来搞笑的?, author_name=光明网]
News [id=2, title=假设飞行器每秒跑1光年,能飞到宇宙边缘吗?科学家说出答案, author_name=探索宇宙奥秘]
平台将会根据已有的Student
表和News
表来调用你所编写的方法,进行数据的增删改查,分别为二张表中插入二条数据载进行修改News
表中一条数据,删除Student
表中一条数据,插入数据如下:
Student
表
id | name | sex | age |
1 | 张三 | 男 | 18 |
2 | 李四 | 女 | 20 |
News
表
id | title | author_name |
1 | 岳云鹏的18岁,贾玲的18岁,沈腾的18岁,网友:不是来搞笑的? | 光明网 |
2 | 假设飞行器每秒跑1光年,能飞到宇宙边缘吗?科学家说出答案 | 小明 |
注意:本章实训封装的JDBC
工具类只做参考,你也可根据自己的实际需求进行封装属于自己的工具类。
开始你的任务吧,祝你成功!
实现代码
【JDBCUtils.java】
packagestep2; importjava.lang.reflect.Field; importjava.sql.Connection; importjava.sql.DriverManager; importjava.sql.PreparedStatement; importjava.sql.ResultSet; importjava.sql.SQLException; importjava.util.ArrayList; importjava.util.List; publicclassJDBCUtils { privatestaticConnectiongetConnection() { try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundExceptione) { e.printStackTrace(); } Stringurl="jdbc:mysql://localhost:3306/mysql_db"; Connectionconn=null; try { conn=DriverManager.getConnection(url, "root", "123123"); } catch (SQLExceptione) { e.printStackTrace(); } returnconn; } /*** 类名对应表,属性对应字段* * @param obj 传入的对象* @return*/publicvoidinsert(Objectobj) { Connectionconn=getConnection(); // 连接数据库PreparedStatementps=null; /********** Begin **********/try { Stringsql="insert into "; Stringsql2=") values("; // 获取类名当表名StringsimpleName=obj.getClass().getSimpleName(); sql+=simpleName+"("; // 获取所有属性Field[] declaredFields=obj.getClass().getDeclaredFields(); // 拼接sql语句for (inti=0; i<declaredFields.length; i++) { sql+=declaredFields[i].getName(); sql2+="?"; if (i+1!=declaredFields.length) { sql+=","; sql2+=","; } else { sql2+=")"; } } sql+=sql2; ps=conn.prepareStatement(sql); // 填充占位符for (inti=0; i<declaredFields.length; i++) { declaredFields[i].setAccessible(true); Objectobject=null; try { object=declaredFields[i].get(obj); } catch (Exceptione) { e.printStackTrace(); } ps.setObject(i+1, object); } ps.execute(); } /********** End **********/catch (SQLExceptione) { e.printStackTrace(); } finally { close(null, ps, conn); } } /*** 通过对象的Class获取对应表中的所有记录* * @param c* @return*/public<T>List<T>selectAll(Class<T>c) { Connectionconn=getConnection(); List<T>list=newArrayList<T>(); PreparedStatementps=null; ResultSetrs=null; /********** Begin **********/try { // 获取类名当作表名StringsimpleName=c.getSimpleName(); // sql查询语句Stringsql="select * from "+simpleName; ps=conn.prepareStatement(sql); // 获取结果集rs=ps.executeQuery(); // 获取所有属性,对应结果集的所有列Field[] fields=c.getDeclaredFields(); while (rs.next()) { // 创建对象Tt=c.newInstance(); // 给对象对应的属性赋值for (Fieldfield : fields) { field.setAccessible(true); field.set(t, rs.getObject(field.getName())); } // 对象添加到集合list.add(t); } } /********** End **********/catch (Exceptione) { e.printStackTrace(); } finally { close(rs, ps, conn); } returnlist; } /*** 通过主键(默认第一个属性)删除对象* * @param obj* @return*/publicvoiddelete(Objectobj) { Connectionconn=getConnection(); PreparedStatementps=null; /********** Begin **********/try { // 获取类名当作表明StringsimpleName=obj.getClass().getSimpleName(); // 获取第一个属性的信息Field[] declaredFields=obj.getClass().getDeclaredFields(); declaredFields[0].setAccessible(true); Stringname=declaredFields[0].getName(); // sql删除语句Stringsql="delete from "+simpleName+" where "+name+"=?"; // 填充占位符ps=conn.prepareStatement(sql); ps.setObject(1, declaredFields[0].get(obj)); ps.execute(); } /********** End **********/catch (Exceptione) { e.printStackTrace(); } finally { close(null, ps, conn); } } /*** 模拟jdbc的更新操作,默认第一个属性为主键* * @param obj* @return*/publicvoidupdate(Objectobj) { Class<?>c=obj.getClass();// 获取obj的ClassStringBuffersb=newStringBuffer("update "+c.getSimpleName() +" set ");// 利用StringBuffer进行修改SQL语句的构造Field[] field=c.getDeclaredFields();// 通过反射获取对象的属性数组for (inti=1; i<field.length; i++) { if (i!=field.length-1) { // 判断是否为最后一个属性,若不是则后增加逗号sb.append(field[i].getName()).append("=?,"); } else { // 若为最后一个属性则添加 wheresb.append(field[i].getName()).append("=? where "); } } // 默认第一个属性为主键,切更改时通过第一个属性进行更改sb.append(field[0].getName() +"=?"); Stringsql=sb.toString() +";"; Connectionconn=getConnection();// 获取连接对象PreparedStatementps=null; try { ps=conn.prepareStatement(sql); for (inti=1; i<field.length; i++) { field[i].setAccessible(true);// 设置可以访问私有属性ps.setObject(i, field[i].get(obj));// 对预编译的SQL语句中的 ? 进行赋值 } field[0].setAccessible(true); ps.setObject(field.length, field[0].get(obj)); ps.execute();// 执行sql语句 } catch (Exceptione) { e.printStackTrace(); } finally { close(null, ps, conn);// 关闭连接数据 } } publicstaticvoidclose(ResultSetrs, PreparedStatementps, Connectionconn) { try { if (rs!=null) rs.close(); if (ps!=null) ps.close(); if (conn!=null) conn.close(); } catch (SQLExceptione) { e.printStackTrace(); } } public<T>ObjectselectById(Class<T>c, intid) { Stringsql="select * from "+c.getSimpleName() +" where id="+id; Field[] field=c.getDeclaredFields(); Connectionconn=getConnection(); PreparedStatementps=null; ResultSetrs=null; Objectobj=null; try { ps=conn.prepareStatement(sql); rs=ps.executeQuery(); obj=c.newInstance(); while (rs.next()) { for (inti=0; i<field.length; i++) { field[i].setAccessible(true); field[i].set(obj, rs.getObject(field[i].getName())); } } } catch (Exceptione) { e.printStackTrace(); } finally { close(rs, ps, conn); } returnobj; } }
【News.java】
packagetest; publicclassNews { privateintid; privateStringtitle; privateStringauthor_name; publicNews() { super(); } publicNews(intid, Stringtitle, Stringanthor_name) { super(); this.id=id; this.title=title; this.author_name=anthor_name; } publicintgetId() { returnid; } publicvoidsetId(intid) { this.id=id; } publicStringgetTitle() { returntitle; } publicvoidsetTitle(Stringtitle) { this.title=title; } publicStringgetAuthor_name() { returnauthor_name; } publicvoidsetAuthor_name(Stringauthor_name) { this.author_name=author_name; } publicStringtoString() { return"News [id="+id+", title="+title+", author_name="+author_name+"]"; } }
【Test2.java】
packagetest; importjava.sql.Connection; importjava.sql.DriverManager; importjava.sql.SQLException; importjava.sql.Statement; importjava.util.List; importstep2.JDBCUtils; publicclassTest2 { staticJDBCUtilsjUtils=newJDBCUtils(); publicstaticvoidmain(String[] args) { createTable(); Studentstudent1=newStudent(1, "张三", "男", 18); Studentstudent2=newStudent(2, "李四", "女", 20); Newsnews1=newNews(1, "岳云鹏的18岁,贾玲的18岁,沈腾的18岁,网友:不是来搞笑的?", "光明网"); Newsnews2=newNews(2, "假设飞行器每秒跑1光年,能飞到宇宙边缘吗?科学家说出答案", "小明"); jUtils.insert(student1); jUtils.insert(student2); jUtils.insert(news1); jUtils.insert(news2); isTrue(student1, student2, news1, news2, "新增"); news2.setAuthor_name("探索宇宙奥秘"); jUtils.update(news2); student2.setSex("男"); jUtils.update(student2); isTrue(student1, student2, news1, news2, "更新"); jUtils.delete(student1); List<Student>studentList1=jUtils.selectAll(Student.class); if (studentList1.size() !=0) { if (studentList1.size() !=1) { System.out.println("数据删除失败,请检查delete方法。"+student1.toString() +"未被删除成功"); } } else { System.out.println("请完成查询方法"); } List<Student>studentList=jUtils.selectAll(Student.class); for (inti=0; i<studentList.size(); i++) { System.out.println(studentList.get(i)); } List<News>newsList=jUtils.selectAll(News.class); for (inti=0; i<newsList.size(); i++) { System.out.println(newsList.get(i)); } } publicstaticvoidcreateTable() { try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundExceptione) { e.printStackTrace(); } Connectionconn=null; Statementstatement=null; Stringurl="jdbc:mysql://localhost:3306/"; try { conn=DriverManager.getConnection(url, "root", "123123"); statement=conn.createStatement(); statement.executeUpdate("drop database if exists mysql_db"); statement.executeUpdate("create database mysql_db"); statement.executeUpdate("use mysql_db"); Stringsql="create table News("+"id int primary key, "+"title varchar(60), "+"author_name varchar(30)"+")"; statement.executeUpdate(sql); Stringsql2="create table Student("+"id int primary key, "+"name varchar(20), "+"sex varchar(4),"+"age int"+")"; statement.executeUpdate(sql2); } catch (SQLExceptione) { e.printStackTrace(); } finally { try { if (statement!=null) statement.close(); if (conn!=null) conn.close(); } catch (SQLExceptione) { e.printStackTrace(); } } } publicstaticvoidisTrue(Studentstudent1, Studentstudent2, Newsnews1, Newsnews2, Stringtype) { Students1= (Student) jUtils.selectById(Student.class, 1); Students2= (Student) jUtils.selectById(Student.class, 2); Newsn1= (News) jUtils.selectById(News.class, 1); Newsn2= (News) jUtils.selectById(News.class, 2); if (!student1.toString().equals(s1.toString()) ||!student2.toString().equals(s2.toString()) ||!news1.toString().equals(n1.toString()) ||!news2.toString().equals(n2.toString())) { System.out.println("请按要求完成"+type+"方法"); } } }