Code Monkey home page Code Monkey logo

yank's Introduction

Yank Yank

Ultra-Light JDBC Persistance Layer for Java Apps

In a Nutshell

Never deal with the monotony and pitfalls of handling JDBC ResultSets and Connections again. Yank deals with connection pooling and table row to Java object mapping for you so you don't have to worry about it.

Long Description

Yank is a very easy-to-use yet flexible SQL-centric persistence layer for JDBC-compatible databases build on top of org.apache.DBUtils. Yank is a different approach to the over-ORMing of Java persistence. Rather than try to abstract away the SQL underneath, Yank assumes you want low level control over the SQL queries you execute. Yank is one level higher than raw JDBC code with minimal frills. Yank wraps DBUtils, hiding the nitty-gritty Connection and ResultSet handling behind a straight-forward proxy class: Yank. "Query" methods execute SELECT statements and return POJOs or a List of POJOs. "Execute" methods execute INSERT, UPDATE, and DELETE (and other) statements. Recently, annotation-based column-field mapping, batch executing, column list querying and scalar querying has been added. Since version 3.0.0, Yank uses the Hikari connection pool as its integrated connection pool.

Features

  • Apache 2.0 license
  • ~16KB Jar
  • Uses Apache DBUtils for JDBC
  • Uses HikariCP for connection pooling
  • Supports prepared statements
  • Java object create, read, update, and delete (or CRUD) operations
  • Automatic snake case (my_column_name) to camel case (myColumnName) mapping
  • Automatic column name to field mapping via annotations
  • Retrieving assigned auto-increment primary key ID for inserts
  • Java object and object List querying
  • Scalar querying
  • Column List querying
  • Batch execute
  • Works with any JDBC-compliant database
  • Write your own SQL statements
  • Optionally store connection pool properties in a Properties file
  • Optionally store SQL statements in a Properties file
  • Multiple connection pools allows for connecting to multiple databases in a single app
  • Choice to either log or receive SQLEceptions
  • Java 8 and up

Basic Example

public static void main(String[] args) {

  // Connection Pool Properties
  Properties dbProps = new Properties();
  dbProps.setProperty("jdbcUrl", "jdbc:mysql://localhost:3306/Yank");
  dbProps.setProperty("username", "root");
  dbProps.setProperty("password", "");

  // setup connection pool
  Yank.setupDefaultConnectionPool(dbProps);

  // query book
  String sql = "SELECT * FROM BOOKS WHERE TITLE = ?";
  Object[] params = new Object[] { "Cryptonomicon" };
  Book book = Yank.queryBean(sql, Book.class, params);
  System.out.println(book.toString());

  // release connection pool
  Yank.releaseDefaultConnectionPool();
}

Connection Pool Configuration

Yank comes bundled with the Hikari Connection Pool. When you setup Yank using the Yank.setupDefaultConnectionPool method and pass it a Properties object, that object must at the very least contain jdbcUrl, username and password properties. Another common property is maximumPoolSize.To see a full list of available configuration properties along with their defaults, see Hikari's main README.

Hide Those Properties Away!

// Connection Pool Properties
Properties dbProps = PropertiesUtils.getPropertiesFromClasspath("MYSQL_DB.properties");

// setup data source
Yank.setupDefaultConnectionPool(dbProps);

Why? Hardcoding properties is fine for something quick and dirty, but loading them from a file is generally more convenient and flexible. For example, you may have separate properties for unit tests, development and production deployments. BTW, you can load them from a path too with: PropertiesUtils.getPropertiesFromPath(String fileName). At the bare minimum, you need to provide username, password, and jdbcUrl configuration properties.

Hide Those SQL Statements Away!

// SQL Statements in Properties file
Properties sqlProps = PropertiesUtils.getPropertiesFromClasspath("MYSQL_SQL.properties");
Yank.addSQLStatements(sqlProps);
// ...
String sqlKey = "BOOKS_CREATE_TABLE";
Yank.executeSQLKey(sqlKey, null);

Why? Sometimes it's nice to have all your SQL statements in one place. As an example see: MYSQL_SQL.properties. Also this allows you to swap databases easily without changing any code. Keep one for database type X and one for database type Y. BTW, to access the actual statements in the properties file, you use the Yank.*SQLKey(...) methods in Yank. You can also add multiple properties files and they will be merged! If the SQL statement cannot be found, a SQLStatementNotFoundException runtime exception is thrown.

