Skip to content

Latest commit

 

History

History
198 lines (153 loc) · 6.47 KB

README.md

File metadata and controls

198 lines (153 loc) · 6.47 KB

PolyJDBC

Build Status

PolyJDBC is a polyglot, lightweight wrapper around standard JDBC drivers with schema inspection/creation capabilities.

Why?

When developing SmartParam JDBC repository i realized that i was writing polyglot JDBC wrapper instead of focusing on core JDBC repository responsibilities. PolyJDBC came to life by extracting low-level wrapping code to separate project.

Before starting work on SmartParam JDBC repo i was looking for a good JDBC wrapper that would do more than suppress SQLExceptions. Specifically i was looking for transaction-aware wrapper that would also make it easy to perform DDL operations.

Target

PolyJDBC primary target are libraries that need light and cross-platform JDBC persistence. Hibernate is great, but it leaves little place for end-user customization, which is important when offering a library. It is also quite heavy. PolyJDBC size is only 75kB, no dependencies except for slf4j logging API.

Features

  • polyglot (or better poly-dialect? multiple DB dialect support, including id generation strategies)
  • transaction-oriented
  • resources (Statements, ResultSets) are managed inside transaction scope
  • intiutive transaction commit/rollback support
  • option to leave transaction management to external framework (i.e. Spring)
  • DDL operation DSL (CREATE TABLE/INDEX/SEQUENCE with constraints, DROP *)
  • SQL query DSL (INSERT, SELECT, UPDATE, DELETE)
  • lightweight
  • schema inspection (table/sequence exists?)
  • schema alteration

Supported database engines

  • H2
  • PostgreSQL
  • MySQL
  • Oracle
  • Microsoft SQL Server

Thanks to testng magic PolyJDBC runs integration tests on each database. This way i can be sure that all features all supported across all engines.

How to get it?

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.polyjdbc', name: 'polyjdbc', version: '0.5.0'
}

Enough, show me the code

Instantiation

By default, PolyJDBC takes care of transaction management on it's own:

Dialect dialect = DialectRegistry.H2.getDialect();
PolyJDBC polyjdbc = PolyJDBCBuilder.polyJDBC(dialect).connectingToDataSource(dataSource).build();

But it is possible to leave connection management to any external framework:

Dialect dialect = DialectRegistry.H2.getDialect();
PolyJDBC polyjdbc = PolyJDBCBuilder.polyJDBC(dialect).usingManagedConnections(() -> frameworkManager::getConnection).build();

Querying

To ask simple questions, use simple tool. SimpleQueryRunner performs each query in new transaction:

SelectQuery query = polyJdbc.query().selectAll().from("test").where("name = :name")
        .withArgument("name", "test");
        
Test test = polyJdbc.simpleQueryRunner().queryUnique(query, new TestMapper());

You might want to span your transaction across multiple statements, if so use TransactionRunner:

TransactionRunner transactionRunner = polyjdbc.transactionRunner();

Test test = transactionRunner.run(new TransactionWrapper<Test>() {
    @Override
    public Test perform(QueryRunner queryRunner) {
        SelectQuery query = polyJdbc.query().selectAll().from("test").where("name = :name")
            .withArgument("name", "test");
        return queryRunner.queryUnique(query, new TestMapper());
    }
});

transactionRunner.run(new VoidTransactionWrapper() {
    @Override
    public void performVoid(QueryRunner queryRunner) {
        DeleteQuery query = polyJdbc.query().delete().from("test").where("year < :year")
            .withArgument("year", 2012);
        queryRunner.delete(query);
    }
});

Or if you need to get your hands dirty, see QueryRunner, but remember to free the resources:

QueryRunner queryRunner = null;

try {
    queryRunner = polyjdbc.queryRunner();
    SelectQuery query = polyJdbc.query().selectAll().from("test").where("year = :year")
        .withArgument("year", 2013).limit(10);
    List<Test> tests = queryRunner.selectList(query, new TestMapper());
    queryRunner.commit()
}
catch(Exception exception) {
    polyjdbc.rollback(queryRunner);
    throw exception;
}
finally {
    polyjdbc.close(queryRunner);
}

Schema management

PolyJDBC comes with tools for schema creating and deletion. More options for schema inspection are planned, although there is no concrete release date.

To check if relation exists:

SchemaInspector schemaInspector = null;
try {
    schemaInspector = polyjdbc.schemaInspector();
    boolean relationExists = schemaInspector.relationExists("testRelation");
} finally {
    polyjdbc.close(schemaManager);
}

To create new schema (group of relations):

SchemaManager schemaManager = null;
try {
    schemaManager = polyjdbc.schemaManager();

    Schema schema = new Schema(configuration.getDialect());
    schema.addRelation("test_one")
        .withAttribute().longAttr("id").withAdditionalModifiers("AUTO_INCREMENT").notNull().and()
        .withAttribute().string("name").withMaxLength(200).notNull().unique().and()
        .withAttribute().integer("age").notNull().and()
        .primaryKey("pk_test_one").using("id").and()
        .build();
    schema.addSequence("seq_test_one").build();
    schema.addRelation("test_two")
        .withAttribute().longAttr("id").withAdditionalModifiers("AUTO_INCREMENT").notNull().and()
        .withAttribute().longAttr("fk_test_one").notNull().and()
        .foreignKey("fk_test_one_id").references("test_one", "id").on("fk_test_one").and()
        .build();
    schema.addSequence("seq_test_two").build();

    schemaManager.create(schema);
} finally {
    polyjdbc.close(schemaManager);
}

You don't need to define Schema object. Single Relation, Sequence or Index can be created using SchemaManager as well.

License

PolyJDBC is published under Apache License 2.0.

Changelog

  • 0.5.0
    • added possibility to plug in external framework for transaction management
    • [API change] PolyJDBC is build using PolyJDBCBuilder
  • 0.4.0 (24.08.2014)
    • fixed bug with closing transaction on exception in query runners
    • [API change] QueryRunner.close() does not commit, use QueryRunner.commit() explicitly
    • [API change] some queries from QueryFactory.* now need Dialect (better Oracle support in future), use dialect-aware PolyJDBC.query()
  • previous versions
    • support for PostgreSQL, MySQL, H2 and partial support for Oracle