Each table in your database has a corresponding Bean (a.k.a. Pojo or Plain Ol’ Java Object). The Bean has private fields with names and data types that match the column names of your table. In other words, the Bean is a one-to-one mapping of a single row in your table.
The next thing you need is a Data Access Object, or DAO. In this Class, you create methods for interacting with the table. In each method, with only a few lines of code, you create the specific SQL query you want and use org.knowm.yank.Yank
to handle the query for you. You actually don’t need to have a DAO Class, but it helps to organize your project. You could always just call the Yank
methods directly and forego a DAO Class.
The advantage of this is that your code for interacting with the database is all wrapped up in just two very simple classes for each table in your database – a Bean and a DAO. And because the actual nitty-gritty details of handling database connections and results sets in handled for you in org.knowm.yank.Yank
, you don’t have to worry about coding that yourself. It saves time and prevents errors. In the following demo code you will see absolutely no low-level ResultSet
, Connection
, or exception handling code – only clean and organized business-domain code.
One advanced feature is also demonstrated here: storing database connection properties and SQL statements in Properties files. You do not have to do it this way; you could hardcode everything if you wanted to. There are several advantage however. First, if you want to switch database technologies, like from Oracle to MySQL, all you’d have to do is load a different Properties file with the new DB connection information. Same goes for the SQL Properties file. Since different database technologies use different SQL syntax, you could have two files – one for DB_X
and one for DB_Y
, and switching between the two is just a matter of loading a different Properties file. Some people also like to have all their SQL statements in one place and not scattered throughout several classes.
Note that in these examples that Yank
is always setup at the beginning and then released at the end. In a real application you would not want to continuously setup and release before and after each database action, but instead setup and application startup and release at application shutdown, leaving Yank “open” for the lifetime of the application.
This demo uses MySQL but any JDBC-Compliant database will work. You just need to put the appropriate JDBC Connector jar on the classpath and tweak the SQL statements to match the specific SQL syntax for your database of choice!
1 2 3 4 5 6 7 8 |
// However you end up creating a database, it must have the name "Yank" for the rest of this example code to work. // In general the database name must match the provided database name in the jdbc url you provide Yank. // The example code also uses MySQL-specific SQL statements. Here's how to create a Yank database in MySQL from the command line: $ /usr/local/mysql/bin/mysql -u root -p mysql$ create database Yank; mysql$ show databases; mysql$ exit; |
1 2 3 4 |
jdbcUrl=jdbc:mysql://localhost:3306/Yank username=root password= maximumPoolSize=10 |
Yank comes bundled with the Hikari Connection Pool. When you setup Yank using the Yank.setupDataSource()
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.
1 2 3 |
BOOKS_CREATE_TABLE=CREATE TABLE `Books` (`ID` int(10) unsigned NOT NULL AUTO_INCREMENT, `TITLE` varchar(42) DEFAULT NULL, `AUTHOR` varchar(42) DEFAULT NULL,`PRICE` double DEFAULT NULL, PRIMARY KEY (`ID`)) ENGINE=MyISAM DEFAULT CHARSET=utf8; BOOKS_SELECT_BY_TITLE=SELECT * FROM BOOKS WHERE TITLE = ? BOOKS_SELECT_TABLE_STATUS=SHOW TABLE STATUS |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
package org.knowm.yank.demo; /** * A class used to represent rows in the BOOKS table <br> * Note: class member naming tip: data type and name must match SQL table!<br> * Note: DBUtils uses reflection to match column names to class member names. <br> * Class members are matched to columns based on several factors: * <ul> * <li>set* methods that match the table's column names (i.e. title <--> setTitle()). The name comparison is case insensitive.</li> * <li>The columns are matched to the object's class members</li> * <li>If the conversion fails (i.e. the property was an int and the column was a Timestamp) an SQLException is thrown.</li> * </ul> * * @author timmolter */ public class Book { private int id; private String title; private String author; private double price; /** Pro-tip: In Eclipse, generate all getters and setters after defining class fields: Right-click --> Source --> Generate Getters and Setters... */ public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } /** Pro-tip: In Eclipse, generate a toString() method for a class: Right-click --> Source --> Generate toString()... */ @Override public String toString() { return "Book [id=" + id + ", title=" + title + ", author=" + author + ", price=" + price + "]"; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
package org.knowm.yank.demo; import java.util.List; import org.knowm.yank.Yank; /** * DAO (Data Access Object) Class for BOOKS table. <br> * This is where you create your own methods for SQL interaction with a database table.<br> * Each table in your database should have it's own DAO Class.<br> * * @author timmolter */ public class BooksDAO { /** * This method demonstrates: * <ul> * <li>executing an SQL statement with DBProxy.executeSQL</li> * <li>using a prepared statement with corresponding params</li> * <li>retrieving assigned auto-increment primary key ID</li> * </ul> */ public static long insertBook(Book book) { Object[] params = new Object[] { book.getTitle(), book.getAuthor(), book.getPrice() }; String SQL = "INSERT INTO BOOKS (TITLE, AUTHOR, PRICE) VALUES (?, ?, ?)"; return Yank.insert(SQL, params); } /** * This method demonstrates: * <ul> * <li>querying a table for a list of Objects, in this case Book objects, using DBProxy.queryObjectListSQL</li> * <li>using a non-prepared statement with null params</li> * </ul> */ public static List<Book> selectAllBooks() { String SQL = "SELECT * FROM BOOKS"; return Yank.queryBeanList(SQL, Book.class, null); } /** * This method demonstrates: * <ul> * <li>querying a table for a list of Strings, in this case Book titles, using DBProxy.queryObjectListSQL</li> * <li>using a non-prepared statement with null params</li> * </ul> */ public static List<String> selectAllBookTitles() { String SQL = "SELECT TITLE FROM BOOKS"; String columnName = "title"; return Yank.queryColumn(SQL, columnName, String.class, null); } /** * This method demonstrates: * <ul> * <li>executing a batch insert statement using DBProxy.executeBatchSQL</li> * <li>using a prepared statement with corresponding params</li> * </ul> */ public static int[] insertBatch(List<Book> books) { 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 (?, ?, ?)"; return Yank.executeBatch(SQL, params); } /** * This method demonstrates: * <ul> * <li>the advanced feature of using an SQL Key corresponding to an actual SQL statement stored in a Properties file using DBProxy.executeSQLKey</li> * <li>using a non-prepared statement with null params</li> * </ul> */ public static int createBooksTable() { String sqlKey = "BOOKS_CREATE_TABLE"; return Yank.executeSQLKey(sqlKey, null); } /** * This method demonstrates: * <ul> * <li>the advanced feature of using an SQL Key corresponding to an actual SQL statement stored in a Properties file using * DBProxy.querySingleObjectSQLKey</li> * <li>using a prepared statement with corresponding params</li> * </ul> */ public static Book selectBook(String title) { Object[] params = new Object[] { title }; String sqlKey = "BOOKS_SELECT_BY_TITLE"; return Yank.queryBeanSQLKey(sqlKey, Book.class, params); } /** * This method demonstrates: * <ul> * <li>the advanced feature of using an SQL Key corresponding to an actual SQL statement stored in a Properties file using * DBProxy.queryGenericObjectArrayListSQLKey</li> * <li>using a non-prepared statement with null params</li> * <li>querying for a List of Objects representing all columns in a table</li> * </ul> */ public static List<Object[]> getTableStatus() { String sqlKey = "BOOKS_SELECT_TABLE_STATUS"; return Yank.queryObjectArraysSQLKey(sqlKey, null); } /** * This method demonstrates: * <ul> * <li>using a non-prepared statement with null params</li> * <li>querying for a Scalar value the row count of a table</li> * </ul> */ public static long getNumBooks() { String SQL = "SELECT COUNT(*) FROM BOOKS"; return Yank.queryScalar(SQL, Long.class, null); } /** * This method demonstrates: * <ul> * <li>using a non-prepared statement with null params</li> * <li>the advanced feature of using an SQL Key corresponding to an actual SQL statement stored in a Properties file using DBProxy.executeSQLKey</li> * </ul> */ public static Book selectRandomBook() { String sqlKey = "BOOKS_SELECT_RANDOM_BOOK"; return Yank.queryBeanSQLKey(sqlKey, Book.class, null); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
package org.knowm.yank.demo; import java.util.Properties; import org.knowm.yank.PropertiesUtils; import org.knowm.yank.Yank; /** * Create a table called BOOKS. <br> * Demonstrates hardcoding the connection pool properties rather then getting them from a Properties file. <br> * Note: myconnectionpoolname can be anything but it needs to match the first String argument in DBProxy.* method calls. See BooksDAO.java. <br> * * @author timmolter */ public class CreateBooksTable { public static void main(String[] args) { // DB Properties Properties dbProps = new Properties(); dbProps.setProperty("jdbcUrl", "jdbc:mysql://localhost:3306/Yank"); dbProps.setProperty("username", "root"); dbProps.setProperty("password", ""); dbProps.setProperty("maximumPoolSize", "5"); // SQL Statements in Properties file Properties sqlProps = PropertiesUtils.getPropertiesFromClasspath("MYSQL_SQL.properties"); Yank.setupDataSource(dbProps); Yank.addSQLStatements(sqlProps); // create table BooksDAO.createBooksTable(); Yank.releaseDataSource(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
package org.knowm.yank.demo; import java.util.Properties; import org.knowm.yank.PropertiesUtils; import org.knowm.yank.Yank; /** * Create a table called BOOKS. Demonstrates getting the connection pool properties from a *.properties file. * * @author timmolter */ public class CreateBooksTableWithPropsFile { public static void main(String[] args) { // MYSQL_DB.properties file on classpath Properties dbProps = PropertiesUtils.getPropertiesFromClasspath("MYSQL_DB.properties"); // Alternative method: MYSQL_DB.properties file using path to file // Properties props = PropertiesUtils.getPropertiesFromPath("/path/to/MYSQL_DB.properties"); // SQL Statements in Properties file Properties sqlProps = PropertiesUtils.getPropertiesFromClasspath("MYSQL_SQL.properties"); Yank.setupDataSource(dbProps); Yank.addSQLStatements(sqlProps); // query BooksDAO.createBooksTable(); Yank.releaseDataSource(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
package org.knowm.yank.demo; import java.util.Properties; import org.knowm.yank.PropertiesUtils; import org.knowm.yank.Yank; /** * Inserts a Book into the BOOKS table. Demonstrates fetching the connection pool properties from a file on the classpath * * @author timmolter */ public class InsertBook { public static void main(String[] args) { // DB Properties Properties dbProps = PropertiesUtils.getPropertiesFromClasspath("MYSQL_DB.properties"); Yank.setupDataSource(dbProps); // query Book book = new Book(); book.setTitle("Cryptonomicon"); book.setAuthor("Neal Stephenson"); book.setPrice(23.99); long autoID = BooksDAO.insertBook(book); System.out.println(autoID); Yank.releaseDataSource(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
package org.knowm.yank.demo; import java.util.ArrayList; import java.util.List; import java.util.Properties; import org.knowm.yank.PropertiesUtils; import org.knowm.yank.Yank; /** * Inserts a Batch of Book Objects into the BOOKS table. * * @author timmolter */ public class InsertBatch { public static void main(String[] args) { // DB Properties Properties dbProps = PropertiesUtils.getPropertiesFromClasspath("MYSQL_DB.properties"); Yank.setupDataSource(dbProps); // query List<Book> books = new ArrayList<Book>(); Book book = new Book(); book.setTitle("Cryptonomicon"); book.setAuthor("Neal Stephenson"); book.setPrice(23.99); books.add(book); book = new Book(); book.setTitle("Harry Potter"); book.setAuthor("Joanne K. Rowling"); book.setPrice(11.99); books.add(book); book = new Book(); book.setTitle("Don Quijote"); book.setAuthor("Cervantes"); book.setPrice(21.99); books.add(book); BooksDAO.insertBatch(books); Yank.releaseDataSource(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package org.knowm.yank.demo; import java.util.List; import java.util.Properties; import org.knowm.yank.PropertiesUtils; import org.knowm.yank.Yank; /** * Selects all Book Objects from the BOOKS table. Demonstrates fetching the connection pool properties from a file on the classpath * * @author timmolter */ public class SelectAllBooks { public static void main(String[] args) { // DB Properties Properties dbProps = PropertiesUtils.getPropertiesFromClasspath("MYSQL_DB.properties"); Yank.setupDataSource(dbProps); // query List<Book> allBooks = BooksDAO.selectAllBooks(); for (Book book : allBooks) { System.out.println(book.getTitle()); } Yank.releaseDataSource(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package org.knowm.yank.demo; import java.util.Properties; import org.knowm.yank.PropertiesUtils; import org.knowm.yank.Yank; /** * Selects Book count from the BOOKS table. */ public class SelectBookCount { public static void main(String[] args) { // DB Properties Properties dbProps = PropertiesUtils.getPropertiesFromClasspath("MYSQL_DB.properties"); Yank.setupDataSource(dbProps); // query long numBooks = BooksDAO.getNumBooks(); System.out.println("The number of books in the table are: " + numBooks); Yank.releaseDataSource(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
package org.knowm.yank.demo; import java.util.Properties; import org.knowm.yank.Yank; /** * Selects a single Book from the BOOKS table. Demonstrates using the Yank API without DAOs or properties. * * @author timmolter */ public class SelectBook { public static void main(String[] args) { // DB Properties Properties dbProps = new Properties(); dbProps.setProperty("jdbcUrl", "jdbc:mysql://localhost:3306/Yank"); dbProps.setProperty("username", "root"); dbProps.setProperty("password", ""); // add connection pool Yank.setupDataSource(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.releaseDataSource(); } } |