Java Spring Data

String Data Projects
  • Spring Data JPA - JPA persistence against a relational database
  • Spring Data MongoDB - Persistence to a Mongo document database
  • Spring Data Neo4j - Persistence to a Neo4j graph database
  • Spring Data Redis - Persistence to a Redis key-value store
  • Spring Data Cassandra - Persistence to a Cassandra database
Without Spring - usage of JDBC connections and resultSet Connection, PreparedStatement, ResultSet Examples
@Override
public Ingredient findOne(String id) {
	Connection connection = null;
	PreparedStatement statement = null;
	ResultSet resultSet = null;
	try {
		connection = dataSource.getConnection();
		statement = connection.prepareStatement(
		"select id, name, type from Ingredient");
		statement.setString(1, id);
		resultSet = statement.executeQuery();
		Ingredient ingredient = null;
		if(resultSet.next()) {
			ingredient = new Ingredient(
			resultSet.getString("id"),
			resultSet.getString("name"),
			Ingredient.Type.valueOf(resultSet.getString("type")));
		}
		return ingredient;
	} catch (SQLException e) {
		// ??? What should be done here ???
	} finally {
		if (resultSet != null) {
			try {
				resultSet.close();
			} catch (SQLException e) {}
		}
		if (statement != null) {
			try {
				statement.close();
			} catch (SQLException e) {}
		}

		if (connection != null) {
			try {
				connection.close();
			} catch (SQLException e) {}
		}
	}
	return null;
}
With Spring JDBC Template No need for cleanup, everything is closed automatically. Examples
private JdbcTemplate jdbc;

@Override
public Ingredient findOne(String id) {
	return jdbc.queryForObject(
		"select id, name, type from Ingredient where id=?", this::mapRowToIngredient, id);
}
private Ingredient mapRowToIngredient(ResultSet rs, int rowNum)
	throws SQLException {
		return new Ingredient(
			rs.getString("id"),
			rs.getString("name"),
			Ingredient.Type.valueOf(rs.getString("type"))
		);
}
Need Repository Interface as well as Implementation No need for cleanup, everything is closed automatically. Examples
import tacos.Ingredient;
public interface IngredientRepository {
	Iterable findAll();
	Ingredient findOne(String id);
	Ingredient save(Ingredient ingredient);
}

// ---------------------

import tacos.Ingredient;

@Repository
public class JdbcIngredientRepository implements IngredientRepository {
	private JdbcTemplate jdbc;

	@Autowired
	public JdbcIngredientRepository(JdbcTemplate jdbc) {
		this.jdbc = jdbc;
	}

	@Override
	public Iterable findAll() {
		return jdbc.query("select id, name, type from Ingredient", this::mapRowToIngredient);
	}
	@Override
	public Ingredient findOne(String id) {
		return jdbc.queryForObject(
			"select id, name, type from Ingredient where id=?",	this::mapRowToIngredient, id);
	}
	
	@Override
	public Ingredient save(Ingredient ingredient) {
		jdbc.update(
			"insert into Ingredient (id, name, type) values (?, ?, ?)",
			ingredient.getId(),
			ingredient.getName(),
			ingredient.getType().toString());
		return ingredient;
	}	
	
	private Ingredient mapRowToIngredient(ResultSet rs, int rowNum)
		throws SQLException {
			return new Ingredient(
				rs.getString("id"),
				rs.getString("name"),
				Ingredient.Type.valueOf(rs.getString("type"))
			);
	}	

}
Use KeyHolder and PreparedStatementCreator to get the ID of saved record Save Taco and ingredients Examples
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Arrays;
import java.util.Date;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import tacos.Ingredient;
import tacos.Taco;

@Repository
public class JdbcTacoRepository implements TacoRepository {
	private JdbcTemplate jdbc;
	public JdbcTacoRepository(JdbcTemplate jdbc) {
		this.jdbc = jdbc;
	}
	@Override
	public Taco save(Taco taco) {
		long tacoId = saveTacoInfo(taco);
		taco.setId(tacoId);
		for (Ingredient ingredient : taco.getIngredients()) {
			saveIngredientToTaco(ingredient, tacoId);
		}
		return taco;
	}
	private long saveTacoInfo(Taco taco) {
		taco.setCreatedAt(new Date());
		PreparedStatementCreator psc = new PreparedStatementCreatorFactory(
			"insert into Taco (name, createdAt) values (?, ?)", Types.VARCHAR, Types.TIMESTAMP
			).newPreparedStatementCreator(
				Arrays.asList(
				taco.getName(),
				new Timestamp(taco.getCreatedAt().getTime()))
			);
		KeyHolder keyHolder = new GeneratedKeyHolder();
		jdbc.update(psc, keyHolder);
		return keyHolder.getKey().longValue();
	}
	private void saveIngredientToTaco( Ingredient ingredient, long tacoId) {
		jdbc.update(
			"insert into Taco_Ingredients (taco, ingredient) " +
			"values (?, ?)",
			tacoId, ingredient.getId());
	}
}
JPA
Make Interface no need implementation
  • Annotate models as @Entity
  • Annotate IDs as @Id
  • Define no-arguments constructor for Entity (private)
  • Add attributes as needed @GeneratedValue, @Size, @Past (for dates), @OneToMany, @NotNull etc.
Customize Repositories Add methods to retrieve records Examples
other Interface methods In addition to an implicit Equals operation and the Between operation, Spring Data method signatures can also include any of these operators:
  • IsAfter, After, IsGreaterThan, GreaterThan
  • IsGreaterThanEqual, GreaterThanEqual
  • IsBefore, Before, IsLessThan, LessThan
  • IsLessThanEqual, LessThanEqual
  • IsBetween, Between
  • IsNull, Null
  • IsNotNull, NotNull
  • IsIn, In
  • IsNotIn, NotIn
  • IsStartingWith, StartingWith, StartsWith
  • IsEndingWith, EndingWith, EndsWith
  • IsContaining, Containing, Contains
  • IsLike, Like
  • IsNotLike, NotLike
  • IsTrue, True
  • IsFalse, False
  • Is, Equals
  • IsNot, Not
  • IgnoringCase, IgnoresCase
Summary Specify intermediate operations for transforming the initial stream into others, possibly in multiple steps. Intermediate - return Streams objects.
Apply a terminal (reduction) operation to produce a result. This operation forces the execution of the lazy operations that precede it. Afterwards, the stream can no longer be used.