Java 处理数据库:良好的软件工程概念

Java 处理数据库:良好的软件工程概念,java,sql,jdbc,Java,Sql,Jdbc,当我创建JDBC应用程序时,我通常做的是,将“sql语句”硬编码到java程序中。例如 ResultSet rs = st.execute("select * from Users") 但是,我听说这种方法不是好的软件工程概念。有人说所有这些sql语句都应该作为“存储过程”留在数据库中,JDBC应该访问它们。从这两种方法中,哪一种可以归类为好的软件工程概念?请帮忙 如果您硬编码SQL语句,那么每次更改数据库中的某些内容时,您可能都必须在源代码中更改它们 通过使用存储过程,您只需更改这些过程,而

当我创建JDBC应用程序时,我通常做的是,将“sql语句”硬编码到java程序中。例如

ResultSet rs = st.execute("select * from Users")

但是,我听说这种方法不是好的软件工程概念。有人说所有这些sql语句都应该作为“存储过程”留在数据库中,JDBC应该访问它们。从这两种方法中,哪一种可以归类为好的软件工程概念?请帮忙

如果您硬编码SQL语句,那么每次更改数据库中的某些内容时,您可能都必须在源代码中更改它们

通过使用存储过程,您只需更改这些过程,而无需更改java程序的源代码


因此,我建议使用存储过程

我预测,在这一点上,你不会找到共识

存储过程用于封装复杂的数据库逻辑和查询,同时避免为了排序/筛选/查询等而将数据从数据库中传输出去

缺点是,您经常会发现业务逻辑潜入存储过程,而它很可能会留在应用程序本身


因此,开发人员/DBA等之间经常会就这个逻辑应该驻留在哪里以及如何使用存储过程展开拔河。我建议务实一点。本地化SQL查询,以便在更改SQL(表名等)时,不必跨整个代码库更改内容。在执行代码复杂但对数据库来说微不足道的工作时,利用存储的过程来提高性能。

使用硬编码字符串并将它们传递到
语句中肯定不是一种好的软件工程实践

您应该始终使用
PreparedStatement

例如:

String selectSQL = "SELECT USER_ID, USERNAME FROM DBUSER WHERE USER_ID = ?";
PreparedStatement preparedStatement = dbConnection.prepareStatement(selectSQL);
preparedStatement.setInt(1, 1001);
ResultSet rs = preparedStatement.executeQuery(selectSQL ); 

存储过程也是很好的实践。大多数情况下,存储过程更多地用作性能透视图,因为您的查询除了第一次运行外都是预编译的。

最好在数据库中使用函数或存储过程,返回
SYS\u REFCURSOR
,并使用
CallableStatement
从java调用这些函数或存储过程

如果您使用的是Oracle数据库,则可以尝试以下操作

数据库功能

CREATE OR REPLACE FUNCTION my_func (p_deptno IN number,p_emp_no IN varchar2)
   RETURN SYS_REFCURSOR
AS
   p_cursor   SYS_REFCURSOR;
BEGIN
   OPEN p_cursor FOR
      select *
        from emp
        where deptno = p_deptno and emp_number=p_emp_no;
   RETURN p_cursor;
END;
/
Java

        callablestatement = 
                connection.prepareCall("begin ? :=my_func(?,?); end;");
callablestatement.registerOutParameter(1, OracleTypes.CURSOR);
callablestatement.setString(2, param);
callablestatement.setString(3, param);
            callablestatement.execute();
            resultSet = ((OracleCallableStatement)callablestatement).getCursor(1);
使用这种方法,您可以避免在java中硬编码sql语句。

使用Hibernate(或其他ORM),这样您就不需要维护这么多sql语句。 Hibernate在后台为您生成大部分SQL,这样您就不必担心维护SQL语句了


其他ORM也可用,如TopLink和OpenJPA

我更愿意将所有SQL查询存储为常量:

public static final String sqlEmpInsert = "SELECT EMP_NAME FROM EMPLOYEES";

在一个单独的java类中。对于每个模块,我有单独的“常量”类文件,对于某些模块,我将SQL查询存储在单独的属性文件中,以便将其与java类文件分离。

在没有参数更改的情况下,不需要更改源代码。但是假设您正在从JDBC向SP传递参数,那么两个位置的更改都需要使用SP进行更改您不需要知道java程序中DB(表名、列名……)的结构。对这些的更改只需要对SP进行更改,而不需要对java程序进行更改。您确定您的意思是“存储过程”吗?您可能对阻止SQL注入的“预处理语句”感兴趣。您这么说,但您的理由是什么?我试图提出避免java中硬编码SQL语句的方法。通过这样做,它将如何成为与问题无关的东西?提出问题的人应该说这与问题无关,而不是对其他人的建议和答案发表意见。@Polappan:不是不愉快的感觉。我可以删除我的评论。没有什么是针对个人的here@HardikMishra也删除了我的评论。没问题。你这么说,但在OP的问题中,他在execute()语句中给出了一个未经优化的示例,这看起来很好me@BrianAgnew:是的,但这只是一个例子。我们可能不知道它是惟一要执行的SQL查询操作类型。所以,我写这篇文章是为了让OP awareimagine像这样:你需要得到(priceColumn*quantityColumn)*2的答案。值“2”不会改变bcs,因为它是算法。在这种情况下,什么是最好的?@Yohan-我可能会在应用程序的业务逻辑中这样做,并将其移动到数据库中,如果该表相当大,并且移动到应用程序中的行数是有限的。正如我所说,没有正确/错误的答案here@Yohan-我不愿意将此视为“非常错误”。我认为这接近于绩效类型和/或公司政策类型的问题。请注意,在Oracle中(不知道其他情况),您可以定义一个虚拟列,该列会自动计算,因此它看起来像一个列,但不是实际列。这是第三种选择。在这种情况下,你最好的办法就是讨论你所有的选择和优缺点。太棒了!我问这个问题的原因是,这个。我参加了一次采访,他让我在30分钟内创建一个JDBC应用程序(为什么??),这是他给我的。我在应用程序中使用了相同的函数(实际上,它甚至不能像这样改变,我必须从2列中得到2个值并乘以2)。他告诉我我做了一件非常非常错误的事情,我必须放入一个存储过程,并将值传递给DB。我对此表示怀疑,因为当我要求在MSSQL中使用“查询分析器”时,他感到震惊!