A zero ceremony ORM for Java

Overview

Release notes

Welcome

Persism is a wood simple, auto discovery, auto configuration, and convention over configuration ORM (Object Relational Mapping) library for Java.

<dependency>
    <groupId>io.github.sproket</groupId>
    <artifactId>persism</artifactId>
    <version>1.0.2</version>
</dependency>

Simple

The API for Persism is small. Mostly you just need a Connection and a persism Session object and you're good to go. There are some optional annotations and a Persistable implementation for where you need to track changes to properties for UPDATE statements.

Auto-Discovery

Persism figures things out for you. Create a table, write a JavaBean, run a query. Persism uses simple mapping rules to find your table and column names and only requires an annotation where it can’t find a match.

Convention over configuration

Persism requires no special configuration. Drop the JAR into your project and go.

Persism has annotations though they are only needed where something is outside the conventions. In most cases you probably don't even need them.

Persism can usually detect the table and column mappings for you including primary/generated keys and columns with defaults.

Smart

Persism will do the correct thing by default. Persism understands that your class is called Customer and your table is called CUSTOMERS. It understands that your table column is CUSTOMER_ID and your property is customerId. Persism gets it. Heck Persism even understands when your class is called Category and your table is called CATEGORIES. No problem. Don’t even bother annotating that stuff. Persism uses annotations as a fall back – annotate only when something is outside the conventions.

Tiny

Persism is under 60k. Yeah, fit it on a floppy if you want. Persism has Zero dependencies however it will utilize logging based on whatever is available at runtime - SLF4J, LOG4J or JUL.

Have a look here for the getting started guide, code coverage and Javadoc

Compile

To run tests only basic tests: in memory databases (H2, HSSQL, Derby) + sqlite (faster)

mvn clean test

To run basic tests + testContainers based tests (postgresql, mysql, mariadb, firebird). Need docker installed.

mvn clean test -P include-test-containers-db

To run tests for every supported database. Needs Oracle up and running

mvn clean test -P all-db

To generate surefire reports with every database but Oracle (in target/site/surefire-report.html)

mvn clean test surefire-report:report -P include-test-containers-db

Thanks!

