您的位置:首页 > 编程语言 > Java开发

spring学习:spring data jpa

2018-01-15 00:00 435 查看

工程改进

在前一篇文章中,我们讨论过对工程的改进。在最开始的思路里,我们是定义了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:

Java代码


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:

Java代码


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:

Java代码


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是怎么实现这些的,这里不再赘述,在后面的文章中会详细讨论。

配置

上面就是所有的代码了。除了前面代码部分,还要一个需要注意的就是配置。这里一个典型的配置如下:

Java代码


<?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,如下是一个典型的引用内容:

Java代码


<dependency>

<groupId>org.springframework.data</groupId>

<artifactId>spring-data-jpa</artifactId>

<version>1.8.0.RELEASE</version>

</dependency>

就只要这么几步,整个数据操作的部分就完成了。详细的实现可以参考后面的附件。

总结

spring data jpa是对dao方式操作数据的进一步优化。它带来的不仅仅是一个抽象的通用数据访问接口,更多的是一个按照命名规范自动生成的数据访问实现。这些玄妙之处值得后续好好学习。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  jpa2web