关于JDBC操作数据的演进(从最基础方式到JDBCTemplate)

Posted 前进道路上的程序猿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于JDBC操作数据的演进(从最基础方式到JDBCTemplate)相关的知识,希望对你有一定的参考价值。

文章目录

前言

在项目中,对数据库进行操作是我们非常重要的一个工作部分,此时我们通常不会使用最原始的数据库操作方法,而是使用一些包装好的中间件来进行数据库操作,jdbcTemplate就是一种很常用的查询数据库的中间件,接下来我们就用实际案例来简单介绍一下相应的演进过程

前期准备

首先我们需要有一个数据库,这里我们用到的是mysql数据库,我们新建了一个school的数据库,同时创建一个student的表如下

然后在数据库表中插入数据用于测试

因为我这里创建的是一个maven项目,我们项目中需要引入mysql操作的相应依赖,如果不是maven项目我们也可以使用相应的jar包

原始操作数据库方式

创建实体类

首先我们根据数据库表创建学生类Student
Student:

public class Student 
    private int id;
    private String name;
    private int age;
    public Student(int id, String name, int age) 
        this.id = id;
        this.name = name;
        this.age = age;
    
    //相应get、set方法
    ...

创建DAO类

然后我们创建相应的Dao
StudentDao :

public class StudentDao 
    public Student get(int id) 
        String sql="select * from student where id=?";
        Connection conn = null;
        Statement st= null;
        ResultSet rs = null;
        try 
            Class.forName("com.mysql.jdbc.Driver");
            conn= DriverManager.getConnection("jdbc:mysql:///school","root","root");
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setObject(1,id);
            rs = ps.executeQuery();
            if(rs.next()) 
                String name = rs.getString("name");
                int age = rs.getInt("age");
                Student stu = new Student(id,name,age);
                return stu;
            
         catch (Exception e)
            e.printStackTrace();
         finally 
            try 
                if(st!=null) 
                    st.close();
                
             catch (SQLException e)
                e.printStackTrace();
             finally 
                try
                    if (conn!=null) conn.close();
                 catch (SQLException e)
                    e.printStackTrace();
                
            
        
        return null;
    
    //新增、删除、修改方法
    ...
 

这个类里我们可以创建student增删改查的方法,这里我们指写了查询方法作为示范,新增、删除、修改、与其类似,这里就不过多赘述
方法里的操作包括:
1、加载注册驱动
2、获取数据库连接
3、创建语句对象
4、执行sql语句
5、释放资源

测试

我们在Test进行测试

public class Test 
     public static void main(String[] args) 
        StudentDao studentDao = new StudentDao();
        System.out.println("name="+studentDao.get(1).getName()+";age="+studentDao.get(1).getAge());
    

执行后后台结果

改进1

我们发现,这里增删改查方法中重复代码很多,如加载驱动、获取数据库连接等等,所有我们可以将这些重复的代码放到一个工具类里
JdbcUtil:

public class JdbcUtil 
    private JdbcUtil() 
    static 
        try 
            Class.forName("com.mysql.jdbc.Driver");
         catch (ClassNotFoundException e) 
            e.printStackTrace();
        
    
    public static Connection getConnection() 
        try
            return DriverManager.getConnection("jdbc:mysql:///school","root","root");
         catch(Exception e) 
            e.printStackTrace();
        
        return null;
    
    public static void close(ResultSet rs, Statement st,Connection conn) 
        try
            if(rs!=null) rs.close();
         catch(SQLException e) 
            e.printStackTrace();
         finally 
            try 
                if(st!=null) st.close();
             catch (SQLException e) 
                e.printStackTrace();
             finally 
                try
                    conn.close();
                 catch(SQLException e) 
                    e.printStackTrace();
                
            
        
    

然后我们在DAO类中直接调用工具类的方法即可

public class StudentDao 
    public Student get(int id) 
        String sql="select * from student where id=?";
        Connection conn = null;
        PreparedStatement ps= null;
        ResultSet rs = null;
        try 
            conn= JdbcUtil.getConnection();
            ps = conn.prepareStatement(sql);
            ps.setObject(1,id);
            rs = ps.executeQuery();
            if(rs.next()) 
                String name = rs.getString("name");
                int age = rs.getInt("age");
                Student stu = new Student(id,name,age);
                return stu;
            
         catch (Exception e)
            e.printStackTrace();
         finally 
            JdbcUtil.close(null,ps,conn);
        
        return null;
    
    //新增、删除、修改方法
    ...

最后测试方法不变,执行结果如下:

改进2

虽然我们完成了重复代码的抽取,但是现实开发中,我们不可能直接将数据库的账号和密码设置在代码里面,这样不利于后续的维护。我们通常都是将数据库账号密码放到一个properties文件里面

新建db.properties

我们在resources下创建db.properties

然后里面输入相应的数据库信息

