Java高级特性 - JDBC(下)

第1关:指定类型JDBC封装
任务描述
本关任务:按照要求封装一个JDBC工具类。
相关知识
为了完成本关任务,你需要掌握JDBC的基本使用,可参考上一个实训内容 Java高级特性 - JDBC(上)。
本章节将针对已知数据结构的某张表进行JDBC的封装。
连接数据库
在增删改查的过程中,我们都离不开数据库的连接,因此我们可以将其操作封装成一个方法,方法无需参数,将连接对象作为返回值。
在方法中完成驱动加载和数据库连接即可使用:

private static Connection getConnection() {
    //1.加载驱动
    //2.连接数据库
    Connection conn=null;
    //返回连接对象
    return conn;
}

封装完后我们就可直接在增删改查中直接使用该方法了。
关闭数据库连接
同样每次连接完数据库我们都需要对相应资源进行释放,我们也将其封装为一个方法,方法参数为经常被使用到的对象,这些对象通常是ResultSet, Statement和Connection,因此我们的关闭连接方法如下:

public static void close(ResultSet rs,PreparedStatement ps,Connection conn){
    try {
        if(rs!=null)  rs.close();
        if(ps!=null)  ps.close();
        if(conn!=null)  conn.close();
    } catch (SQLException e) {
        e.printStackT\frace();
    }
}

新增数据
现我们数据库中已有的一张新闻表news,结构如下:
在这里插入图片描述
根据表结构我们创建一个News对象:

