什么是构建数据库管理Java应用程序的正确方式?

huangapple go评论82阅读模式
英文:

What is the correct way to structure a Database Management Java application?

问题

首先,如果我听起来不太连贯,请原谅,因为我还是个初学者,不太确定如何表达一些事情。

我正在使用JavaFX和SQLite创建图书馆管理系统。我已经熟悉了Java中如何处理SQL查询,并且我的应用程序是可用的。然而,我现在正在重新构建这个应用程序,使其遵循面向对象编程原则。我的问题与涉及查询数据库的方法有关。

在普通的应用程序中,我认为我会将这些方法写在相关的类中 - 比如,一个查看图书信息的方法会包含在“图书”类中。但在这里,这将涉及创建新的数据库连接或在各处传递当前连接,我的直觉告诉我这不是正确的做法。我应该单独创建一个类来存储连接并处理所有的数据库操作吗?在这方面应该采取什么正确的方法?

英文:

Firstly, forgive me if I don't sound coherent as I am still a beginner and not quite certain how to word some of these things.

I am creating a Library Management system in JavaFX using SQLite for the database. I have familiarised myself with how SQL queries are handled in Java and my application is functional. However, I am now restructuring the application to make it follow OOP principles. My question is in regard to what approach I should take with methods that involve querying the database.

In an ordinary application, I think I would write these methods in the relevant Class - say, for instance, a method to view information on a book would be contained in the "Book" class. But here that would involve creating a new database connection or passing around the current one, and my gut tells me this isn't the right way to do it. Should I instead have a separate class to store the connection and also handle all database operations? What is the correct way to go about this?

答案1

得分: 1

问题在于,关系型表格与对象之间的映射并不好。如何将以下 SQL 查询转换为对象呢?

SELECT author.name, book.title,
book.lang = author.native_tongue AS nativeWritten
FROM book LEFT JOIN author ON author.id = book.author;

它无法直接转换为对象。

如果你想放弃在所有地方或至少在大多数地方使用 SQL 的强大功能,基本上只想执行类似于 SELECT * FROM book WHERE unid = 1; 这样的操作,而不做更多深入的事情,你可以做一个简单的过度简化,即有一个类型为 Book 的类,它同时对应于 book 表,并且可以合理地封装所有涉及书籍的数据库操作。好吧,你可以重新发明轮子,重新编写所有 JPA/Hibernate 的内容,或者你可以直接使用它们。

或者,你可以考虑使用 JDBI 或 JOOQ,它们不坚持 "数据库中的表格等于 Java 中的类" 这一观念,更加注重 SQL。这些框架都有各种教程和指南,可以精确地展示如何使用它们。

如果你真的坚持要重新发明这个轮子:在各个地方传递连接对象并不是不合理的。这是执行所述任务所需的。类似于:

public static Book getById(Connection db, int unid) throws SQLException { ... }

是一种方式。一个稍微复杂一些,对于测试更加方便的方式是:

public class DbBridge {
    public Book getById(int unid) throws SQLException { ... }
}

它允许你抽象出如何执行该任务,但是... 这意味着你需要在各处传递一个 DbBridge 对象。

"我有这个有些复杂、有状态的概念,我在很多地方都需要它,它几乎就像是一个配置",这是一个常见的问题。这正是诸如 Dagger 等 "依赖注入" 框架试图解决的问题。你可以选择重新发明这个轮子,或者只选择其中一个。如果你想重新发明,好吧,先看看这些项目的工作原理,这样你就能了解有哪些解决方案可用。

附注:如果你之所以选择 SQLite 是因为它很 "轻量级",那么事实并非如此。至少从 Java 的角度来看是这样的:你需要一个本地可执行文件才能使用它。一个更简单、更轻量级的方法是使用基于 Java 的文件型数据库引擎,如 H2 或 JavaDB。只有在需要从非 Java 应用程序访问该数据库,或者你几乎被迫这样做(例如,因为你正在编写 Android 应用程序)时,才使用 Java 中的 SQLite。从 Java 的角度来看,复杂性上,SQLite 和一个完整的 PostgreSQL 或其他类似数据库一样复杂。

英文:

The problem is, relational tables don't map well to objects. How does:

SELECT author.name, book.title,
book.lang = author.native_tongue AS nativeWritten
FROM book LEFT JOIN author ON author.id = book.author;

translate to objects?

It doesn't.

If you want to forego the power of SQL everywhere, or at least in most places, and basically do SELECT * FROM book WHERE unid = 1; and not go much further, you can make the trite oversimplification that there is a class of type Book and it matches both the book table and can reasonably encapsulate all the things you might want to do to the DB that involve books at all, okay, well, you could re-invent the wheel and rewrite all of JPA/Hibernate, or you just use that.

Alternatively, you should look into JDBI or JOOQ which forego the idea that 'table in db == class in java', and are more SQL oriented. These have all sorts of tutorials and guides to show you exactly how to use them.

If you really are insistent on reinventing this wheel: Passing a connection object around is not crazy. It's what is needed to perform the stated task. Something like:

public static Book getById(Connection db, int unid) throws SQLException { ... }

is one way. A slightly more involved way that makes life easier for testing would be something like:

public class DbBridge {
    public Book getById(int unid) throws SQLException { ... }
}

lets you abstract the notion of how to do the job, but.. then it means you're passing a DbBridge object around to everything.

The general principle of 'I have this somewhat complicated, stateful concept that I need in a ton of places, it's almost like a configuration' is a common problem. It is what 'dependency injection' frameworks such as dagger are trying to solve. You can either reinvent that wheel too, or just one of them. If you want to reinvent, well, have a look at how those projects work so you have an idea of what solutions are available.

NB: If you chose SQLite because it's 'lite', it's not. Not from the java perspective: You need a native executable to use it. A muuch simpler and lighter approach is to use a java-native file-based db engine such as H2 or JavaDB. Only use SQLite from java if you need that db to be accessible from non-java applications, or you're more or less forced into it, e.g. because you're writing android apps. Complexity-wise, SQLite is about as complicated as a full blown postgres or whatnot, from the java perspective.

huangapple
  • 本文由 发表于 2020年10月5日 08:25:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/64201116.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定