From fa92d1db3d3fb1b0ddd4573c41717f909466b244 Mon Sep 17 00:00:00 2001 From: araknoid Date: Sat, 6 Jan 2018 20:38:33 +0100 Subject: [PATCH] BAEL-1419: Guide to cockroachDB in Java (#3325) * adding CockroachDB code * Fixed database name * Added handling transaction examples --- .../java-cockroachdb/README.md | 2 + persistence-modules/java-cockroachdb/pom.xml | 74 +++++++ .../baeldung/cockroachdb/domain/Article.java | 43 ++++ .../repository/ArticleRepository.java | 172 +++++++++++++++ .../ArticleRepositoryIntegrationTest.java | 208 ++++++++++++++++++ pom.xml | 1 + 6 files changed, 500 insertions(+) create mode 100644 persistence-modules/java-cockroachdb/README.md create mode 100644 persistence-modules/java-cockroachdb/pom.xml create mode 100644 persistence-modules/java-cockroachdb/src/main/java/com/baeldung/cockroachdb/domain/Article.java create mode 100644 persistence-modules/java-cockroachdb/src/main/java/com/baeldung/cockroachdb/repository/ArticleRepository.java create mode 100644 persistence-modules/java-cockroachdb/src/test/java/com/baeldung/cockroachdb/ArticleRepositoryIntegrationTest.java diff --git a/persistence-modules/java-cockroachdb/README.md b/persistence-modules/java-cockroachdb/README.md new file mode 100644 index 0000000000..0f0381212d --- /dev/null +++ b/persistence-modules/java-cockroachdb/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Guide to CockroachDB in Java](http://www.baeldung.com/) diff --git a/persistence-modules/java-cockroachdb/pom.xml b/persistence-modules/java-cockroachdb/pom.xml new file mode 100644 index 0000000000..2b6f9651bc --- /dev/null +++ b/persistence-modules/java-cockroachdb/pom.xml @@ -0,0 +1,74 @@ + + + + + parent-modules + com.baeldung + 1.0.0-SNAPSHOT + ../../ + + + 4.0.0 + + com.baeldung + java-cockroachdb + 1.0-SNAPSHOT + + + 42.1.4 + + + + + org.postgresql + postgresql + ${postgresql.version} + + + + + + integration + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration-test + + test + + + + **/*ManualTest.java + + + **/*IntegrationTest.java + + + + + + + json + + + + + + + + + + + Central + Central + http://repo1.maven.org/maven2/ + default + + + \ No newline at end of file diff --git a/persistence-modules/java-cockroachdb/src/main/java/com/baeldung/cockroachdb/domain/Article.java b/persistence-modules/java-cockroachdb/src/main/java/com/baeldung/cockroachdb/domain/Article.java new file mode 100644 index 0000000000..dcc9dfb5b7 --- /dev/null +++ b/persistence-modules/java-cockroachdb/src/main/java/com/baeldung/cockroachdb/domain/Article.java @@ -0,0 +1,43 @@ +package com.baeldung.cockroachdb.domain; + +import java.util.UUID; + +public class Article { + + private UUID id; + + private String title; + + private String author; + + public Article(UUID id, String title, String author) { + this.id = id; + this.title = title; + this.author = author; + } + + public UUID getId() { + return id; + } + + public void setId(UUID 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; + } + +} diff --git a/persistence-modules/java-cockroachdb/src/main/java/com/baeldung/cockroachdb/repository/ArticleRepository.java b/persistence-modules/java-cockroachdb/src/main/java/com/baeldung/cockroachdb/repository/ArticleRepository.java new file mode 100644 index 0000000000..a37c19e397 --- /dev/null +++ b/persistence-modules/java-cockroachdb/src/main/java/com/baeldung/cockroachdb/repository/ArticleRepository.java @@ -0,0 +1,172 @@ +package com.baeldung.cockroachdb.repository; + +import com.baeldung.cockroachdb.domain.Article; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * Repository for the articles table related operations + */ +public class ArticleRepository { + + private static final String TABLE_NAME = "articles"; + private Connection connection; + + public ArticleRepository(Connection connection) { + this.connection = connection; + } + + /** + * Creates the articles table. + */ + public void createTable() throws SQLException { + StringBuilder sb = new StringBuilder("CREATE TABLE IF NOT EXISTS ").append(TABLE_NAME) + .append("(id uuid PRIMARY KEY, ") + .append("title string,") + .append("author string)"); + + final String query = sb.toString(); + Statement stmt = connection.createStatement(); + stmt.execute(query); + } + + /** + * Alter the articles table adding a column + * + * @param columnName Column name of the additional column + * @param columnType Column type of the additional column + * @throws SQLException + */ + public void alterTable(String columnName, String columnType) throws SQLException { + StringBuilder sb = new StringBuilder("ALTER TABLE ").append(TABLE_NAME) + .append(" ADD ") + .append(columnName) + .append(" ") + .append(columnType); + + final String query = sb.toString(); + Statement stmt = connection.createStatement(); + stmt.execute(query); + } + + /** + * Insert a new article in the articles table + * + * @param article New article to insert + * @throws SQLException + */ + public void insertArticle(Article article) throws SQLException { + StringBuilder sb = new StringBuilder("INSERT INTO ").append(TABLE_NAME) + .append("(id, title, author) ") + .append("VALUES (?,?,?)"); + + final String query = sb.toString(); + PreparedStatement preparedStatement = connection.prepareStatement(query); + preparedStatement.setString(1, article.getId().toString()); + preparedStatement.setString(2, article.getTitle()); + preparedStatement.setString(3, article.getAuthor()); + preparedStatement.execute(); + } + + /** + * Select article by Title + * + * @param title title of the article to retrieve + * @return article with the given title + * @throws SQLException + */ + public Article selectByTitle(String title) throws SQLException { + StringBuilder sb = new StringBuilder("SELECT * FROM ").append(TABLE_NAME) + .append(" WHERE title = ?"); + + final String query = sb.toString(); + PreparedStatement preparedStatement = connection.prepareStatement(query); + preparedStatement.setString(1, title); + + try (ResultSet rs = preparedStatement.executeQuery()) { + + List
articles = new ArrayList<>(); + + while (rs.next()) { + Article article = new Article( + UUID.fromString(rs.getString("id")), + rs.getString("title"), + rs.getString("author") + ); + articles.add(article); + } + return articles.get(0); + } + + } + + /** + * Select all the articles + * + * @return list of all articles + * @throws SQLException + */ + public List
selectAll() throws SQLException { + StringBuilder sb = new StringBuilder("SELECT * FROM ").append(TABLE_NAME); + + final String query = sb.toString(); + PreparedStatement preparedStatement = connection.prepareStatement(query); + try (ResultSet rs = preparedStatement.executeQuery()) { + + List
articles = new ArrayList<>(); + + while (rs.next()) { + Article article = new Article( + UUID.fromString(rs.getString("id")), + rs.getString("title"), + rs.getString("author") + ); + articles.add(article); + } + return articles; + } + } + + /** + * Delete article by title + * + * @param title title of the article to delete + * @throws SQLException + */ + public void deleteArticleByTitle(String title) throws SQLException { + StringBuilder sb = new StringBuilder("DELETE FROM ").append(TABLE_NAME) + .append(" WHERE title = ?"); + + final String query = sb.toString(); + PreparedStatement preparedStatement = connection.prepareStatement(query); + preparedStatement.setString(1, title); + preparedStatement.execute(); + } + + /** + * Delete all rows in the table + * + * @throws SQLException + */ + public void truncateTable() throws SQLException { + StringBuilder sb = new StringBuilder("TRUNCATE TABLE ").append(TABLE_NAME); + + final String query = sb.toString(); + Statement stmt = connection.createStatement(); + stmt.execute(query); + } + + /** + * Delete table + */ + public void deleteTable() throws SQLException { + StringBuilder sb = new StringBuilder("DROP TABLE IF EXISTS ").append(TABLE_NAME); + + final String query = sb.toString(); + Statement stmt = connection.createStatement(); + stmt.execute(query); + } +} diff --git a/persistence-modules/java-cockroachdb/src/test/java/com/baeldung/cockroachdb/ArticleRepositoryIntegrationTest.java b/persistence-modules/java-cockroachdb/src/test/java/com/baeldung/cockroachdb/ArticleRepositoryIntegrationTest.java new file mode 100644 index 0000000000..9eb00b3651 --- /dev/null +++ b/persistence-modules/java-cockroachdb/src/test/java/com/baeldung/cockroachdb/ArticleRepositoryIntegrationTest.java @@ -0,0 +1,208 @@ +package com.baeldung.cockroachdb; + +import com.baeldung.cockroachdb.domain.Article; +import com.baeldung.cockroachdb.repository.ArticleRepository; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.postgresql.util.PSQLException; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class ArticleRepositoryIntegrationTest { + + private static final String TABLE_NAME = "articles"; + + private Connection con; + private ArticleRepository articleRepository; + + @Before + public void connect() throws Exception { + Class.forName("org.postgresql.Driver"); + con = DriverManager.getConnection("jdbc:postgresql://localhost:26257/testdb", "user17", "qwerty"); + + articleRepository = new ArticleRepository(con); + } + + @Test + public void whenCreatingTable_thenCreatedCorrectly() throws Exception { + articleRepository.deleteTable(); + articleRepository.createTable(); + + PreparedStatement preparedStatement = con.prepareStatement("SHOW TABLES"); + ResultSet resultSet = preparedStatement.executeQuery(); + List tables = new ArrayList<>(); + while (resultSet.next()) { + tables.add(resultSet.getString("Table")); + } + + assertTrue(tables.stream().anyMatch(t -> t.equals(TABLE_NAME))); + } + + @Test + public void whenAlteringTheTable_thenColumnAddedCorrectly() throws SQLException { + articleRepository.deleteTable(); + articleRepository.createTable(); + + String columnName = "creationdate"; + articleRepository.alterTable(columnName, "DATE"); + + String query = "SHOW COLUMNS FROM " + TABLE_NAME; + PreparedStatement preparedStatement = con.prepareStatement(query); + ResultSet resultSet = preparedStatement.executeQuery(); + List columns = new ArrayList<>(); + while (resultSet.next()) { + columns.add(resultSet.getString("Field")); + } + + assertTrue(columns.stream().anyMatch(c -> c.equals(columnName))); + } + + @Test + public void whenInsertingNewArticle_thenArticleExists() throws SQLException { + articleRepository.deleteTable(); + articleRepository.createTable(); + + String title = "Guide to CockroachDB in Java"; + String author = "baeldung"; + Article article = new Article(UUID.randomUUID(), title, author); + articleRepository.insertArticle(article); + + Article savedArticle = articleRepository.selectByTitle(title); + assertEquals(article.getTitle(), savedArticle.getTitle()); + } + + @Test + public void whenSelectingAllArticles_thenAllArticlesAreReturned() throws SQLException { + articleRepository.deleteTable(); + articleRepository.createTable(); + + Article article = new Article(UUID.randomUUID(), "Guide to CockroachDB in Java", "baeldung"); + articleRepository.insertArticle(article); + + article = new Article(UUID.randomUUID(), "A Guide to MongoDB with Java", "baeldung"); + articleRepository.insertArticle(article); + + List
savedArticles = articleRepository.selectAll(); + + assertEquals(2, savedArticles.size()); + assertTrue(savedArticles.stream().anyMatch(a -> a.getTitle().equals("Guide to CockroachDB in Java"))); + assertTrue(savedArticles.stream().anyMatch(a -> a.getTitle().equals("A Guide to MongoDB with Java"))); + } + + @Test + public void whenDeletingArticleByTtile_thenArticleIsDeleted() throws SQLException { + articleRepository.deleteTable(); + articleRepository.createTable(); + + Article article = new Article(UUID.randomUUID(), "Guide to CockroachDB in Java", "baeldung"); + articleRepository.insertArticle(article); + + article = new Article(UUID.randomUUID(), "A Guide to MongoDB with Java", "baeldung"); + articleRepository.insertArticle(article); + + articleRepository.deleteArticleByTitle("A Guide to MongoDB with Java"); + + List
savedArticles = articleRepository.selectAll(); + assertEquals(1, savedArticles.size()); + assertTrue(savedArticles.stream().anyMatch(a -> a.getTitle().equals("Guide to CockroachDB in Java"))); + assertFalse(savedArticles.stream().anyMatch(a -> a.getTitle().equals("A Guide to MongoDB with Java"))); + } + + @Test(expected = PSQLException.class) + public void whenDeletingATable_thenExceptionIfAccessed() throws SQLException { + articleRepository.createTable(); + articleRepository.deleteTable(); + + StringBuilder sb = new StringBuilder("SELECT * FROM ").append(TABLE_NAME); + + final String query = sb.toString(); + PreparedStatement preparedStatement = con.prepareStatement(query); + preparedStatement.executeQuery(); + } + + @Test + public void whenTruncatingATable_thenEmptyTable() throws SQLException { + articleRepository.deleteTable(); + articleRepository.createTable(); + + Article article = new Article(UUID.randomUUID(), "Guide to CockroachDB in Java", "baeldung"); + articleRepository.insertArticle(article); + + article = new Article(UUID.randomUUID(), "A Guide to MongoDB with Java", "baeldung"); + articleRepository.insertArticle(article); + + articleRepository.truncateTable(); + + List
savedArticles = articleRepository.selectAll(); + assertEquals(0, savedArticles.size()); + } + + @Test + public void whenInsertingTwoArticlesWithSamePrimaryKeyInASingleTransaction_thenRollback() throws SQLException { + articleRepository.deleteTable(); + articleRepository.createTable(); + + try { + con.setAutoCommit(false); + + UUID articleId = UUID.randomUUID(); + + Article article = new Article(articleId, "Guide to CockroachDB in Java", "baeldung"); + articleRepository.insertArticle(article); + + article = new Article(articleId, "A Guide to MongoDB with Java", "baeldung"); + articleRepository.insertArticle(article); + + con.commit(); + } catch (Exception e) { + con.rollback(); + } finally { + con.setAutoCommit(true); + } + + List
savedArticles = articleRepository.selectAll(); + assertEquals(0, savedArticles.size()); + } + + @Test + public void whenInsertingTwoArticlesInASingleTransaction_thenInserted() throws SQLException { + articleRepository.deleteTable(); + articleRepository.createTable(); + + try { + con.setAutoCommit(false); + + Article article = new Article(UUID.randomUUID(), "Guide to CockroachDB in Java", "baeldung"); + articleRepository.insertArticle(article); + + article = new Article(UUID.randomUUID(), "A Guide to MongoDB with Java", "baeldung"); + articleRepository.insertArticle(article); + + con.commit(); + } catch (Exception e) { + con.rollback(); + } finally { + con.setAutoCommit(true); + } + + List
savedArticles = articleRepository.selectAll(); + assertEquals(2, savedArticles.size()); + assertTrue(savedArticles.stream().anyMatch(a -> a.getTitle().equals("Guide to CockroachDB in Java"))); + assertTrue(savedArticles.stream().anyMatch(a -> a.getTitle().equals("A Guide to MongoDB with Java"))); + } + + @After + public void disconnect() throws SQLException { + articleRepository = null; + con.close(); + con = null; + } +} diff --git a/pom.xml b/pom.xml index 68edf19cb2..1050bb8ba2 100644 --- a/pom.xml +++ b/pom.xml @@ -269,6 +269,7 @@ deeplearning4j lucene vraptor + persistence-modules/java-cockroachdb