public class News {
    private int id;
    private String title;
    private String anthor_name;
    public News(int id, String title, String anthor_name) {
        super();
        this.id = id;
        this.title = title;
        this.anthor_name = anthor_name;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    ......//省略其他属性的get、set方法
}

日常生活中我们每天都会看到很多新闻,因此我们需要往数据库中不断新增最新新闻,下面我们一起来对新增方法进行封装:
封装前我们先对方法进行构思,该方法需传递一个News对象,无需返回值,因此方法的定义和实现思路如下:

public void insert(News news) throws SQLException {
    Connection conn = getConnection();//拿到连接对象
    PreparedStatement ps = null;
    //编写新增sql语句
    String sql = "";
    try{
        ps = conn.prepareStatement(sql);
        //通过传入的news对象对预编译中 ? 进行赋值
        ps.setXXX(1,news.getXXX());
        //执行新增sql语句
        ps.executeUpdate();
    }catch(SQLException e){
        e.printStackT\frace();
    }finally{
        //关闭连接
        close(null, ps, conn);
    }
}

编程要求
在右侧编辑器补充代码,完成数据库连接、删除、更新以及查找方法。其中删除方法是通过用户传入新闻id来进行删除。
注意:连接数据库名为mysql_db,数据库用户为root,密码为123123。
测试说明
平台会对你编写的代码进行测试:
测试输入:无
预期输出:
News [id=1, title=岳云鹏的18岁,贾玲的18岁,沈腾的18岁,网友:不是来搞笑的?, anthor_name=光明网]
说明:测试文件中会向news表中插入二条新闻数据,以便对你编写的方法进行检测,数据如下:
在这里插入图片描述
开始你的任务吧,祝你成功!
参考代码:

package step1;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import test.News;
public class JDBCUtils {
    /**
     * 连接数据库
     */
    private static Connection getConnection() {
        Connection conn=null;
        /**********  Begin  **********/
        String url="jdbc:mysql://localhost:3306/mysql_db";
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection(url, "root","123123");
        }catch (ClassNotFoundException e) {
            e.printStackTrace();
        }catch (SQLException e) {
            e.printStackTrace();
        }
        /**********   End   **********/
        return conn;
    }
    /**
     * 更新数据方法
     * @param news
     * @throws SQLException
     */
    public void update(News news) throws SQLException {
        Connection conn = getConnection();
        PreparedStatement ps = null;
        /**********  Begin  **********/
        String sql = "update news set title=?,author_name=? where id=?";
        try{
            ps = conn.prepareStatement(sql);
            ps.setString(1, news.getTitle());
            ps.setString(2, news.getAuthor_name());
            ps.setInt(3, news.getId());
            ps.executeUpdate();
        }catch(SQLException e){
            e.printStackTrace();
            throw new SQLException("更新数据失败");
        }finally{
            close(null, ps, conn);
        }    
        /**********  End  **********/
    }
    /**
     * 查询所有数据
     * @return
     * @throws SQLException
     */
    public List<News> findAll() throws SQLException {
        Connection conn =  getConnection();
        PreparedStatement ps = null;
        ResultSet rs = null;
        News news = null;
        List<News> newsList = new ArrayList<News>();
        /**********  Begin  **********/
        String sql = "select * from news";
        try{
            ps = conn.prepareStatement(sql);
            rs = ps.executeQuery();
            while(rs.next()){
                news = new News();
                news.setId(rs.getInt(1));
                news.setTitle(rs.getString(2));
                news.setAuthor_name(rs.getString(3));
                newsList.add(news);
            }
        }catch(SQLException e){
            e.printStackTrace();
            throw new SQLException("查询所有数据失败");
        }finally{
            close(rs, ps, conn);
        }
        /**********  End  **********/
        return newsList;
    }
    /**
     * 删除方法
     * @param id
     * @throws SQLException
     */
    public void delete(int id) throws SQLException{
        Connection conn = getConnection();
        PreparedStatement ps = null;
        /**********  Begin  **********/
        String sql = "delete from news where id=?";
        try{
            ps = conn.prepareStatement(sql);
            ps.setInt(1,id);
            ps.executeUpdate();
        }catch(SQLException e){
            e.printStackTrace();
            throw new SQLException(" 删除数据失败");
        }
        finally{
            close(null, ps, conn);
        }        
        /**********  End  **********/
    }
    /**
     * 增加对象
     * @param news
     * @throws SQLException
     */
    public void insert(News news) throws SQLException {
        Connection conn = getConnection();
        PreparedStatement ps = null;
        String sql = "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(SQLException e){
            e.printStackTrace();
            throw new SQLException("添加数据失败");
        }finally{
           close(null, ps, conn);
        }
    }
    /**
     * 根据id查询对象
     * @param id
     * @return
     * @throws SQLException
     */
    public News findById(int id) throws SQLException {
        Connection conn = getConnection();
        PreparedStatement ps = null;
        ResultSet rs = null;
        News news = null;
        String sql = "select * from news where id=?";
        try{
            ps = conn.prepareStatement(sql);
            ps.setInt(1, id);
            rs = ps.executeQuery();
            if(rs.next()){
            	news = new News();
            	news.setId(id);
            	news.setTitle(rs.getString(2));
            	news.setAuthor_name(rs.getString(3));
            }
        }catch(SQLException e){
            e.printStackTrace();
            throw new SQLException("根据ID查询数据失败");
        }
        finally{
            close(rs, ps, conn);
        }
        return news;
    }
    /**
     * 关闭数据库连接
     * @param rs
     * @param ps
     * @param conn
     */
    public static void close(ResultSet rs,PreparedStatement ps,Connection conn){
    	try {
    		if(rs!=null)rs.close();
    		if(ps!=null)ps.close();
    		if(conn!=null)conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
    }
}	

第2关:泛型JDBC封装
任务描述
本关任务:封装一个泛型类的JDBC工具类。
相关知识
上一章节中我们对具体类(News)进行JDBC的封装,但是在一个项目中,数据库中的表远不止一个,难道我们需要对每一张表都进行封装吗?显然是不妥的,因此我们可以将JDBC工具类封装为一个泛型的。
在学习了反射( Java高级特性 - Java反射 )之后,我们都知道反射机制的强大,利用反射可以获取到类的结构信息,动态调用属性和方法等等。因此,本章节我们采用反射对JDBC的增删改查进行泛型的封装。
为了完成本关任务,你需要掌握:反射的常用方法。
反射的常用方法
获取Class的实例的三种方法

Class class=类名.class;
Class class=Class.forName("全类名");
Class class=对象.getClass();

获取对象的类名

