Persistence : A save system for all your datas

Discussion in 'WIP and Development Status' started by NathanWolf, Jan 31, 2011.

Thread Status:
Not open for further replies.
  1. Offline


    Hey everyone, I just came here to plug a plugin I'm working on, Persistence.

    The idea is to provide an easy-to-use object-oriented persistence engine for Bukkit plugins.

    If you're familiar with Hibernate-db or quickdb, this aims to be a bit like those, but simpler (and less powerful).

    It's easy to persist any class that you have control over- you just need to add a few Java annotations, then you can call Persistences' get() and set() methods to store and retrieve instances of your object.

    For now, SQLLite is the only supported data storage mechanism, but the data store system is written to be extensible. A MySQL store could be added very easily, other stores could be done as well.

    Objects that reference other objects are supported, as are List<>'s. Persistence is completely type-safe, so you never have to do any casting, deal with raw Objects, or call getInteger() type functions. You just use your Java classes, exactly like you're used to doing.

    Please check out the thread if this sounds like something you'd be interested in. You can also check out the roadmap on github to see what I'm working on currently- it's very much a W.I.P, but it's getting to be very useable, and now would be a great time for suggestions or feedback.

    Thanks for your time!
  2. Offline


    Sorry to be a pest, but I have a question about the "less powerful" bit. I am wondering what sort of "common" features you have no plans on implementing.
  3. Offline


    Well, Hm- I guess I'm not sure. I don't really plan on supporting persisting HashMaps, unless someone really needs it. My feeling is you can just populate one from a list in the setter... but I may change my mind, depending on use cases. It'll probably get implemented eventually, really :)

    I guess what I meant is that Hibernate in particular is very complex, with lots of different annotations for managing the table structure- I don't really plan on any of that.

    Mainly, I'm trying to keep it simple- I don't really want it to be less powerful, necessarily :)

    I plan on fully supporting complex object graph persistence, which is basically the core of both of those libraries- the rest is just details.

    Also, I could be mistaken, but I don't think Hibernate or quickdb really deal with schema creation- Persistence makes the assumption that you're starting with an empty database, and creates everything for you. So, I guess in one way at least, Persistence is "more powerful" than those libraries. Anyway, forgive me Hibernate fans if I'm mistaken about that.

    Feel free to ask specific questions- is there something specifically you're interested in Persistence supporting?
  4. Offline


    Sadly most of my database experience is with my tinkering with pylons/sqlalchemy and django, so I am not positive on the right questions to ask or if the answer well be "well duh, I said so in the OP!" :p

    I'm mostly wondering on things like:
    will many to many relationships be supported,

    basic queries like (making up syntax here) player = persistance.obtain("players").where("player").equals("croxis);

    or searches like recentPlayers = persistence.obtain("players").where("lastlogin").between(yesterday, now).findAll();

    Apologies if you actually have stated this. I'm still learning the database lingo.

    On a tangent: Are/can databases be shared or are they separated by plugin?
  5. Offline


    The first thing to realize is that, by default, Persistence caches all of your entities in memory. So, the first time you ask for an entity, say

    User nathan = persistence.get("NathanWolf", User.class);
    Instead of doing a "select * from player where id = 'NathanWolf'", it just does a "select * from player" (basically), caching all of the results.

    It then looks up the one you asked for from the in-memory cache based on the id ("NathanWolf" in this case), and returns it.

    The next time you ask for a User, it won't do a query. It won't touch the db again until a save() or reload() is issued.

    Using the console UI, you could accomplish what you ask above with "/persist list classes.player.NathanWolf"- this would list all of the player field values for NathanWolf- such as the last time I logged in, etc (these examples are all from my Classes plugin...).

    Does that make sense?

    Basically, I'm trying to avoid plugins ever having to write code that uses SQL directly. For one thing, Persistence supports non-SQL data stores (at least, in theory, at an API level) - so keeping the SQL hidden is a fairly major priority.

    For cached entities, the best way to do this would be to just use getAll(), and then iterate through the list and pick out the ones you want.

    For un-cached entities, something I plan on supporting in the future, there would be a query interface where you could do this sort of thing, and it would do a live SQL query for the results, returning a list.

    However, I think that the cached solution will work for the majority of plugins- something like Big Brother would probably need an uncached solution, but if you're just managing a bit of data it shouldn't be a memory issue.

    No problem, it's complicated stuff- I hope to make it easier.

    Great question!

    Databases are separated by schema, which you define in each persisted class.

    Most likely, this translates into "one db per plugin"- that's how I would use it, anyway, unless you have a very complex plugin that requires multiple distinct parts. You can see in the examples I gave from Classes I use "classes".

    My personal preference is for lower-case schema and table names, and singular table names (so, "player" instead of "players"). I don't really enforce anything like that (yet?), though.

    So, you don't have to make it match your plugin name- for instance, the Persistence plugin itself registers some things in a "global" schema.

    This makes it difficult to do cross-schema joins, but for now that's a sacrifice I'm willing to make. I didn't like the idea of one plugin's data bloat killing another plugin's data store. I'm willing to explore other options, or make it configurable.

    If they were all stored in the same db, I'd have to make the table names dotted or something to avoid name collisions, though.
  6. Offline


    Reason I ask on the plugin aspect is situations such as supporting economy plugins. I know of at least three base economy plugins and supporting them all in code risks getting fairly nasty. However, if there was just one Player table in just one db, and all base econ plugins use a column called "money" in the player table, then I can integrate economy into my plugin without trying to juggle and keep up with a handful of economy plugins.
  7. Offline


    Right, that's a wonderful idea- if they all used Persistence, that would be easy (theoretically).

    Though, to really be safe, they'd probably all need to move their common DAO objects (like "money") into a shared library somewhere- so that one person doesn't change it in a way that makes it incompatible with the other plugins.

    However, that wouldn't strictly speaking be necessary- if they all used their own objects, but had them marked up exactly the same way (same name, schema, fields and types) - it would work fine. Actually, types are somewhat irrelevant for the time being since SqlLite isn't typed- though I try to ignore that fact in my code :)
Thread Status:
Not open for further replies.

Share This Page