简介
在前一篇文章中,我们讨论了spring和jpa的集成实现。jpa本身是一个数据访问的规范,针对它有很多具体的实现。在这里,重点针对前面工程设计中一些地方进行改进。通过讨论这些值得改进的地方引入spring data jpa。在实际中我们会发现引入的东西居然和我们前面改进的思路是暗合的。
工程改进
在前一篇文章中,我们讨论过对工程的改进。在最开始的思路里,我们是定义了ContactService接口,在具体的ContactServiceImpl里直接引用sessionFactory或者EntityManager来操作数据。在这种情况下,我们的实际业务逻辑却直接和数据操作部分耦合起来了。于是,为了使得这部分不是紧密耦合的。我们定义了dao包,将真正数据访问的部分放在dao的实现里。
另外,考虑到对数据的基本增删查改算是最常用的操作。几乎每个对象都需要,我们完全可以定义一个通用的给其他dao实现来集成。因为要足够通用,我们采用泛型的参数接口。于是就得出了一个如下图的设计思路:
在这种实现里,我们定义了dao的抽象接口。理论上它可以进行CRUD操作的数据可以是继承自Object的任何对象。然后我们需要继承dao接口来定义自己的特定dao操作部分。而针对dao本身这些基础的crud操作就都由AbstractHbnDao实现了。我们定义自己的实现时只需要继承AbstractHbnDao,然后实现自定义的那部分接口就可以了 。
这种方式带来了不少的便利。当然,也带来了一个可以改进的地方。既然这个dao是用来针对通用的对象操作的。而且AbstractHbnDao也是定义的一个通用操作。那么可不可以直接将它们实现好作为一个通用的类库呢?这样以后我们就连这部分的定义都省了。真是基于这个观点,我们找到了spring data jpa。
引入spring data jpa
spring data jpa是一个通用的DAO框架。它除了支持基础的crud操作之外,还分页、排序和批处理操作。我们原来很多需要手工定义的dao类它都通过动态代理生成了。
spring data jpa的类结构图如下:
我们在工程中使用它们就比较简单了。首先定义一个自定义的dao接口。比如本例中的ContactDao:
package com.yunzero.dao; import java.util.List; import org.springframework.data.repository.CrudRepository; import com.yunzero.model.Contact; public interface ContactDao extends CrudRepository<Contact, Long> { List<Contact> findByEmailLike(String email); }
在这里我们可以看到,我们自定义的方法findByEmailLike。按照以往的思路,既然这是我们定义的方法,总该要我们自己去实现它吧?可是在这里,居然不用自己去实现它。我们看后续的代码:
ContactService:
package com.yunzero.service; import java.util.List; import com.yunzero.model.Contact; public interface ContactService { void createContact(Contact contact); List<Contact> getContacts(); List<Contact> getContactsByEmail(String email); Contact getContact(Long id); void updateContact(Contact contact); void deleteContact(Long id); }
真正重点的是ContactServiceImpl:
package com.yunzero.service.impl; import static org.springframework.util.Assert.notNull; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.inject.Inject; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.yunzero.dao.ContactDao; import com.yunzero.model.Contact; import com.yunzero.service.ContactService; @Service @Transactional public class ContactServiceImpl implements ContactService { @Inject private ContactDao contactDao; @Override public void createContact(Contact contact) { notNull(contact, "contact can't be null"); contactDao.save(contact); } @Override public List<Contact> getContacts() { Iterable<Contact> iterable = contactDao.findAll(); Iterator<Contact> iterator = iterable.iterator(); List<Contact> contacts = new ArrayList<Contact>(); while (iterator.hasNext()) { contacts.add(iterator.next()); } return contacts; } @Override public List<Contact> getContactsByEmail(String email) { notNull(email, "email can't be null"); return contactDao.findByEmailLike("%" + email + "%"); } @Override public Contact getContact(Long id) { notNull(id, "id can't be null"); return contactDao.findOne(id); } @Override public void updateContact(Contact contact) { notNull(contact, "contact can't be null"); contactDao.save(contact); } @Override public void deleteContact(Long id) { notNull(id, "id can't be null"); contactDao.delete(id); } }
这里最玄乎的就是contactDao有了save, delete等方法了。而实际上ContactDao继承的不是接口吗?而且更猛的是,我在ContactDao里定义的方法findByEmailLike没有定义实现居然可以拿来直接用!这一切看起来像魔法一样,实在是太不可思议了。
实际上,这一切就是spring data jpa的动态代理方法带来的好处。我们定义的方法只要按照它定义的规则来命名,它就可以通过反射将名字和各种操作方法和映射起来。有点convention over configuration的感觉哈。对于具体spring data jpa是怎么实现这些的,这里不再赘述,在后面的文章中会详细讨论。
配置
上面就是所有的代码了。除了前面代码部分,还要一个需要注意的就是配置。这里一个典型的配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:c="http://www.springframework.org/schema/c" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.8.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd"> <context:property-placeholder location="classpath:/environment.properties" /> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close" p:driverClassName="${dataSource.driverClassName}" p:url="${dataSource.url}" p:username="${dataSource.username}" p:password="${dataSource.password}" /> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" p:dataSource-ref="dataSource" p:packagesToScan="com.yunzero.model"> <property name="persistenceProvider"> <bean class="org.hibernate.jpa.HibernatePersistenceProvider" /> </property> <property name="jpaProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop> <prop key="hibernate.show_sql">false</prop> </props> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory" /> <tx:annotation-driven /> <jpa:repositories base-package="com.yunzero.dao" /> <context:component-scan base-package="com.yunzero.service.impl" /> </beans>
看起来和前面的配置没什么差别。唯一的一点就是引入了jpa的命名空间,并引入了这么一个配置。<jpa:repositories base-package="com.yunzero.dao" />
当然,在我们依赖的包里也需要引入spring-data-jpa,如下是一个典型的引用内容:
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>1.8.0.RELEASE</version> </dependency>
就只要这么几步,整个数据操作的部分就完成了。详细的实现可以参考后面的附件。
总结
spring data jpa是对dao方式操作数据的进一步优化。它带来的不仅仅是一个抽象的通用数据访问接口,更多的是一个按照命名规范自动生成的数据访问实现。这些玄妙之处值得后续好好学习。
相关推荐
Maven坐标:org.springframework.data:spring-data-jpa:2.0.9.RELEASE; 标签:springframework、data、spring、jpa、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,...
Spring Data JPA API。 Spring Data JPA 开发文档。 官网 Spring Data JPA API。
5-Spring-Boot(五):spring data jpa的使用.docx5-Spring-Boot(五):spring data jpa的使用.docx5-Spring-Boot(五):spring data jpa的使用.docx5-Spring-Boot(五):spring data jpa的使用.docx5-Spring-Boot(五):...
'SpringDataJPA从入门到精通'以SpringBoot为技术基础 从入门到精通 由浅入深地介绍SpringDataJPA的使用。有语法 有实践 有原理剖析。'SpringDataJPA从入门到精通'分为12章 内容包括整体认识JPA、JPA基础查询方法、...
spring-data-jpa知识。
Maven坐标:org.springframework.data:spring-data-jpa:2.0.9.RELEASE; 标签:springframework、data、spring、jpa、中英对照文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件...
spring注解完整版+spring data jpa官方文档中文翻译+JPA2.0官方文档 文档内容齐全 值得参考学习
Spring Data JPA中文文档1.4.3
1. The Spring Data Project 2. Repositories: Convenient Data Access Layers 3. Type-Safe Querying Using Querydsl . . Part II. Relational Databases 4. JPA Repositories 5. Type-Safe JDBC Programming with ...
第一章:Spring Data JPA入门 包括:是什么、能干什么、有什么、HelloWorld等 第二章:JpaRepository基本功能 包括:代码示例JpaRepository提供的CRUD功能,还有翻页、排序等功能 第三章:JpaRepository的查询 ...
技术架构:SpringMVC3+Spring3.1.2+Spring Data JPA+Maven 声明:该应用仅仅是技术研究:Spring Data JPA的配置和常见api的使用&maven构建项目,其他技术不在此研究 内涵sql和各种Spring Data JPA测试和案例,导入&...
4. Spring Data JPA: - eclipselink:展示了如何在Spring Boot和Eclipselink中使用Spring Data JPA的示例项目。 - example:包含了各种示例包,展示了使用Spring Data JPA的不同级别。可以查看simple包以获取最...
spring data jpa最新版本1.8.0,包含了spring-data-jpa-1.8.0.RELEASE.jar,spring-data-jpa-1.8.0.RELEASE-javadoc.jar以及 spring-data-jpa-1.8.0.RELEASE-sources.jar文档和源代码
NULL 博文链接:https://mixo44.iteye.com/blog/1797079
Database interaction using Spring and Hibernate/JPA- Spring Data JPA- Spring Data MongoDB- Messaging, emailing and caching support- Spring Web MVC- Developing RESTful web services using Spring Web ...
spring Data家族给我们提供了一个现成的dao层框架,这里面有不同的项目,如Spring Data JPA, Spring Data Neo4j and Spring Data MongoDB,他们的共同特点是他们给我们提供了框架代码,不再需要我们自己去实现了。
3. 与Spring全家桶结合紧密: 4. 成熟的框架和架构 常⻅的SQL性能问题,如何优雅处理? 2. 错综复杂的关联关系如何应对? 3. 万恶的LazyException本质是什么? 4. ⾼并发⾼性能要求的API服务要⽤JPA吗?
Spring Boot使用spring-data-jpa配置Mysql多数据源,可用版本