Stay Organized! You Will Thank Yourself Later.

public class Book {

  private String title;
  private String author;
  private double price;
  
    // default constructor

  // getters and setters
}
public class BooksDAO {

  public static int insertBook(Book book) {

    Object[] params = new Object[] { book.getTitle(), book.getAuthor(), book.getPrice() };
    String SQL = "INSERT INTO BOOKS  (TITLE, AUTHOR, PRICE) VALUES (?, ?, ?)";
    return Yank.execute(SQL, params);
  }

  // ...

  public static List<Book> selectAllBooks() {

    String SQL = "SELECT * FROM BOOKS";
    return Yank.queryBeanList(SQL, Book.class, null);
  }
}

Why? By creating a DAO class and putting all methods related to a single database table in it, you have a single point of access to that table. In this example the BooksDAO corresponds to a table called Books, which contains rows of Book objects (a.k.a beans). Note that your beans must have the default, no args constructor.

Annotate Class Fields

public static class Book {

  private int id;
  @Column("TITEL")
  private String title;
  @Column("AUTOR")
  private String author;
  @Column("PREIS")
  private double price;
  
  // default constructor

  // getters and setters
}

The default automatic mapping from database row to Java objects happens when the object's field names match the table column names (not case-sensitive). Automatic snake case (my_column_name) to camel case (myColumnName) mapping is supported too. If that still isn't good enough, you can annotate the Java object's fields with a Column annotation.

Insert and Receive the Assigned ID

Object[] params = new Object[] { book.getTitle(), book.getAuthorName(), book.getPrice() };
String SQL = "INSERT INTO BOOKS (TITLE, AUTHOR, PRICE) VALUES (?, ?, ?)";
Long id = Yank.insert(SQL, params);

With a special Yank.insert(...) method, Yank will return the assigned auto-increment primary key ID. Note that you can alternatively use the Yank.execute(...) method for inserts, which returns the number of affected rows.

Retrieve a Column as a List

String SQL = "SELECT TITLE FROM BOOKS";
String columnName = "title";
List<String> bookTitles = Yank.queryColumnList(SQL, columnName, String.class, null);

With the Yank.queryColumnList(...) method you can retrieve a List containing objects matching column data type.

Query a Scalar Value

String SQL = "SELECT COUNT(*) FROM BOOKS";
long numBooks = Yank.querySingleScalar(SQL, Long.class, null);

With the Yank.querySingleScalar(...) method you can retrieve a single scalar value that matches the return type of the given SQL statement.

Life's a Batch

List<Book> books = new ArrayList<Book>();
// add books to list

Object[][] params = new Object[books.size()][];

for (int i = 0; i < books.size(); i++) {
  Book book = books.get(i);
  params[i] = new Object[] { book.getTitle(), book.getAuthor(), book.getPrice() };
}

String SQL = "INSERT INTO BOOKS (TITLE, AUTHOR, PRICE) VALUES (?, ?, ?)";
int numInsertedRows = Yank.executeBatch(SQL, params);

Handle Exceptions

By default Yank catches each SQLException, wraps them in a YankSQLException and logs them as error logs using the slf4J logging framework. If you want to change the behavior so that the YankSQLExceptions are instead rethrown, just call Yank.setThrowWrappedExceptions(true);. If you want direct access to the SQLException, simply call the getSqlException() method. Here's an example:

Yank.setThrowWrappedExceptions(true);

Object[] params = new Object[] { book.getTitle(), book.getAuthor(), book.getPrice() };
String SQL = "INSERT INTO BOOKS (TITLE, AUT_HOR, PRICE) VALUES (?, ?, ?, ?)";
try {
  Yank.execute(SQL, params);
} catch (YankSQLException e) {
  e.printStackTrace();
SQLException sqlException = e.getSqlException();
}
org.knowm.yank.exceptions.YankSQLException: Error in SQL query!!!; row column count mismatch Query: INSERT INTO BOOKS (TITLE, AUT_HOR, PRICE) VALUES (?, ?, ?, ?) Parameters: [Cryptonomicon, Neal Stephenson, 23.99]; Pool Name= yank-default; SQL= INSERT INTO BOOKS (TITLE, AUT_HOR, PRICE) VALUES (?, ?, ?, ?)
...

Summary