String className=class.getName();//获取结果为全类名
String className=class.getSimpleName();//获取简单类名

获取Field

Field field=class.getField("属性名");//通过属性名获取public的属性
Field[] fields=class.getFields();//获取所有用public修饰的属性
Field field=class.getDeclaredField("属性名");//获取的属性包括public和private
Field[] field = c.getDeclaredFields();//获取所有属性包括public和private

获取Field的信息

String name=field.getName();//获取属性名
Class<?> type=filed.getType();//获取属性类型
Object value=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对象属性名称要求和数据库中表结构字段名以及类型一致):

public static void update(Object obj) {
    Connection conn = getConnection();//获取连接对象
    PreparedStatement ps = null;
    Class<?> c = obj.getClass();//获取obj的Class
    StringBuffer sb = new StringBuffer("update "+ c.getSimpleName() +" set ");//利用StringBuffer进行修改SQL语句的构造
    Field[] field = c.getDeclaredFields();//通过反射获取对象的属性数组
    for(int i = 1; i < field.length; i++) {
        if(i != field.length-1) {    //判断是否为最后一个属性,若不是则后增加逗号
            sb.append(field[i].getName()).append("=?,");
        }else {    //若为最后一个属性则添加 where
            sb.append(field[i].getName()).append("=? where ");
        }
    }
    //默认第一个属性为主键,切更改时通过第一个属性进行更改
    sb.append(field[0].getName() + "=?");
    try {
        ps = conn.prepareStatement(sb.toString());
        for(int i = 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 (Exception e) {
        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表
在这里插入图片描述
News表
在这里插入图片描述
注意:本章实训封装的JDBC工具类只做参考,你也可根据自己的实际需求进行封装属于自己的工具类。
开始你的任务吧,祝你成功!
参考代码:

package step2;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class JDBCUtils {
	private static Connection getConnection() {
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		String url="jdbc:mysql://localhost:3306/mysql_db";
		Connection conn=null;
		try {
			conn = DriverManager.getConnection(url, "root","123123");
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return conn;
	}
	/**
     * 类名对应表,属性对应字段
     * @param obj  传入的对象
     * @return
     */
    public void insert(Object obj) {
    	Connection conn = getConnection();  //连接数据库
    	PreparedStatement ps = null;
    	/********** Begin **********/
    	//获取obj的Class
        Class<?> c = obj.getClass();        
        //利用StringBuffer进行插入SQL语句的构造
        StringBuffer sb1 = new StringBuffer("insert into "+ c.getSimpleName() +"(");  //通过反射获取类名映射表名
        StringBuffer sb2 = new StringBuffer(" values(");  //注意前面要多加一个空格 否则sql将连在一起
        Field[] field = c.getDeclaredFields();            //获取对象的属性数组
        for(int i = 0; i < field.length; i++) {           //遍历属性构造SQL语句
            if(i != field.length-1) {
                sb1.append(field[i].getName()).append(",");
                sb2.append("?,");
            }else {
                sb1.append(field[i].getName()).append(")");
                sb2.append("?);");
            }
        }
        String sql = sb1.append(sb2).toString();
        try {
            ps = conn.prepareStatement(sql);
            for(int i = 0; i < field.length; i++) {    
                field[i].setAccessible(true);                    //设置属性的可访问性,可以访问私有属性
                try {                                            //通过Field的get(Object)方法获取Object对象的属性值
                    ps.setObject(i+1, field[i].get(obj));        //对预编译的SQL语句中的?进行赋值
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            ps.execute();        //执行SQL
        }
        /********** End **********/
        catch (SQLException e) {
            e.printStackTrace();
        }finally {    
            close(null,ps,conn);
        }
    }
    /**
     * 通过对象的Class获取对应表中的所有记录
     * @param c
     * @return
     */
    public <T> List<T> selectAll(Class<T> c) {
    	Connection conn = getConnection();
    	List<T> list = new ArrayList<T>();          
    	PreparedStatement ps = null;
    	ResultSet rs = null;
    	/********** Begin **********/
       String sql = "select * from "+ c.getSimpleName()+";";        //通过反射获取类名对应表名构造SQL语句
        Field[] field = c.getDeclaredFields();                        //通过反射获取所有属性
        try {
            ps = conn.prepareStatement(sql);            
            rs = ps.executeQuery();                     
            while(rs.next()) {
                T obj = c.newInstance();                //通过反射构造一个T类型的实例
                for(int i = 0; i < field.length; i++) {        
                    field[i].setAccessible(true);                            //设置可以访问私有属性
                    field[i].set(obj, rs.getObject(field[i].getName()));    //通过属性名获取结果集中的值赋值到实例对象中
                }
                list.add(obj);                                                //将实例对象添加到list集合
            }
         }
        /********** End **********/ 
        catch (Exception e) {
            e.printStackTrace();
        }finally {    
            close(rs,ps,conn);
        }
        return list;
    }
    /**
     * 通过主键(默认第一个属性)删除对象
     * @param obj
     * @return
     */
    public void delete(Object obj) {
    	Connection conn = getConnection();
    	PreparedStatement ps = null;
    	/********** Begin **********/
       //获取obj的Class
        Class<?> c = obj.getClass();        
        //构造删除的SQL语句
        StringBuffer sb = new StringBuffer("delete from ");
        sb.append(c.getSimpleName()).append(" where ");
        //获取对象属性数组
        Field[] field = c.getDeclaredFields();
        //设置第一个属性的可访问性
        field[0].setAccessible(true);
        //获取第一个属性的属性名构造删除sql
        sb.append(field[0].getName()).append("=?");
        String sql = sb.toString();
        try {
            ps = conn.prepareStatement(sql);
            ps.setObject(1, field[0].get(obj));    
            ps.execute();
        } 
        /********** End **********/
        catch (Exception e) {
            e.printStackTrace();
        }finally {    
            close(null,ps,conn);
        }
    }
    /**
     * 模拟jdbc的更新操作,默认第一个属性为主键
     * @param obj
     * @return
     */
    public void update(Object obj) {
    	Class<?> c = obj.getClass();//获取obj的Class
    	StringBuffer sb = new StringBuffer("update "+ c.getSimpleName() +" set ");//利用StringBuffer进行修改SQL语句的构造
    	Field[] field = c.getDeclaredFields();//通过反射获取对象的属性数组
    	for(int i = 1; i < field.length; i++) {
    		if(i != field.length-1) {    //判断是否为最后一个属性,若不是则后增加逗号
    			sb.append(field[i].getName()).append("=?,");
    		}else {    //若为最后一个属性则添加 where
    			sb.append(field[i].getName()).append("=? where ");
    		}
    	}
    	//默认第一个属性为主键,切更改时通过第一个属性进行更改
    	sb.append(field[0].getName() + "=?");
    	String sql = sb.toString()+";";
    	Connection conn = getConnection();//获取连接对象
    	PreparedStatement ps = null;
    	try {
    		ps = conn.prepareStatement(sql);
    		for(int i = 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 (Exception e) {
    		e.printStackTrace();
    	}finally {
    		close(null,ps,conn);//关闭连接数据
    	}
    }
    public static void close(ResultSet rs,PreparedStatement ps,Connection conn){
    	try {
    		if(rs!=null) rs.close();
    		if(ps!=null) ps.close();
    		if(conn!=null) conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
    }
    public <T> Object selectById(Class<T> c,int id) {
        String sql = "select * from "+ c.getSimpleName()+" where id="+id;    
        Field[] field = c.getDeclaredFields();
        Connection conn = getConnection();
        PreparedStatement ps = null;
        ResultSet rs = null;
        Object obj=null;
        try {
            ps = conn.prepareStatement(sql);  
            rs = ps.executeQuery(); 
            obj = c.newInstance();
            while(rs.next()) {
                for(int i = 0; i < field.length; i++) {      
                    field[i].setAccessible(true);           
                    field[i].set(obj, rs.getObject(field[i].getName()));   
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {    
            close(rs,ps,conn);
        }
        return obj;
    }
}
  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值