{"id":20718498,"url":"https://github.com/knowm/yank","last_synced_at":"2025-04-13T00:47:04.585Z","repository":{"id":41873046,"uuid":"1635654","full_name":"knowm/Yank","owner":"knowm","description":"Ultra-Light JDBC Persistance Layer","archived":false,"fork":false,"pushed_at":"2025-03-25T12:46:46.000Z","size":1792,"stargazers_count":133,"open_issues_count":12,"forks_count":16,"subscribers_count":10,"default_branch":"develop","last_synced_at":"2025-04-13T00:46:59.131Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://knowm.org/open-source/yank/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/knowm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2011-04-19T13:57:49.000Z","updated_at":"2025-02-27T10:57:52.000Z","dependencies_parsed_at":"2024-04-22T13:29:50.901Z","dependency_job_id":"3eb2f007-09ba-446d-a1b6-1f07d700462c","html_url":"https://github.com/knowm/Yank","commit_stats":null,"previous_names":["timmolter/yank"],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knowm%2FYank","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knowm%2FYank/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knowm%2FYank/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knowm%2FYank/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/knowm","download_url":"https://codeload.github.com/knowm/Yank/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248650433,"owners_count":21139672,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-17T03:13:51.638Z","updated_at":"2025-04-13T00:47:04.558Z","avatar_url":"https://github.com/knowm.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"## [![Yank](https://raw.githubusercontent.com/knowm/Yank/develop/etc/Yank_64_64.png)](http://knowm.org/open-source/yank/) Yank\nUltra-Light JDBC Persistance Layer for Java Apps\n\n## In a Nutshell\n\nNever 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.\n\n## Long Description\n\nYank 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.\nRather 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,\nhiding 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\"\nmethods 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\n[Hikari connection pool](https://github.com/brettwooldridge/HikariCP) as its integrated connection pool.\n\n## Features\n\n * [x] Apache 2.0 license\n * [x] ~16KB Jar\n * [x] Uses Apache DBUtils for JDBC\n * [x] Uses HikariCP for connection pooling\n * [x] Supports prepared statements\n * [x] Java object create, read, update, and delete (or CRUD) operations\n * [x] Automatic snake case (my_column_name) to camel case (myColumnName) mapping\n * [x] Automatic column name to field mapping via annotations\n * [x] Retrieving assigned auto-increment primary key ID for inserts\n * [x] Java object and object List querying\n * [x] Scalar querying\n * [x] Column List querying\n * [x] Batch execute\n * [x] Works with any JDBC-compliant database\n * [x] Write your own SQL statements\n * [x] Optionally store connection pool properties in a Properties file\n * [x] Optionally store SQL statements in a Properties file\n * [x] Multiple connection pools allows for connecting to multiple databases in a single app\n * [x] Choice to either log or receive SQLEceptions\n * [x] Java 8 and up\n\n## Basic Example\n\n```java\npublic static void main(String[] args) {\n\n  // Connection Pool Properties\n  Properties dbProps = new Properties();\n  dbProps.setProperty(\"jdbcUrl\", \"jdbc:mysql://localhost:3306/Yank\");\n  dbProps.setProperty(\"username\", \"root\");\n  dbProps.setProperty(\"password\", \"\");\n\n  // setup connection pool\n  Yank.setupDefaultConnectionPool(dbProps);\n\n  // query book\n  String sql = \"SELECT * FROM BOOKS WHERE TITLE = ?\";\n  Object[] params = new Object[] { \"Cryptonomicon\" };\n  Book book = Yank.queryBean(sql, Book.class, params);\n  System.out.println(book.toString());\n\n  // release connection pool\n  Yank.releaseDefaultConnectionPool();\n}\n```\n\n## Connection Pool Configuration\n\nYank 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](https://github.com/brettwooldridge/HikariCP).\n\n## Hide Those Properties Away!\n\n```java\n// Connection Pool Properties\nProperties dbProps = PropertiesUtils.getPropertiesFromClasspath(\"MYSQL_DB.properties\");\n\n// setup data source\nYank.setupDefaultConnectionPool(dbProps);\n```\nWhy? 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.\n\n## Hide Those SQL Statements Away!\n\n```java\n// SQL Statements in Properties file\nProperties sqlProps = PropertiesUtils.getPropertiesFromClasspath(\"MYSQL_SQL.properties\");\nYank.addSQLStatements(sqlProps);\n// ...\nString sqlKey = \"BOOKS_CREATE_TABLE\";\nYank.executeSQLKey(sqlKey, null);\n```\nWhy? Sometimes it's nice to have all your SQL statements in one place. As an example see: [MYSQL_SQL.properties](https://github.com/knowm/Yank/blob/develop/src/test/resources/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.\n\n## Stay Organized! You Will Thank Yourself Later.\n```java\npublic class Book {\n\n  private String title;\n  private String author;\n  private double price;\n  \n    // default constructor\n\n  // getters and setters\n}\n```\n```java\n\npublic class BooksDAO {\n\n  public static int insertBook(Book book) {\n\n    Object[] params = new Object[] { book.getTitle(), book.getAuthor(), book.getPrice() };\n    String SQL = \"INSERT INTO BOOKS  (TITLE, AUTHOR, PRICE) VALUES (?, ?, ?)\";\n    return Yank.execute(SQL, params);\n  }\n\n  // ...\n\n  public static List\u003cBook\u003e selectAllBooks() {\n\n    String SQL = \"SELECT * FROM BOOKS\";\n    return Yank.queryBeanList(SQL, Book.class, null);\n  }\n}\n```\nWhy? 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.\n\n## Annotate Class Fields\n```java\npublic static class Book {\n\n  private int id;\n  @Column(\"TITEL\")\n  private String title;\n  @Column(\"AUTOR\")\n  private String author;\n  @Column(\"PREIS\")\n  private double price;\n  \n  // default constructor\n\n  // getters and setters\n}\n```\nThe 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.\n\n## Insert and Receive the Assigned ID\n```java\nObject[] params = new Object[] { book.getTitle(), book.getAuthorName(), book.getPrice() };\nString SQL = \"INSERT INTO BOOKS (TITLE, AUTHOR, PRICE) VALUES (?, ?, ?)\";\nLong id = Yank.insert(SQL, params);\n```\nWith 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.\n\n## Retrieve a Column as a List\n```java\nString SQL = \"SELECT TITLE FROM BOOKS\";\nString columnName = \"title\";\nList\u003cString\u003e bookTitles = Yank.queryColumnList(SQL, columnName, String.class, null);\n```\nWith the `Yank.queryColumnList(...)` method you can retrieve a List containing objects matching column data type.\n\n## Query a Scalar Value\n```java\nString SQL = \"SELECT COUNT(*) FROM BOOKS\";\nlong numBooks = Yank.querySingleScalar(SQL, Long.class, null);\n```\nWith the `Yank.querySingleScalar(...)` method you can retrieve a single scalar value that matches the return type of the given SQL statement.\n## Life's a Batch\n```java\nList\u003cBook\u003e books = new ArrayList\u003cBook\u003e();\n// add books to list\n\nObject[][] params = new Object[books.size()][];\n\nfor (int i = 0; i \u003c books.size(); i++) {\n  Book book = books.get(i);\n  params[i] = new Object[] { book.getTitle(), book.getAuthor(), book.getPrice() };\n}\n\nString SQL = \"INSERT INTO BOOKS (TITLE, AUTHOR, PRICE) VALUES (?, ?, ?)\";\nint numInsertedRows = Yank.executeBatch(SQL, params);\n```\n\n## Handle Exceptions\n\nBy 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 `YankSQLException`s 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:\n\n```java\nYank.setThrowWrappedExceptions(true);\n\nObject[] params = new Object[] { book.getTitle(), book.getAuthor(), book.getPrice() };\nString SQL = \"INSERT INTO BOOKS (TITLE, AUT_HOR, PRICE) VALUES (?, ?, ?, ?)\";\ntry {\n  Yank.execute(SQL, params);\n} catch (YankSQLException e) {\n  e.printStackTrace();\nSQLException sqlException = e.getSqlException();\n}\n```\n\n```java\norg.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 (?, ?, ?, ?)\n...\n```\n\n\n## Summary\n\nWhether or not your app is a tiny script, a large webapp, or anything in between the main pattern to follow is the same:\n\n1. Configure a connection pool: `Yank.setupDefaultConnectionPool(dbProps);`\n1. Use Yank's methods: `Yank.execute(...) `,`Yank.executeBatch(...) `, `Yank.insert(...) `, `Yank.queryColumn(...) `, `Yank.queryObjectArrays(...) `, `Yank.queryBeanList(...) `, `Yank.queryBean(...) `, `Yank.queryScalar(...) `\n1. Release the connection pool: ` Yank.releaseDefaultConnectionPool();`\n\nFor an example of Yank in action in a `DropWizard` web application see [XDropWizard](https://github.com/knowm/XDropWizard).\n\nNow go ahead and [study some more examples](http://knowm.org/open-source/yank/yank-example-code), [download the thing](http://knowm.org/open-source/yank/yank-change-log/) and [provide feedback](https://github.com/knowm/Yank/issues).\n\n## Caveats\n\nYank 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.\n\n * 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.)\n * Checked SQLExceptions are wrapped into unchecked `YankSQLException`s (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.)\n * 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.)\n\nFor 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](https://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](http://www.sql2o.org/) and [JDBI](http://jdbi.org/).\n\n## Getting Started\n\n### Non-Maven\n\nDownload Jar: \u003chttp://knowm.org/open-source/yank/yank-change-log/\u003e\n\n#### Dependencies\n\n* commons-dbutils.dbutils-1.8.1\n* org.slf4j.slf4j-api-2.0.13\n* com.zaxxer.HikariCP-5.1.0\n* a JDBC-compliant Connector jar\n\n### Maven\n\nThe Yank release artifacts are hosted on Maven Central.\n\nAdd the Yank library as a dependency to your pom.xml file:\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.knowm\u003c/groupId\u003e\n    \u003cartifactId\u003eyank\u003c/artifactId\u003e\n    \u003cversion\u003e3.5.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\nFor snapshots, add the following to your pom.xml file:\n```xml\n\u003crepository\u003e\n  \u003cid\u003esonatype-oss-snapshot\u003c/id\u003e\n  \u003csnapshots/\u003e\n  \u003curl\u003ehttps://oss.sonatype.org/content/repositories/snapshots\u003c/url\u003e\n\u003c/repository\u003e\n\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.knowm\u003c/groupId\u003e\n    \u003cartifactId\u003eyank\u003c/artifactId\u003e\n    \u003cversion\u003e3.5.1-SNAPSHOT\u003c/version\u003e\n\u003c/dependency\u003e\n```\n## Building\n\n#### general\n\n    mvn clean package  \n    mvn javadoc:javadoc  \n\n#### Check for updated dependencies\n\n    mvn versions:display-dependency-updates\n    mvn versions:display-plugin-updates\n\n#### Formatting\n\n    mvn com.spotify.fmt:fmt-maven-plugin:format\n    \nFormats your code using [google-java-format](https://github.com/google/google-java-format) which follows [Google's code styleguide](https://google.github.io/styleguide/javaguide.html).\n\nIf you want your IDE to stick to the same format, check out the available configuration plugins:\n\n#### Eclipse\n\nDownload [`google-java-format-eclipse-plugin_*.jar`](https://github.com/google/google-java-format/releases) and place in `/Applications/Eclipse Java.app/Contents/Eclipse/dropins`. Restart Eclipse. Select the plugin in `Preferences \u003e Java \u003e Code Style \u003e Formatter \u003e Formatter Implementation`. \n\n#### IntelliJ\n\nIn the plugins section in IntelliJ search for `google-java-format` and install the plugin. Restart IntelliJ.\n\n\n## DropWizard Integration\n\nIf you want to integrate Yank into a DropWizard application, head over to [XDropWizard](https://github.com/knowm/XDropWizard) and grab [YankManager.java](https://github.com/knowm/XDropWizard/blob/master/src/main/java/org/knowm/xdropwizard/manager/YankManager.java) and add a simple configuration to your DropWizard [myapp.yml](https://github.com/knowm/XDropWizard/blob/master/xdropwizard.yml) file.\n\n## Bugs\nPlease report any bugs or submit feature requests to [Yank's Github issue tracker](https://github.com/knowm/Yank/issues).  \n\n## Continuous Integration\n[![Java CI with Maven on Push](https://github.com/knowm/Yank/actions/workflows/maven_on_push.yml/badge.svg)](https://github.com/knowm/Yank/actions/workflows/maven_on_push.yml)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fknowm%2Fyank","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fknowm%2Fyank","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fknowm%2Fyank/lists"}