driverClassName =com.mysql.jdbc.Driver
url =jdbc:mysql:///school
username =root
password =root

改造JdbcUtils

我们在JdbcUtils工具类中,首先在静态类中获取properties资源,然后使用properties中的值替换代码中的数据库相应信息

改进3

我们发现增删改查方法中,出来SQL和设置值不同,其他基本都相同,所以,此时可以将相同的部分抽取出去,不同的部分通过参数传递进来,这是我们创建一个模板类JdbcTemplate

创建模板类JdbcTemplate

JdbcTemplate:

public class JdbcTemplate 
    public static List<Student> query(String sql,Object...params) 
        List<Student> list = new ArrayList();
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try 
            conn=JdbcUtil.getConnection();
            ps=conn.prepareStatement(sql);
            for(int i=0;i<params.length;i++) 
                ps.setObject(i+1,params[i]);
            
            rs=ps.executeQuery();
            while(rs.next()) 
                int id = rs.getInt("id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                Student stu = new Student(id,name,age);
                list.add(stu);
            
         catch (Exception e) 
            e.printStackTrace();
         finally 
            JdbcUtil.close(rs,ps,conn);
        
        return list;
    

调用模板类方法

我们将方法中剩余的重复部分放到模板类中,去除了大量重复性的代码,然后DAO里直接调用就可以了
StudentDao:

public Student get(int id) 
        String sql="select * from student where id=?";
        List<Student> list = JdbcTemplate.query(sql,id);
        return list.size()>0? list.get(0):null;
    

改进4

上面的代码我们只能使用在student中,如果我们想广泛用到其他类中,就需要进一步改造了

创建IRowMapper接口

IRowMapper:

public interface IRowMapper 
    List mapping(ResultSet rs) throws Exception;

创建StudentRowMapper

StudentRowMapper针对Student实现IRowMapper 接口,里面对查询到的结果与实体类进行一一映射
StudentRowMapper :

public class StudentRowMapper implements IRowMapper
    public List mapping(ResultSet rs) throws Exception 
        List<Student> list = new ArrayList<>();
        while (rs.next())
            int id=rs.getInt("id");
            String name = rs.getString("name");
            int age = rs.getInt("age");
            Student stu = new Student(id,name,age);
            list.add(stu);
        
        return list;
    

改造JdbcTemplate

我们在JdbcTemplate中传递IRowMapper 类,然后用IRowMapper的mapping方法处理结果

public class JdbcTemplate 
    public static List<Student> query(String sql,IRowMapper rsh, Object...params) 
        List<Student> list = new ArrayList();
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try 
            conn= JdbcUtil.getConnection();
            ps=conn.prepareStatement(sql);
            for(int i=0;i<params.length;i++) 
                ps.setObject(i+1,params[i]);
            
            rs=ps.executeQuery();
            return rsh.mapping(rs);
         catch (Exception e) 
            e.printStackTrace();
         finally 
            JdbcUtil.close(rs,ps,conn);
        
        return list;
    

改造StudentDao

StudentDao中调用模板方法也做相应调整
StudentDao:

public class StudentDao 
    public Student get(int id) 
        String sql="select * from student where id=?";
        List<Student> list = JdbcTemplate.query(sql,new StudentRowMapper(),id);
        return list.size()>0? list.get(0):null;
    

最后Test不变,测试结果如下:

public class Test 
    public static void main(String[] args) 
        StudentDao studentDao = new StudentDao();
        System.out.println("name="+studentDao.get(1).getName()+";age="+studentDao.get(1).getAge());
    

改进5

我们看到上面IRowMapper中方法返回的类型是List,但是我们实际中还需要查询数量等信息,所以这里需要用到泛型

改造IRowMapper

IRowMapper:

public interface IRowMapper<T> 
    T mapping(ResultSet rs) throws Exception;

改造JdbcTemplate

在模板类中参数和返回中添加泛型
JdbcTemplate:

public class JdbcTemplate 
    public static <T> T query(String sql, IRowMapper<T> rsh, Object...params) 
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try 
            conn= JdbcUtil.getConnection();
            ps=conn.prepareStatement(sql);
            for(int i=0;i<params.length;i++) 
                ps.setObject(i+1,params[i]);
            
            rs=ps.executeQuery();
            return rsh.mapping(rs);
         catch (Exception e) 
            e.printStackTrace();
         finally 
            JdbcUtil.close(rs,ps,conn);
        
        return null;
    

Test不变,测试后结果如下:

至此,大功告成

以上是关于关于JDBC操作数据的演进(从最基础方式到JDBCTemplate)的主要内容,如果未能解决你的问题,请参考以下文章

JDBC操作数据库的三种方式比较

Java基础--JDBC

使用原生JDBC方式对数据库进行操作

JDBC综合例题

java基础——JDBC链接数据库的步骤

关于JDBC小总结