• spring: 在Spring应用中使用JDBC(使用profiles选择数据源/使用基于JDBC驱动的数据源)


    在实际开发过程中有很多持久化技术可供选择:Hibernate、iBATIS和JPA等。尽管如此,还是有很多应用使用古老的方法即JDBC技术,来访问数据库。

    使用JDBC技术不需要开发人员学习新的框架,因为它就是基于SQL语言运行的。JDBC技术更加灵活,开发人员可以调整的余地很大,JDBC技术允许开发人员充分利用数据库的本地特性,而在其他ORM框架中可能做不到如此灵活和可定制。

    除了上述提到的灵活性、可定制能力,JDBC技术也有一些缺点。

    开发者使用JDBC技术提供的API可以非常底层得操作数据库,同时也意味着,开发者需要负责处理数据访问过程中的各个具体步骤:管理数据库资源和处理数据库访问异常。如果你使用JDBC插入数据库,在这个例子中,假设需要插入一条spitter数据,则可以使用如下代码:

    @Component
    public class SpitterDao {
        private static final String SQL_INSERT_SPITTER =
                "insert into spitter (username, password, firstName, lastName) values (?, ?, ?, ?)";
    
        @Autowired
        private DataSource dataSource;
    
        public void addSpitter(Spitter spitter) {
            Connection conn = null;
            PreparedStatement stmt = null;
    
            try {
                conn = dataSource.getConnection();
                stmt = conn.prepareStatement(SQL_INSERT_SPITTER);
                stmt.setString(1, spitter.getUsername());
                stmt.setString(2, spitter.getPassword());
                stmt.setString(3, spitter.getFirstName());
                stmt.setString(4, spitter.getLastName());
                stmt.execute();
            } catch (SQLException e) {
                //do something...not sure what, though
            } finally {
                try {
                    if (stmt != null) {
                        stmt.close();
                    }
                    if (conn != null) {
                        conn.close();
                    }
                } catch (SQLException e) {
                    //I'm even less sure about what to do here
                }
            }
        }
    }
    

      

    addSpitter函数一共有28行,但是只有6行是真正的业务逻辑。为什么如此简单的操作也需要这么多代码?JDBC需要开发者自己管理数据库连接、自己管理SQL语句,以及自己处理可能抛出的异常。

    对于SQLException,开发者并不清楚具体该如何处理该异常(该异常并未指明具体的错误原因),却被迫需要捕获该异常。如果在执行插入语句时发生错误,你需要捕获该异常;如果在关闭statement和connection资源时发生错误,你也需要捕获该异常,但是捕获后你并不能做实际的有意义的操作。

    同样,如果你需要更新一条spitter记录,则可使用下列代码:

    private static final String SQL_UPDATE_SPITTER =
            "update spitter set username = ?, password = ?, firstName = ?, lastName=? where id = ?";
    
    public void saveSpitter(Spitter spitter) {
        Connection conn = null;
        PreparedStatement stmt = null;
    
        try {
            conn = dataSource.getConnection();
            stmt = conn.prepareStatement(SQL_UPDATE_SPITTER);
            stmt.setString(1, spitter.getUsername());
            stmt.setString(2, spitter.getPassword());
            stmt.setString(3, spitter.getFirstName());
            stmt.setString(4, spitter.getLastName());
            stmt.setLong(5, spitter.getId());
            stmt.execute();
        } catch (SQLException e) {
            // Still not sure what I'm supposed to do here
        } finally {
            try {
                if (stmt != null) {
                    stmt.close();
                }
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException e) {
                // or here
            }
        }
    }
    

      

    这一次,saveSpitter函数用于更新数据库中的一行记录,可以看出,有很多重复代码。理想情况应该是:你只需要写特定功能相关的代码。

    为了补足JDBC体验之旅,我们再看看如何使用JDBC从数据库中查询一条记录,例子代码如下:

    private static final String SQL_SELECT_SPITTER =
            "select id, username, firstName, lastName from spitter where id = ?";
    
    public Spitter findOne(long id) {
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
    
        try {
            conn = dataSource.getConnection();
            stmt = conn.prepareStatement(SQL_SELECT_SPITTER);
            stmt.setLong(1, id);
            rs = stmt.executeQuery();
            Spitter spitter = null;
            if (rs.next()) {
                spitter = new Spitter();
                spitter.setId(rs.getLong("id"));
                spitter.setUsername(rs.getString("username"));
                spitter.setPassword(rs.getString("password"));
                spitter.setFirstName(rs.getString("firstName"));
                spitter.setLastName(rs.getString("lastName"));
            }
            return spitter;
        } catch (SQLException e) {
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) { }
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) { }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) { }
            }
        }
        return null;
    }
    

      

    这个函数跟之前的insert和update例子一样啰嗦冗长:几乎只有20%的代码是真正有用的业务逻辑,而80%的代码则是模板样式代码。

    可以看出,使用JDBC持久化技术,就需要编写大量的模板样式代码,用于创建连接、创建statements和处理异常。另外,上述提到的模板样式代码在数据库访问过程中又非常重要:释放资源和处理异常等,这都能提高数据访问的稳定性。如果没有这些操作,应用就无法及时处理错误、资源始终被占用,会导致内存泄露。因此,开发者需要一个数据库访问框架,用于处理这些模板样式代码。

  • 相关阅读:
    Java8新特性(一)_interface中的static方法和default方法
    从ELK到EFK演进
    使用Maven构建多模块项目
    maven 把本地jar包打进本地仓库
    在基于acpi的linux系统上如何检查当前系统是否支持深度睡眠?
    linux内核中#if IS_ENABLED(CONFIG_XXX)与#ifdef CONFIG_XXX的区别
    linux内核睡眠状态解析
    如何在linux中测试i2c slave模式驱动的功能?
    insmod内核模块时提示"unknown symbol ..."如何处理?
    insmod某个内核模块时提示“Failed to find the folder holding the modules”如何处理?
  • 原文地址:https://www.cnblogs.com/achengmu/p/8301522.html
Copyright © 2020-2023  润新知