Comments
  • Session-creation not possible with container-managed DataSource

    Session-creation not possible with container-managed DataSource

    I'm trying to use Persism with a DataSource managed by Payara (Glassfish): Session session = new Session(dataSource.getConnection()); I'm getting a NPE in this scenario :-(:

    java.lang.NullPointerException
    	at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936)
    	at net.sf.persism.MetaData.getInstance(MetaData.java:79)
    	at net.sf.persism.Session.init(Session.java:61)
    	at net.sf.persism.Session.<init>(Session.java:40)
            at ....
    

    The reason for this is in the MetaData-class, that wants to use the URL as a key in the HashMap of Persism-MetaData:

       static synchronized MetaData getInstance(Connection con) throws SQLException {
    
            String url = con.getMetaData().getURL();
            if (metaData.get(url) == null) {
                metaData.put(url, new MetaData(con));
            }
            log.debug("MetaData getting instance " + url);
            return metaData.get(url);
        }
    

    The use of getURL() is unfortunate, as the JDBC-Doc in DatabaseMetaData states that this value might be null -- and for my DataSource it seems to be the case :-( ...

        /**
         * Retrieves the URL for this DBMS.
         *
         * @return the URL for this DBMS or <code>null</code> if it cannot be
         *          generated
         * @exception SQLException if a database access error occurs
         */
        String getURL() throws SQLException;
    

    Even there's another place where the URL will bite back: it's the ConnectionTypes.get()-method which will return null, and lead to funny NPEs in other places later on.

    I browsed through DatabaseMetaData and Connection, but I couldn't find a suitable alternative as an identifier for a connection. I've use Connection.getCatalog() in other cases if I need some identifier for a database, but only for informative user display, and it's local to a single database and might be null, too. So this will not work as a general solution to fix this problem.

    I propose two things:

    • provide a new Session-constructor with an extra argument used as connection-id. The current constructor can chain to this constructor and use DatabaseMetaData.getURL() as default value.
    • change the get-factory-method in ConnectionTypes to use DatabaseMetaData.getDatabaseProductName() (or getDriverName()?), maybe keeping the current implementation as a fallback until the new way is stable. [Actually I would prefer having the database-product be flexibly configurable somewhere -- we had the Informix question before, and currently there's no way to add a new database product without modifying the library itself.]

    If you say that looks like a reasonable way to go, I could see if I manage to fork the project and prepare a pull request.

    opened by dstango 41
  • Oracle JDBC drivers have new groupIds and artifactIds

    Oracle JDBC drivers have new groupIds and artifactIds

    The Oracle JDBC drivers have been updated and published to Maven Central since September 2019 starting with version 19.6.0.0. The new coordinates use com.oracle.database.jdbc as base gorupId

    https://mvnrepository.com/artifact/com.oracle.database.jdbc

    opened by aalmiray 5
  • Failure in TestMetaData

    Failure in TestMetaData

    Running TestMetaData results in a failure:

    -------------------------------------------------------------------------------
    Test set: net.sf.persism.TestMetaData
    -------------------------------------------------------------------------------
    Tests run: 4, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.02 s <<< FAILURE! - in net.sf.persism.TestMetaData
    net.sf.persism.TestMetaData.testGuessing  Time elapsed: 0.009 s  <<< FAILURE!
    junit.framework.ComparisonFailure: Message s/b 'Could not determine a table for type: net.sf.persism.TestDerby Guesses were: [TestDerby, TestDerbies, Test Derby, Test_Derby, Test Derbies, Test_Derbies] and we found multiple matching tables: [TEST_DERBY, TESTDERBY]' expected:<...rbies, Test_Derbies][ and we found multiple matching tables: [TEST_DERBY, TESTDERBY]]> but was:<...rbies, Test_Derbies][]>
    	at net.sf.persism.TestMetaData.testGuessing(TestMetaData.java:70)
    

    The test seems to assume the existence of two tables in the Derby-database: TEST_DERBY and TESTDERBY. Maybe you somehow created them a long time ago manually.

            try {
                session.insert(new TestDerby());
            } catch (PersismException e) {
                failed = true;
                assertEquals("Message s/b 'Could not determine a table for type: net.sf.persism.TestDerby Guesses were: [TestDerby, TestDerbies, Test Derby, Test_Derby, Test Derbies, Test_Derbies] and we found multiple matching tables: [TEST_DERBY, TESTDERBY]'",
                        "Could not determine a table for type: net.sf.persism.TestDerby Guesses were: [TestDerby, TestDerbies, Test Derby, Test_Derby, Test Derbies, Test_Derbies] and we found multiple matching tables: [TEST_DERBY, TESTDERBY]",
                        e.getMessage());
            }
    

    Easiest solution seems to be to create the required tables in the test:

    diff --git a/test/net/sf/persism/TestMetaData.java b/test/net/sf/persism/TestMetaData.java
    index 105fc69..cbb9fe7 100644
    --- a/test/net/sf/persism/TestMetaData.java
    +++ b/test/net/sf/persism/TestMetaData.java
    @@ -41,0 +42 @@
    +        createTables();
    @@ -43,0 +45,8 @@
    +    private void createTables() {
    +        if (!UtilsForTests.isTableInDatabase("TEST_DERBY", con)) {
    +            session.execute("CREATE TABLE TEST_DERBY (X INTEGER)");
    +        }
    +        if (!UtilsForTests.isTableInDatabase("TESTDERBY", con)) {
    +            session.execute("CREATE TABLE TESTDERBY (X INTEGER)");
    +        }
    +    }
    

    This makes the test pass for me.

    opened by dstango 4
  • Test containers

    Test containers

    My original idea was to make another totally unrelated change. But I saw I could not run most test without installing every engine manually, and I didn't like the idea.

    I found this wonderful project TestContainers, used for other persistence libraries. Basically it automatically starts and stops an instance of a docker virtual machine with whatever database you need. I'm not docker-savvy, but it worked with docker for windows, instructions were pretty clear and so I give it a try. And it worked.

    You still need to install docker (for windows if that's your OS), but it's waaaay less work than installing 5 database engines.

    The first time a test for a specific database runs it need to download the full image and that make take some time, but after that it reuses the same image and they are pretty fast.

    161 tests run in 300 seconds on my laptop

    What I did:

    I migrated all tests to junit4, since is the minimal version supported by testContainers I separated the tests in 3 categories

    • The quick tests that run in memory databases plus sqlite. I didn't touch them, they don't need to be installed.
    • The TestContainerDB category that run using test containers and cover almost every other database.
    • The ExternalDB category that runs with a working external DB. The only class left in that category is TestOracle, because I couldn't make it work.

    You can choose what category to run from command line, I wrote the instructions in the readme.md file.

    I refactored the tests one by one, using TestContainers docker based databased and most test worked after a few changes

    The changes

    • MySql tables and columns are case sensitive or not depending on the file system. In Windows they are case insensitive, in linux (like docker images) are case sensitive. I edited your script for creating tables for MySql, basically making all tables names PascalCase.
    • There was a bug in the method UtilsForTests.isProcedureInDatabase, fixed.
    • I needed to separate the two MSSQL tests in two classes, on for the MS driver, one for the jtds driver.
    • jtds returned a null clob when there was null data! A simple if solved the problem.
    • In some cases the insert call to executeUpdate throw an exception! Something like "there is a record and should not be". I solved it by changing from executeUpdate to execute.
    • executeCommand methods in BaseTest are now static because I needed them.
    • TestContainers database are empty, in order to run tests that included Pubs or Northwind databases I needed to create them first, and then reverse engineer your extra columns.
    • In some cases I was able to create the tables just once (and make them faster), in other cases I needed to recreate them on every test method.

    Finally I don't know If I broke oracle, I find no way to test it.

    I think there is still room for improvement:

    • Every TestContainer DB starts form zero, so there is no need to clean up anything. That may speed things up.
    • If all tests inside a class can run without restarting the database, it will be faster.
    • Probably the logging of every creation statement is slowing down the whole thing.
    • Maybe create a basic battery of tests for every engine using Pubs and Northwind, and then add specific tests for the non-standard dataypes?
    • there is a lot of copy/paste between Test clases, could be removed.
    • Every once in a while a got an OOM, or a "The forked VM terminated without properly saying goodbye. VM crash or System.exit called?" message. I think I'm killing my machine by starting/stopping multiple database engines, but maybe there is something else.

    Anyway, let me know what you think, and please try in you machine!

    PS: Persism.iml files, and the whole folders .idea and target should be included in .gitignore. There are not needed because idea regenerated them on demand, and are filesystem dependent. I didn't change them because I didn't want to make more changes in the PR.

    Again, let me know what you think!

    opened by pablogrisafi1975 4
  • Projections

    Projections

    I don't know whether this is implemented or not, but I haven't found the way. I have an object whose name is Movie and also a moviesList. I know I can fetch a list of these movies and , of course, a single movie object. But what I don't know is how to get a list of the movies ids.

    Example: Table movies( int id , String title), ...... I don't want a list of movies with ALL their fields, nor a single movie object. I want a list that ONLY consists of the ids of these movies and for the other fields, filled with their default values. Is that possible?. I can load all the objects and afterwards, map these objects to their ids, but I'd like to avoid loading everything.

    I've tried the following but is not working: List<Movie> moviesIdsList = session.query(Movie.class, sql("SELECT id FROM Movies")); It says the object movie was not properly initialized. I though the object would be initialized with default values or something like that. Can you help me?

    opened by vicenrico 3
  • Maybe the method Types.isCountable is wrong?

    Maybe the method Types.isCountable is wrong?

    Describe the bug Maybe the method Types.isCountable is wrong?

    The code is :

        public boolean isCountable() {
            return this == IntegerType || this == integerType || this == LongType || this == longType || this == byteType || this == ByteType
                    || this == ShortType || this == shortType || this == DoubleType || this == doubleType || this == BigDecimalType;
        }
    

    DoubleType, doubleType and BigDecimalType seem to be included by mistake , and BigInteger seems to be missing.

    Of course, maybe you have your reasons, but in that case please write them.

    Thanks for this project! Great idea and compact implementation!

    opened by pablogrisafi1975 3
  • Add support for schema names with table names

    Add support for schema names with table names

    We should have support to include the schema name as well as the table name when generating or using SQL.

    e,g,

    SELECT [identity], [First Name], [Last Name], [ContactName] FROM [Contacts]

    s.b.

    SELECT [identity], [First Name], [Last Name], [ContactName] FROM [dbo].[Contacts]

    It is possible to have access to a DB where you would have multiple schema names. Currently Persism fails to find them.

    It is also possible that a DB has multiple schemas with tables with the same name. Need to be able to handle that situation.

    enhancement 
    opened by sproket 2
  • Improve signature of insert-Method

    Improve signature of insert-Method

    The signature of the insert-Method currently reads:

    public <T> Result<T> insert(Object object) throws PersismException

    The type parameter T is rather useless this way. It should read:

    public <T> Result<T> insert(T object) throws PersismException

    enhancement 
    opened by dstango 2
  • Add support for Views

    Add support for Views

    Views have some advantages if Persism can use them directly. Namely we can cache the meta-data for better performance and do better type checking.

    Add Annotation for View to work like Table.

    enhancement 
    opened by sproket 2
  • query() forces classname to match tablename

    query() forces classname to match tablename

    Yesterday I ran into an - at first sight - obscure problem with the query()-method. Digging into it revealed what's going an.

    The following query:

    List<UnknownTable> l = session.query(UnknownTable.class,
    "SELECT LIMIT 10 personalnr, bewerbernr, nlcode FROM mitarbeiter WHERE austrittsdatum < MDY(1,1,2018)");
    

    results in an exception, unless the the database has a matching table name for "unknowntable":

    net.sf.persism.PersismException: Could not determine a table for type: de.test.dali.persistence.UnknownTable Guesses were: [UnknownTable, UnknownTables, Unknown Table, Unknown_Table, Unknown Tables, Unknown_Tables]
    

    If there is actually a table for "UnknownTable" the error message gets more obscure (as it was for us yesterday) - imagine you do a query with the parameter Bewerber.class and there actually is a table in the database with the same name:

    net.sf.persism.PersismException: Object class de.test.dali.persistence.Bewerber was not properly initialized. Some properties not initialized by the queried columns: [bewerbernr, nlcode] Missing:[nl_code]
    

    I didn't try it with joins, but I guess it will cause similar problems.

    So what's would be expected behaviour:

    • at least an error message stating something like "Class name (or @Table annotation) needs to match the queried tabled" -- especially the second case left us totally clueless yesterday ...
    • but better: no error message but simply delivering the results of the query, independent of a match of the table name.

    I think the meachanism to match table names to class names (or @Table annotations) is useful for CRUD of individual records -- but with a free query this should not be constraining the classes that can be used.

    opened by dstango 2
  • Is there any easier option to update an object in a

    Is there any easier option to update an object in a "one-to-many" relationship?

    Hello, how can I easily update an object belonging to a one-to-many relationship?. I mean:

    
    Table Movies(id, title, ...)
    Table Genres(id, movie_id, name)
    

    I have, movie Blade runner and a list of genres( scifi, action...). What I'm doing is delete the genres and again insert the new ones, but I remember years ago I was using ormlite and they had something like 'movie.getGenres.update(...)' Is there something similiar to this for persism? Am I using the best and most efficient way to update a register in a one-to-many relationship? There will be an easier feature to update 'children' records in this kind of relationships?

    By the way, I'm using sqlite as DB Engine

    opened by vicenrico 1
  • You can get a module error because persismOriginalValue is serializable to json or xml

    You can get a module error because persismOriginalValue is serializable to json or xml

    If you try serializing to xml you can't extend from PersistableObject since it has a field which is not accessible to the modules.

    [GameManager] Failed making field 'net.sf.persism.PersistableObject#persismOriginalValue' accessible; either increase its visibility or write a custom TypeAdapter for its declaring type.
    com.google.gson.JsonIOException: Failed making field 'net.sf.persism.PersistableObject#persismOriginalValue' accessible; either increase its visibility or write a custom TypeAdapter for its declaring type.
    	at [email protected]/com.google.gson.internal.reflect.ReflectionHelper.makeAccessible(ReflectionHelper.java:38)
    	at [email protected]/com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:287)
    	at [email protected]/com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:130)
    	at [email protected]/com.google.gson.Gson.getAdapter(Gson.java:546)
    	at [email protected]/com.google.gson.internal.bind.CollectionTypeAdapterFactory.create(CollectionTypeAdapterFactory.java:53)
    	at [email protected]/com.google.gson.Gson.getAdapter(Gson.java:546)
    	at [email protected]/com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:160)
    	at [email protected]/com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:295)
    	at [email protected]/com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:130)
    	at [email protected]/com.google.gson.Gson.getAdapter(Gson.java:546)
    	at [email protected]/com.google.gson.Gson.toJson(Gson.java:817)
    	at [email protected]/com.google.gson.Gson.toJson(Gson.java:795)
    	at [email protected]/com.google.gson.Gson.toJson(Gson.java:742)
    	at [email protected]/com.google.gson.Gson.toJson(Gson.java:719)
    	at game.goldchest/game.ui.GameManager.saveGame(GameManager.java:457)
    	at game.goldchest/game.ui.menu.CampMenu.lambda$new$0(CampMenu.java:46)
    	at game.goldchest/game.ui.MenuPanel.doSelect(MenuPanel.java:359)
    	at game.goldchest/game.ui.MenuPanel.menuKeyEvent(MenuPanel.java:273)
    	at game.goldchest/game.ui.MenuPanel.keyPressed(MenuPanel.java:202)
    	at game.goldchest/game.ui.KeyDispatcher.dispatchKeyEvent(KeyDispatcher.java:64)
    	at java.desktop/java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1144)
    	at java.desktop/java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:1020)
    	at java.desktop/java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:848)
    	at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4882)
    	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2324)
    	at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2780)
    	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4833)
    	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
    	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
    	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
    	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:97)
    	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:746)
    	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:744)
    	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:743)
    	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
    Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private java.lang.Object net.sf.persism.PersistableObject.persismOriginalValue accessible: module sproket.github.io.persism does not "opens net.sf.persism" to module com.google.gson
    	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
    	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
    	at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:178)
    	at java.base/java.lang.reflect.Field.setAccessible(Field.java:172)
    	at [email protected]/com.google.gson.internal.reflect.ReflectionHelper.makeAccessible(ReflectionHelper.java:35)
    	... 43 common frames omitted
    
    
    
    bug 
    opened by sproket 0
  • Insert with POJO containing @Join annotations should also insert the child records

    Insert with POJO containing @Join annotations should also insert the child records

    Let's say you have a customer class containing invoices. You instantiate a new Customer and also set some child Invoice objects on the invoices property (annotated with @Join). In that case Persism should also insert the child rows using the new auto-inc parent value.

    enhancement 
    opened by sproket 0
  • Add upsert and/or fetchByKey(Class, Object...) methods to Session

    Add upsert and/or fetchByKey(Class, Object...) methods to Session

    I'm just exploring this library on Informix and it's basically working though it doesn't have "official" support - so that good :-).

    What I'm missing is a kind of upsert-statement: if an object is alread in the database I'd like to update it, if it's not there I'd like to insert it, e.g.:

    try (Session session = new Session(dataSource.getConnection())) {
        session.upsert(customer);			
    }
    

    I tried to work around it by using fetch first and then deciding if I need to insert or update. But I couldn't find a method which I could pass in the requested class and the key, e.g.: Customer customer = session.fetch(Customer.class, 5); Actually -- I found exactly that method, but it's commented out, as it doesn't work together with the variant that accepts an sql as a second parameter)... so that's a method that I'm missing, too.

    There is a fetch-method with a single POJO parameter, but it needs to be filled with the primary key first and when querying it, it will overwrite all contents contained in it. I could work around it by cloning the object, but that would require the POJO to be Cloneable, and it doesn't feel very right conceptually:

        Customer customerThrowAway = customer.clone();
        if (session.fetch(customerThrowAway)) {
            session.update(customer);
        } else {
            session.insert(customer);
        }
    

    So I'm kind of stuck here. I can of course write a simple SELECT myself and use the fetch-method with the SQL as a second parameter, but that doesn't really fit into the concept of simplicity with zero ceremony ;-) ...

    So I'd propose

    • to "wake up" the commented out fetch-method, probably with a new name
    • (an alternative to using a different name would be to change the existing fetch(Class, String, Object...) signature to fetch(String, Class, Object...) -- it should avoid the clash of signatures, but would break backwards compatibility).
    • consider adding an upsert-method

    So what do you think? Thanks for consdidering :-)

    [Background: My usage szenario is that I'm offering a REST webservice where the consumer can request a PUT some special field value. This value is usually just some optional add-one to some other POJO. In the GET-request we simply provide a default value if there's no value available, but we need to offer the option to store something explicitly.]

    enhancement 
    opened by dstango 9
