940 likes | 1.47k Views
Spring Data 简介. Mark Pollack 博士. 议题. 当前的数据形态 项目目标 项目概览. 企业数据趋势. 企业数据趋势. 非结构化数据 无预定义的数据模型 经常不大适合于 RDBMS 预聚合数据 在数据收集期间进行计算 计数器 运行平均数. 数据的价值. Mozilla/5.0 ( Macintosh ; U ; Intel Mac OS X; en ) AppleWebKit/418.9 ( KHTML ,比如 Gecko ) Safari/419.3. 数据的价值超越了软硬件成本 连接数据集的价值
E N D
Spring Data 简介 Mark Pollack 博士
议题 当前的数据形态 项目目标 项目概览
企业数据趋势 • 非结构化数据 • 无预定义的数据模型 • 经常不大适合于 RDBMS • 预聚合数据 • 在数据收集期间进行计算 • 计数器 • 运行平均数
数据的价值 Mozilla/5.0(Macintosh; U; Intel Mac OS X; en)AppleWebKit/418.9(KHTML,比如 Gecko)Safari/419.3 • 数据的价值超越了软硬件成本 • 连接数据集的价值 • 通过用户代理程序将电子商务用户组合起来
数据革命 • 极其难以/不可能在 RDBMS 中扩展写操作 • 纵向扩展受限制/成本高昂 • 横向扩展受限制或耗费资金 • 从 ACID 转换到 BASE • 基本可用、可扩展、最终一致性 • NoSQL 数据存储成为新兴的“点解决方案” • Amazon/Google 论文 • Facebook、LinkedIn …
NoSQL “不仅仅SQL” NOSQL\no-seek-wool\ n.描述当下的趋势,即开发人员越多越多地选择用非关系数据库来帮助解决其问题,试图使用合适的工具来完成合适的工作。 • 查询机制 • 关键字查询、映射缩减、按示例查询、查询语言、遍历
大数据 “大数据”是指规模过大,以至一般数据库软件工具无法进行数据捕获、存储、管理和分析的数据集。 一个主观性和不断移动的目标。 当今许多领域中的大数据的大小范围为从几十个 TB 到多个 PB
Spring Data – 背景和动机 • 数据访问形态已经发生天翻地覆的变化 • RDBMS 仍然占据重要和支配性的地位 • 但不再被视作“万金油”解决方案 • 但 RMBMS 具有局限性 • 难以扩展 • 新的数据访问技术正在解决 RMBMS 所无法解决的问题 • 更高的性能和可扩展性,不同的数据模型 • 常常受到限制的事务模型和松弛的一致性 • 坚持使用多种语言变得更普遍 • 在一个解决方案中将 RDBMS 与其他数据库相结合
Spring 和数据访问 • Spring 一直提供出色的数据访问支持 • 事务管理 • 可移植的数据访问异常层次结构 • JDBC – JdbcTemplate • ORM – 支持 Hibernate、JPA、JDO、Ibatis • 支持缓存 (Spring 3.1) • Spring Data 项目于 2010 年启动 • 目标是“刷新”Spring 的数据访问支持 • 参照新的数据访问形态
Spring Data 使命声明 89% of all virtualized applications in the world run on VMware. Gartner, December 2008 “ 为大数据、NoSQL 和关系存储提供熟悉、一致且基于 Spring 的编程模型,同时保留特定于存储的特性和功能。
Spring Data 使命声明 89% of all virtualized applications in the world run on VMware. Gartner, December 2008 “ 为大数据、NoSQL 和关系存储提供熟悉、一致且基于 Spring 的编程模型,同时保留特定于存储的特性和功能。
Spring Data 使命声明 89% of all virtualized applications in the world run on VMware. Gartner, December 2008 “ 特定于存储的特性和功能。
Spring Data – 支持的技术 • 大数据 • Hadoop • HDFS 和 M/R • Hive • Pig • Cascading • Splunk • 访问 • 资源库 • QueryDSL • REST • 关系型 • JPA • JDBC 扩展 • NoSQL • Redis • HBase • Mongo • Neo4j • Lucene • Gemfire
Spring Data – 一切由您做主 • 共享的编程模型和数据访问机制 • 资源库模型 • 跨数据存储的公用 CRUD • 与 QueryDSL 集成 • 类型安全的查询语言 • REST 导出器 • 以基于 REST 的方式通过 HTTP 公开资源库。 • 通过熟悉的 Spring 模板样式访问特定于数据库的特性 • RedisTemplate • HBaseTemplate • MongoTemplate • Neo4jTemplate • GemfireTemplate
Spring Data JDBC 扩展 – Oracle 支持 • 轻松访问本机 XML、Struct、Array 数据类型 • 用于自定义连接环境的 API • 快速连接故障转移 • 高级队列 JMS 支持和数据源的简化配置 • 消息传送和数据库访问的单一本地事务
QueryDSL “ 支持为多个后端(包括 JPA、JDO、MongoDB、Lucence、SQL 和 Java 中的普通集合)构造类型安全的类似 SQL 的查询 • http://www.querydsl.com/- 开源,Apache 2.0
使用字符串作为查询语言的问题 使用字符串容易出错 必须记住查询语法、域类、属性和关系 按照名称或位置的冗长参数绑定 每个后端都拥有其自身的查询语言和 API 注释:.NET 含有 LINQ
QueryDSL 特性 QCustomer customer = QCustomer.customer; JPQLQuery query = new JPAQuery(entityManger) Customer bob = query.from(customer) .where(customer.firstName.eq(“Bob”) .uniqueResult(customer) • 在 IDE 中完成编码 • 几乎完全禁止语法无效的查询 • 域类型和属性可以安全引用(无字符串) • 通过 Java 注释处理程序生成帮助程序类 • 冗长性远小于 JPA2 标准的 API
将 QueryDSL 用于 JDBC QAddress qAddress = QAddress.address; SQLTemplates dialect = new HSQLDBTemplates(); SQLQuery query = new SQLQueryImpl(connection, dialect) .from(qAddress) .where(qAddress.city.eq("London")); List<Address> results = query.list(new QBean<Address>(Address.class, qAddress.street, qAddress.city, qAddress.country)); Querydsl 判定 • 将代码生成融入到构建流程中 • 以创建域类或表格 (JDBC) 的查询元数据模型 • 对于 SQL
Spring JDBC 扩展 – QueryDslJdbcTemplate • 支持的 JdbcTemplate打包程序 • 使用 Querydsl SQLQuery 类来执行查询 • 与 Spring 的事务管理集成 • 自动检测数据库类型并设置 SQLTemplates 方言 • 用于映射到 POJO 的 Spring RowMapper 和 ResultSetExtractors • 通过 Querds 的 SQLInsertClause、SQLUpdateClause 和SQLDeleteClause 执行插入、更新和删除
Spring JDBC 扩展 – QueryDslJdbcTemplate // Query with join QCustomer qCustomer = QCustomer.customer; SQLQuery findByIdQuery = qdslTemplate.newSqlQuery() .from(qCustomer) .leftJoin(qCustomer._addressCustomerRef, qAddress) .where(qCustomer.id.eq(id));
资源库 通过使用类似集合的接口来访问域对象,在域和数据映射层之间进行调解。 http://martinfowler.com/eaaCatalog/repository.html
Spring Data 资源库 有了 Spring Data 资源库,您将不必忙于开发资源库
例如… publicinterface CustomerRepository { Customer findOne(Long id); Customer save(Customer customer); Customer findByEmailAddress(EmailAddress emailAddress); } @Entity publicclass Customer { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(unique = true) private EmailAddress emailAddress; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "customer_id") private Set<Address> addresses = new HashSet<Address>(); // constructor, properties, equals, hashcode omitted for brevity }
传统 JPA 实施 @Repository public class JpaCustomerRepository implements CustomerRepository { @PersistenceContext private EntityManager em; @Override public Customer findOne(Long id) { returnem.find(Customer.class, id); } public Customer save(Customer customer) { if (customer.getId() == null) { em.persist(customer); return customer; } else { returnem.merge(customer); } } ...
传统 JPA 实施 . . . @Override public Customer findByEmailAddress(EmailAddress emailAddress) { TypedQuery<Customer> query = em.createQuery("select c from Customer c where c.emailAddress = :email", Customer.class); query.setParameter("email", emailAddress); return query.getSingleResult(); } }
Spring Data 资源库 • 简单的方法 • 使用 JPA 来映射 POJO • 扩展资源库(标记)接口或使用注释 • 添加查询程序方法 • 配置 Spring 来扫描资源库接口并创建实施 • 将实施注入到服务中,并正常使用…
Spring Data 资源库示例 publicinterface CustomerRepository extends Repository<Customer, Long> { // Marker Interface Customer findOne(Long id); Customer save(Customer customer); Customer findByEmailAddress(EmailAddress emailAddress); } @RepositoryDefinition(domainClass=Customer.class, idClass=Long.class) publicinterface CustomerRepository { . . . } 或
Spring Data 资源库示例 @Configuration @EnableJpaRepositories @Import(InfrastructureConfig.class) publicclass ApplicationConfig { } <jpa:repositories base-package="com.oreilly.springdata.jpa" /> 具有 JavaConfig 的 Boostratp 或 XML Spring 将创建接口实施
Spring Data JPA – 用法 正常地融入到事务服务层中
查询方法关键字 findByEmailAddres 的工作原理…
Spring Data 资源库 – CRUD publicinterface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> { T save(T entity); Iterable<T> save(Iterable<? extends T> entities); T findOne(ID id); boolean exists(ID id); Iterable<T> findAll(); long count(); void delete(ID id); void delete(T entity); void delete(Iterable<? extends T> entities); void deleteAll(); }
切换、排序和自定义查找程序 publicinterface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> { Iterable<T> findAll(Sort sort); Page<T> findAll(Pageable pageable); } publicinterfacePersonRepositoryextendsCrudRepository<Person,BigInteger> { // Finder for a single entity Person findByEmailAddress(String emailAddress); // Finder for a multiple entities List<Person> findByLastnameLike(String lastName); // Finder with pagination Page<Person> findByFirstnameLike(String firstName, Pageable page); }
Spring Data JPA –自定义查询方法 publicinterfaceCustomerRepositoryextendsCrudRepository<Customer,Long> { // previous methods omitted… @Query("select p from Person p where p.emailAddress = ?1") Person findByEmailAddress(String emailAddress); @Query("select p from Person p where p.firstname = :firstname or p.lastname = :lastname") Person findByLastnameOrFirstname(@Param("lastname") String lastname, @Param("firstname") String firstname); } • 查询方法使用方法命名约定 • 可以用查询注释覆盖 • 或者方法名称引用 JPA 命名的查询
Spring Data JPA – 其他特性 使用 JPA 标准的 API 进行指定 锁定模式,覆盖事务元数据、查询提示 审查、 CDI 集成 支持 QueryDSL
Querydsl 和 JPA CriteriaBuilder builder = entityManagerFactory.getCriteriaBuilder(); CriteriaQuery<Person> query = builder.createQuery(Person.class); Root<Person> men = query.from( Person.class ); Root<Person> women = query.from( Person.class ); Predicate menRestriction = builder.and( builder.equal( men.get( Person_.gender ), Gender.MALE ), builder.equal( men.get( Person_.relationshipStatus ), RelationshipStatus.SINGLE ) ); Predicate womenRestriction = builder.and( builder.equal( women.get( Person_.gender ), Gender.FEMALE ), builder.equal( women.get( Person_.relationshipStatus ),RelationshipStatus.SINGLE ) ); query.where( builder.and( menRestriction, womenRestriction ) ); • 更简单、冗长性更低和 JPA2 标准的 API • “等于属性值”与“属性等于值” • 通过构建程序对象进行操作
Querydsl 和 JPA JPAQuery query = new JPAQuery(entityManager); QPerson men = new QPerson("men"); QPerson women = new QPerson("women"); query.from(men, women).where(men.gender.eq(Gender.MALE), men.relationshipStatus.eq(RelationshipStatus.SINGLE), women.gender.eq(Gender.FEMALE), women.relationshipStatus.eq(RelationshipStatus.SINGLE)); Querydsl 判定 与…
QueryDSL – 资源库 publicinterface QueryDSLPredicateExecutor<T> { long count(com.mysema.query.types.Predicate predicate); T findOne(Predicate predicate); List<T> findAll(Predicate predicate); List<T> findAll(Predicate predicate, OrderSpecifier<?>... orders); Page<T> findAll(Predicate predicate, Pageable pageable); } public interface ProductRepository extends Repository<Product,Long>, QueryDslPredicateExecutor<Product> { … } Product iPad = productRepository.findOne(product.name.eq("iPad")); Predicate tablets = product.description.contains("tablet"); Iterable<Product> result = productRepository.findAll(tablets);
键/值 比较熟悉,与哈希表格非常类似 Redis、Riak、Voldemort,… 受 Amazon Dynamo 启发
列系列 • 扩展的键/值模型 • 值可以为键/值对 • HBase、Cassandra • 受 Google Bigtable 启发