将 SQL 与 Java 代码分离
Posted
技术标签:
【中文标题】将 SQL 与 Java 代码分离【英文标题】:Separating SQL from the Java Code 【发布时间】:2012-06-03 18:45:25 【问题描述】:这是我必须连接数据库时经常遇到的问题;如何将 SQL 与普通的 java 代码分开?我通常为数据库连接使用单独的类,但是,当您有多个数据库和每个数据库中的多个表时,总是很难做到 100%
例如,如果我们想将所有 java SQL 放在一个名为 DBConnector.java 的类中,我们如何为不同的插入、删除、数据检索等进行通用编码?我认为理想情况是所有 SQL 语句都应该在同一个类中,并且应该与数据库应用程序范围内的不同风格的相同操作兼容,从而提供与其余代码的逻辑分离。
public void insertData (String db, String table, <Whatever Fields to be Inserted>)
//generic SQL INSERT statement and execution
public ResultSet retrieveData (String db, String table, <Whatever Fields Relevant>)
//generic retrieval of data
有没有办法做到这一点?还是我们应该只为不同风格的插入、查询等添加功能?
谢谢!
【问题讨论】:
【参考方案1】:如果您想要一个健全的架构,您至少需要几层来分离关注点。
首先,从模型类开始(大多数情况下,您需要为数据库中的每个表创建一个)。自己编写它们,或者使用 ORM(例如 EclipseLink、Hibernate)自动生成它们。这些应该是 POJO(普通旧 Java 对象),这意味着它们是具有属性的 simple
对象(例如,字符串类型的 Name
、整数类型的 Id
等)。您的模型对象应该是数据的载体,仅此而已(当然没有逻辑或处理)。
然后,为所有模型类创建 DAO(数据访问对象)(如果需要,您可以构建一个 GenericDao 类来继承)。在这里,您将通过将 model 对象作为参数的方法提供 CRUD 操作(插入、更新、删除)。这是特定于数据库后端的,尽管您可以根据需要插入与数据库无关的 DAO 层。
第三,每个逻辑类组有一个 service 或 manager 层(这是所有前端和控制器代码都应该与所有想要的功能对话的层)。一个典型的方法可以称为registerCustomer(...)
(可能使用不同的 DAO 类)。或findCustomerByName()
等。
以这种方式构建您的应用程序称为MVC
(模型 - 视图 - 控制器),因此如果您想了解更多信息,请在 Google 上使用该术语。
这样,您通常不会有高于 DAO 层的 SQL 查询,这意味着您的应用程序 a) 可维护 b) 以后更容易更改后端。
【讨论】:
感谢您提供一般而详细的答案。我正在寻找独立于技术的解决方案。【参考方案2】:伊扎, 这里有关于将 SQL 与 Java 代码分离的讨论:Java - Storing SQL statements in an external file 您的解决方案是可以理解的,但是如果查询不是标准的(例如,不仅仅是 a = 10 的位置,而是包含在 (...) 或 group by 中,所以我建议您避免使用它。 当您在 Java 中使用 DB 时,为了最大限度地减少样板代码,您应该使用 Spring JDBC。你也可以使用 Hibernate,如果它在你的情况下是可以接受的,它可以让你避免一些 sql 的使用。
【讨论】:
【参考方案3】:最好的方法是使用Hibernate,它现在是行业标准。
简而言之,它生成所需的 SQL,代码处理表示行的 java 对象。如果您调用 setter,Hibernate 会计算出完成更新所需的 SQL。
对于 getter,您的代码可能如下所示:
shoppingCart.getCustomer().getCountry().getCode();
Hibernate 计算出通过customer
表从shopping_cart
表到country
表所需的SQL 连接。
它真的很棒,值得过渡。
【讨论】:
我不会这么直截了当地说 Hibernate 是 最佳 选项。例如,MyBatis 是这个问题的轻量级替代方案,它以更快、更容易理解(更不用说幕后“魔术”)的方式解决了这个问题。 这不是问题的答案,向想编写 SQL 的人推荐 ORM 就像在有人寻求如何烘焙蛋糕的帮助时告诉他们买蛋糕。 是的,例如,我正在做一个课堂项目。如果我提交 Hibernate 代码而不是 PreparedStatements,我肯定会得到一个 F. @michael 我不知道。使用标准库是正常且最好的方法。除非您被告知不允许使用特定资源,否则您应该按照行业的做法行事。 @Bohemian 很遗憾,这是一个 SQL 类。【参考方案4】:你应该使用一些DAOFactory
,这个类用于获取连接。
为了反映数据库中的表,您应该创建代表实体的DTO - Data Tranfer Objects
。因此,如果您有表User
,只需创建带有属性、getter 和 setter 的UserDTO.java
。与数据库通信的类是DAO - Data Access Object
。您应该只在此处创建用于从数据库中获取数据的 SQL 语句和方法。 首先是精心设计的结构。这样您的代码就会变得更干净、更快速、更安全。我建议您创建自己的ORM
。
所以,看看不同的框架并进行一些测试
EasyORM
double count = 0;
TransDB trans = new TransDB() ;
List<Trans> list = new ArrayList<Trans>();
list = trans.getAll();
for (Trans element : list)
count+= element.getData();
...
休眠
double count = 0;
Session session = null;
List<Trans> list = new ArrayList<Trans>();
list = HibernateUtil.getSessionFactory().openSession();
list = (List<Trans>) session
.createQuery("from Trans").list();
for (Trans element : list)
count += element.getData().doubleValue();
...
然后比较??
评估(以毫秒为单位)
EasyORM: mysql:初始化 - 6344,平均 - 4868 MS SQL:初始化 - 8126,平均 - 6752
休眠: MySQL:初始化 - 27406,平均 - 23728 MS SQL:初始化 - 28605(+250%),平均 - 24912
所以你自己的ORM
实际上是从SQL script
生成的,比Hibernate(到10)要快,为什么?通过在层间插入肯定不能去提高吞吐量。这只是一项测试,我还有其他测试。
所以对我来说,我建议您创建自己的ORM
,这里还有一些缺点,例如时间消耗或使用有问题的更改DMS
,但作为对生成命令的完全控制的优势,您可以使用特定于特定DMS
的功能(ORDM、特殊命令等)。所以我不认为Hibernate
是最好的,真的不是。
【讨论】:
don't use automated frameworks as Hibernate
- 对不起,这个说法是错误的。阅读一些关于 MyBatis 的内容(例如)。基本上,它是一个 SQL 模板引擎。所以,就像在 JSP 中一样,你创建一个视图,并将变量传递给它,你创建 MyBatis “SQL 模板”,并将变量传递给它们。非常轻巧有效。另外我敢肯定还有其他类似的解决方案。
但我仍然坚持认为你的 owm ORM 比 Hibernate ok EclipseLink 快得多,所以我不知道为什么我的帖子在真实时被否决(除了我编辑的错误,抱歉) 我认为首先是你的 IS 的性能和速度。
不,性能和速度不是重中之重。牺牲一些性能是值得的,以防它使您的代码更具可读性和组织性 - 这会导致未来的错误和拼写错误更少。当然,编写自己的 DAO 层很简洁,但每次你必须用一些新方法扩展它时,你会因为这个决定而讨厌自己。以上是关于将 SQL 与 Java 代码分离的主要内容,如果未能解决你的问题,请参考以下文章