Releases(V2.2.0)
Owner
Dan Howard
Software developer with 20+ years XP - Java, .NET etc...
Dan Howard
Speedment is a Stream ORM Java Toolkit and Runtime

Java Stream ORM Speedment is an open source Java Stream ORM toolkit and runtime. The toolkit analyzes the metadata of an existing SQL database and aut

Speedment 2k Dec 21, 2022
A lightweight and performant Java ORM alternative.

LightORM A lightweight and performant Java ORM alternative. LightORM has annotation processors so that all the integration code with the database is g

Jailson Pereira 14 Nov 22, 2022
Core ORMLite functionality that provides a lite Java ORM in conjunction with ormlite-jdbc or ormlite-android

ORMLite Core This package provides the core functionality for the JDBC and Android packages. Users that are connecting to SQL databases via JDBC shoul

Gray 547 Dec 25, 2022
A simple-to-use storage ORM supporting several databases for Java.

Storage Handler This is a library based off of my old storage handler within my queue revamp. It's for easy storage handling for multiple platforms. N

NV6 7 Jun 22, 2022
sql2o is a small library, which makes it easy to convert the result of your sql-statements into objects. No resultset hacking required. Kind of like an orm, but without the sql-generation capabilities. Supports named parameters.

sql2o Sql2o is a small java library, with the purpose of making database interaction easy. When fetching data from the database, the ResultSet will au

