Yes, but only if we are going to use a JPA provider. Bukkit used Ebean, which had EbeanServer instead of EntityManager.
After thinking about it, I have to ask: Why don’t we just put this into a plugin? Actually there is no need to bundle it with Sponge, and plugins can still require the Persistence Plugin to be installed…
The advantage of having it in sponge is that you only need to configure your database connection once in the sponge config. Otherwise your config is distributed over multiple config files. Also devs don’t have to care about where the database comes from, all is nicely abstracted.
That’s why I suggest that sponge should provide an API to fetch a DB connection. The advantage of using JPA would be that sponge can always change the provider without changing the API.
Some kind of core module providing that could also work, but then why not directly include it?
I think what some people are missing is that the problem - storage of object-oriented-data in a relational way - is not (yet) solved in Java and in object-oriented programming in general. The inclusion of Ebeans in Bukkit might have given the false impression that such a solution exists, however this is not the case. There are various attempts, but each has its own advantages and disadvantages:
ORMs (like Hibernate, the already mentioned ORMLite or Ebeans) try to solve the transition by handling the ‘conversion’ between both worlds internally. Users have no control over the database layout or the mapping, except the configuration allowed by the library. With JPA Java provides a standardisation for these configurations, but it depends on the ORM how well JPA is supported or if it is supported at all.
There has been written a lot (like really A LOT) on ORMs and whether they are a solution or just make things worse and I do not claim to have any better insight than others who have worked on the problem. That said, ORMs try to be data-centric, meaning the focus lies on the object-oriented-data-structure. The database is essentially hidden to the developer as every access is handled by the ORM. This can be problematic because you cannot control (and optimize) the queries send to the database. Any optimizations on the database-side (indexes, database-layout…) must be done with the ORMs internal logic in mind that might not be as straight forward as expected.
JDBC (and tools like JOOQ or MyBatis) take the opposite approach. The ‘conversion’ between both worlds is left to the developer as the approach is SQL-centric. Since the developer writes plain SQL, he has access to every function the database (and the JDBC driver) offers. This is the major difference to ORMs: the database is not hidden but directly accessed. Nearly anything is controlled by the developer (database-layout, optimisation of queries, indexes…) and can be changed as needed. Naturally this also means that developers need to put work into writing the database-layer itself, testing and optimising it (plus manage changes to the database layout that may arise when the application matures).
For JOOQ (or MyBatis) it should be mentioned that these tools follow the same SQL-centric thinking: They work on top of JDBC but hide some of the ugly parts behind APIs to ease the life of the developer, e.g. JOOQ provides fluent-builders for queries and type-safety which simplify writing the database-layer a lot.
NoSQL is jet another approach. Instead of trying to solve the ‘conversion’ the data is stored in an object-oriented way so there is no longer a need for a conversion. The problem is that most of the tasks a relational database can handle are only possible due to the relational storage (think of indexes as an example). I do not have much experience as I always needed a relational storage, but as before there are lots and lots of discussions about the pros and cons compared to relational storage - this stackoverflow-answer and the links at the bottom might give you an idea.
The bottom line is that it is not quit clear what the perfect solution is. All of the described ways are used and can be considered established, but each has its own advantages and disadvantages. What’s actually the best way for an individual application (of, for that matter, plugin) depends greatly on multiple factors, from the data that’s stored, over the way the data is accessed, to the needed scalability and the developer’s personal experience.
In my eyes, it would not make much sense to include some type of ‘official’ database support into Sponge as there is no way to know what an individual plugin might need, there not a solution that ‘fits them all’.
That’s why I suggest to have one API to fetch a JDBC Connection for low level access (maybe combined with JOOQ to switch providers) and a JPA EntityManager for developers that need persistence but don’t want to write fancy DAOs. I wouldn’t even use JPA for real ORM, object mapping without relations is already a huge help. The only reason for an NoSQL DB I see is due to performance, if a plugin needs a NoSQL DB it should set it up by itself, no API needed (no way to switch providers, heavily depends on DB used).
On topic, an ideal way to handle persistence would be a single database interface that a plugin, or entire server implementation could implement with any database they choose. This way, the only limit on what persistence backends are available would be the limits of the programmer’s skill.
There’s only one real interface and that is the Java Persistence API. SQL can be made somewhat implementation independent via JOOQ (or similar) and I have yet to see a NoSQL interface that is compatible and still useful.
Expecting plugins to work with any kind of JDBC connection is problematic because different databases provide different features a developer might want to use. They even expect a different SQL syntax sometimes (e.g. I had [problems][1] with nested JOINs on SQLIte and MySQL in the past). A developer that uses a central JDBC connection would be expected to test his database layer against all of the supported databases, and maybe he even might be expected to things differently for different databases (say because he can shift some work over to the database when using H2, but must do it by himself when using SQLite), so a way to get the used database type would be needed too.
This also applies for tools like JOOQ: While a general abstraction is provided, if you support multiple databases you must make sure that the written code works for all off the supported databases. Once again, this can be done (I do it right now in MyWarp) but you need to know what you are doing and test things carefully.
JPA (or any ORM) does not have this problem as the database is hidden completely, but as noted above that comes at the cost that you have no longer any access to the databases logic.
[1]: http://stackoverflow.com/q/23964972/1692291
@sk89q I made a PoC for JPA integration to see if this would work without a persistence.xml. I am using eclipselink with mysql underneath.
You can find the Demo i.e. Test class here. Currently everything that would need to be in the
config is hardcoded, but eclipselink can be persuaded to work without a persistence.xml.
Since only JPA interfaces are presented, one could easily implement another JPAProvider using
hibernate or some other JPA implementation as well as switching the underlying database.
Before anyone complains that it is hackish or looks ugly, it’s just a PoC.
IMHO this is much easier than handling actual JDBC connections and might be easier for devs that are just starting as well as devs that don’t want to handle everything themselves. But we should probably provide another service that exposes a more raw access to the database.
We need to bumb this up I guess! I am still waiting on what we are going to use. I would like to avoid shading libraries. Personally I like Jooq in combination with javax.persistence.