Whether or not your app is a tiny script, a large webapp, or anything in between the main pattern to follow is the same:

  1. Configure a connection pool: Yank.setupDefaultConnectionPool(dbProps);
  2. Use Yank's methods: Yank.execute(...) ,Yank.executeBatch(...) , Yank.insert(...) , Yank.queryColumn(...) , Yank.queryObjectArrays(...) , Yank.queryBeanList(...) , Yank.queryBean(...) , Yank.queryScalar(...)
  3. Release the connection pool: Yank.releaseDefaultConnectionPool();

For an example of Yank in action in a DropWizard web application see XDropWizard.

Now go ahead and study some more examples, download the thing and provide feedback.

Caveats

Yank was designed to be ultra-light and ultra-convenient and is philosophically different than most other competing libraries. Some "sacrifices" were made to stick to this design.

  • No multi-statement transaction service (This may be just fine for small to medium projects or to back a REST web application's API: POST, GET, PUT, and DELETE. These correspond to create, read, update, and delete (or CRUD) operations, respectively.)
  • Checked SQLExceptions are wrapped into unchecked YankSQLExceptions (SQL Exceptions are internally caught and wrapped. This is a heavily debated topic and many differing opinions exist. Yank, being ultra-light, catches and logs or rethrows YankSQLExceptions.)
  • A Hikari connection pool is used behind the scenes (Generic DataSource integration isn't supported. If you just want a connection pool that works and don't care about the specific implementation this point is irrelevant.)

For many cases, the above features are not necessary, but that's for you to determine. If you are developing a critical banking application, you will probably need those features. For other applications where 100% data integrity isn't critical (such as bitcoinium.com for example), Yank's simplicity may be attractive. In return for the sacrifices, you write less code and your code will be cleaner. Additionally, since Yank's methods are public static, you can access it from anywhere in your application and not have to worry about passing around a reference to it. If you need those missing features, check out these projects similar to Yank: sql2o and JDBI.

Getting Started

Non-Maven

Download Jar: http://knowm.org/open-source/yank/yank-change-log/

Dependencies

  • commons-dbutils.dbutils-1.8.1
  • org.slf4j.slf4j-api-2.0.13
  • com.zaxxer.HikariCP-5.1.0
  • a JDBC-compliant Connector jar

Maven

The Yank release artifacts are hosted on Maven Central.

Add the Yank library as a dependency to your pom.xml file:

<dependency>
    <groupId>org.knowm</groupId>
    <artifactId>yank</artifactId>
    <version>3.5.0</version>
</dependency>

For snapshots, add the following to your pom.xml file:

<repository>
  <id>sonatype-oss-snapshot</id>
  <snapshots/>
  <url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>

<dependency>
    <groupId>org.knowm</groupId>
    <artifactId>yank</artifactId>
    <version>3.5.1-SNAPSHOT</version>
</dependency>

Building

general

mvn clean package  
mvn javadoc:javadoc  

Check for updated dependencies

mvn versions:display-dependency-updates
mvn versions:display-plugin-updates

Formatting

mvn com.spotify.fmt:fmt-maven-plugin:format

Formats your code using google-java-format which follows Google's code styleguide.

If you want your IDE to stick to the same format, check out the available configuration plugins:

Eclipse

Download google-java-format-eclipse-plugin_*.jar and place in /Applications/Eclipse Java.app/Contents/Eclipse/dropins. Restart Eclipse. Select the plugin in Preferences > Java > Code Style > Formatter > Formatter Implementation.

IntelliJ

In the plugins section in IntelliJ search for google-java-format and install the plugin. Restart IntelliJ.

DropWizard Integration

If you want to integrate Yank into a DropWizard application, head over to XDropWizard and grab YankManager.java and add a simple configuration to your DropWizard myapp.yml file.

Bugs

Please report any bugs or submit feature requests to Yank's Github issue tracker.

Continuous Integration

Java CI with Maven on Push

yank's People

Contributors

dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar eepstein avatar jlleitschuh avatar nelsongomes avatar timmolter avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

yank's Issues

logging messages only errors.

i need suppress the server logging messages, i want only the error messages,

can i do this task with normal options or i need update the code.

can you help me please.

MariaDB 10.0

I am starting a new project, could you please inform me if mariadb 10.0 is and will be fully supported in this version and in the next version of yank?

set variables

with yank can i set variables like:

set @varDate = '2020-02-13'

is compatible with r2dbc?

I want to start a project with spring boot and I can only select r2dbc drivers (mysql/mariadb),

are they compatible with yank?

yank-test

Field have underscore

I have table structure:

CREATE TABLE users (
user_id int(11) NOT NULL AUTO_INCREMENT,
admin_id int(11) DEFAULT NULL,
loginname varchar(100) NOT NULL,
password varchar(45) NOT NULL,
password_salt varchar(10) NOT NULL,
display_name varchar(100) DEFAULT NULL,
first_name varchar(100) DEFAULT NULL,
last_name varchar(100) DEFAULT NULL,
email varchar(100) NOT NULL,
phone varchar(20) DEFAULT NULL,
created_time int(10) NOT NULL,
active tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (user_id),
UNIQUE KEY email_UNIQUE (email),
UNIQUE KEY loginname_UNIQUE (loginname),
KEY fk_users_users_idx (admin_id),
CONSTRAINT fk_users_users FOREIGN KEY (admin_id) REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

Can not get values of fields have underscore:

Users{userId=0, adminId=0, loginname='[email protected]', password='1c1802e725674705f25af1de5a50dec9', passwordSalt='null', displayName='null', firstName='null', lastName='null', email='[email protected]', phone='0989831911', createdTime=0, active=1}

Update dependencies?

Apache Commons DbUtils is at 1.7
HikariCP is at 2.6.3

Both of them with fixes and improvements.

:-)

Add field to column mapping annotations

Actually this looks pretty easy with annotations. DBUtils allows for an override map so something like the following would work with an annotation parser beforehand:

final Map<String, String> columnToPropertyOverrides = new HashMap<>();
columnToPropertyOverrides.put("WIND_DIRECTION", "WindDirection");

BeanProcessor dateForProcessor = new BeanProcessor(columnToPropertyOverrides);
BasicRowProcessor rp = new BasicRowProcessor(dateForProcessor);

Cannot use insert or insertBatch with SQLite

This is more documenting the issue than asking for help, but I discovered that both insert and insertBatch call PreparedStatement.getGeneratedKeys(), which is not supported by any SQLite JDBC driver. This prevents getting the new ID from the inserted row.

However, it turns out that https://github.com/xerial/sqlite-jdbc supports getGeneratedKeys(), but only on an older release (2 weeks ago from posting), 3.42.0.1.

Connection Pooling issue

Hi,

I have used Yank manager for my database connection but beyond a point of time, I am getting "Too many connections". Do I need to handle separately for connection pooling.

queryColumnSQLKey is not working as intended

When I use the queryColumn, it give me the desired result whereas using queryColumnSQLKey and passing the SQL key does not work well. It returns empty value for each record and not the actual value.

concurrent, multiuser and custom database

apologies if I am repetitive,

I have a concurrent, multiuser web application that each user connects to this application uses a custom database.

eg User 1 connects to the database 1 and so on (I have almost 100 users and the same number of databases).

several or all users are connected simultaneously.

yank 3 can optimally cover this scenario?

otherwise you could please recommend some strategy or other product (excuse me if the latter is reckless)

hikari 2.4.1, compatibility Patch shutdown() to close()

Hy @timmolter,

diff --git a/src/main/java/com/xeiam/yank/YankPoolManager.java b/src/main/java/com/xeiam/yank/YankPoolManager.java
index da3d4e5..f374d7d 100644
--- a/src/main/java/com/xeiam/yank/YankPoolManager.java
+++ b/src/main/java/com/xeiam/yank/YankPoolManager.java
@@ -90,7 +90,7 @@

     if (this.hikariDataSource != null) {
       logger.info("Releasing pool: {}...", this.hikariDataSource.getPoolName());
-      this.hikariDataSource.shutdown();
+      this.hikariDataSource.close();
     }
   }

then pom.xml dependency can be changed too:
from:

        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP-java6</artifactId>
            <version>2.3.9</version>
            <scope>compile</scope>
        </dependency>

to:

        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
            <version>2.4.1</version>
            <scope>compile</scope>
        </dependency>

A small issue I've found in examples MYSQL_SQL.properties too:

BOOKS_CREATE_TABLE=CREATE TABLE `Books` ...

should be changed to:

BOOKS_CREATE_TABLE=CREATE TABLE `BOOKS` ...

I tested with Mysql, and got an error: 'BOOKS' could not be found.

Thank you very much.
Helmut

Connection Pool Leak Issues

Hello.

There are two changes you might consider:

DBConnectionPool.release()
should set checkedOut=0;

DBConnectionPool.getConnection()
...
if (con.isClosed()) {
checkedOut--;
//etc
}
//etc

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.