Lars Aaberg 1.1k Dec 28, 2022
H2 is an embeddable RDBMS written in Java.

Welcome to H2, the Java SQL database. The main features of H2 are: Very fast, open source, JDBC API Embedded and server modes; disk-based or in-memory

H2 Database Engine 3.6k Jan 5, 2023
A blazingly small and sane redis java client

Jedis Jedis is a blazingly small and sane Redis java client. Jedis was conceived to be EASY to use. Jedis is fully compatible with redis 2.8.x, 3.x.x

Redis 10.8k Dec 31, 2022
Elasticsearch Java Rest Client.

JEST Jest is a Java HTTP Rest client for ElasticSearch. ElasticSearch is an Open Source (Apache 2), Distributed, RESTful, Search Engine built on top o

Searchly 2.1k Jan 1, 2023
Java binding for etcd

jetcd: Java binding for etcd TravisCI: CircleCI: A simple Java client library for the awesome etcd Uses the Apache HttpAsyncClient to implement watche

Justin Santa Barbara 134 Jan 26, 2022
LINQ-style queries for Java 8

JINQ: Easy Database Queries for Java 8 Jinq provides developers an easy and natural way to write database queries in Java. You can treat database data

Ming Iu 641 Dec 28, 2022
MapDB provides concurrent Maps, Sets and Queues backed by disk storage or off-heap-memory. It is a fast and easy to use embedded Java database engine.

MapDB: database engine MapDB combines embedded database engine and Java collections. It is free under Apache 2 license. MapDB is flexible and can be u

Jan Kotek 4.6k Dec 30, 2022
MariaDB Embedded in Java JAR

What? MariaDB4j is a Java (!) "launcher" for MariaDB (the "backward compatible, drop-in replacement of the MySQL(R) Database Server", see FAQ and Wiki

Michael Vorburger ⛑️ 720 Jan 4, 2023
Unified Queries for Java

Querydsl Querydsl is a framework which enables the construction of type-safe SQL-like queries for multiple backends including JPA, MongoDB and SQL in

Querydsl 4.1k Dec 31, 2022
requery - modern SQL based query & persistence for Java / Kotlin / Android

A light but powerful object mapping and SQL generator for Java/Kotlin/Android with RxJava and Java 8 support. Easily map to or create databases, perfo

requery 3.1k Jan 5, 2023
A blazingly small and sane redis java client

Jedis Jedis is a blazingly small and sane Redis java client. Jedis was conceived to be EASY to use. Jedis is fully compatible with redis 2.8.x, 3.x.x

Redis 10.9k Jan 8, 2023
jOOQ is the best way to write SQL in Java

jOOQ's reason for being - compared to JPA Java and SQL have come a long way. SQL is an "ancient", yet established and well-understood technology. Java

jOOQ Object Oriented Querying 5.3k Jan 4, 2023
MapDB provides concurrent Maps, Sets and Queues backed by disk storage or off-heap-memory. It is a fast and easy to use embedded Java database engine.

MapDB: database engine MapDB combines embedded database engine and Java collections. It is free under Apache 2 license. MapDB is flexible and can be u

Jan Kotek 4.6k Jan 1, 2023
jdbi is designed to provide convenient tabular data access in Java; including templated SQL, parameterized and strongly typed queries, and Streams integration

The Jdbi library provides convenient, idiomatic access to relational databases in Java. Jdbi is built on top of JDBC. If your database has a JDBC driv

null 1.7k Dec 27, 2022