Spring Data JPA 1.10.1 详解二之快速Demo

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Data JPA 1.10.1 详解二之快速Demo相关的知识,希望对你有一定的参考价值。

一、maven配置文件加入依赖


Spring Data JPA 依赖,最新稳定的版本为1.10.1.RELEASE,这里需要说明下的是,其依然依赖hibernate JPA相关JAR,hibernate-core之类的是不需要的。hibernate是JPA规范的一种实现,所以需要加入其依赖。ehcache是hibernate二级缓存的配置,不是必须的。

<dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>1.10.1.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-ehcache</artifactId>
    <version>5.1.0.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
	<artifactId>hibernate-validator</artifactId>
	<version>5.2.4.Final</version>
</dependency>
<dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-entitymanager</artifactId>
	<version>5.1.0.Final</version>
</dependency>

二、声明持久层接口


这里给大家说说几个常见的很重要的核心类文件,源码下面也贴上了。


技术分享


大家可以看到这个类的继承结构,这里值得说的是,Spring Data JPA的持久层的借口命名是有一套规范的,后面你加入的自定义方法满足其规范之后,你的实现类都是可以不需要写的,而且事务管理也帮你做好了。是不是觉得很神奇呢!

JpaRepository继承了PagingAndSortingRepository、QueryByExampleExecutor,PagingAndSortingRepository又继承了CrudRepository,CrudRepository 大家通过看名字也应该是干啥的,其就是CRUD的,PagingAndSortingRepository里面加了分页的相关方法。

CrudRepository.java

package org.springframework.data.repository;

import java.io.Serializable;

@NoRepositoryBean
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {

	<S extends T> S save(S entity);

	<S extends T> Iterable<S> save(Iterable<S> entities);

	T findOne(ID id);

	boolean exists(ID id);

	Iterable<T> findAll();

	Iterable<T> findAll(Iterable<ID> ids);

	long count();

	void delete(ID id);

	void delete(T entity);

	void delete(Iterable<? extends T> entities);

	void deleteAll();
}

Repository.java 是一个空的接口

package org.springframework.data.repository;

import java.io.Serializable;

public interface Repository<T, ID extends Serializable> {

}

大伙可以看看其源码,源码里面的注释我就不贴出来了,大家看方法名应该就知道其具体的意思了。
package org.springframework.data.jpa.repository;

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;

import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;

@NoRepositoryBean
public interface JpaRepository<T, ID extends Serializable>
		extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {

	List<T> findAll();

	List<T> findAll(Sort sort);

	List<T> findAll(Iterable<ID> ids);

	<S extends T> List<S> save(Iterable<S> entities);

	void flush();

	<S extends T> S saveAndFlush(S entity);

	void deleteInBatch(Iterable<T> entities);

	void deleteAllInBatch();

	T getOne(ID id);

	@Override
	<S extends T> List<S> findAll(Example<S> example);

	@Override
	<S extends T> List<S> findAll(Example<S> example, Sort sort);

}


大家用maven的时候,可以将源码顺便下下来,myeclipse里面设置一下即可,如图所示:

技术分享


我这里的接口如下:

package com.example.dao;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;

import com.example.entity.UserInfo;

public interface UserDaoSpringJpa extends JpaRepository<UserInfo,String>{

	public List<UserInfo> findByUsername(String username);//注意这个命名,Spring会自动根据这个username去数据库里面取值,可以看到后面生成的sql语句,where条件里面就加了 where user_name =?,这就是Spring Data JPA查询命名的方便之处,只要按规则命名,他会采取一定的策略,通过解析方法名称创建查询,来生成sql语句。
}


JpaRepository<UserInfo,String> 这里是泛型接口,UserInfo是我们的实体类,String是主键类型,也称为id,大家以前写hibernatebasedao的时候可能是见过了的。这叫 泛型限定式依赖注入,也是Spring4的一大特性。之前有篇博文也提到了 http://enetq.blog.51cto.com/479739/1783339


三、在接口中声明自定义业务方法

Spring Data JPA将会根据指定的策略(后续会有文章说明,本此只是简单的介绍下,能跑起来。)为该方法生成实现代码,用户不需要实现该接口,这样就只需要写接口就行了。


四、Spring配置文件相关配置

配置文件中加入 jpa:repositories,启用扫描并自动创建代理 Spring 初始化容器时将会扫描 base-package 指定的包目录及其子目录,为继承 Repository 或其子接口的接口创建代理对象,并将代理对象注册为 Spring Bean,业务层便可以通过 Spring autowired来直接使用该对象。


此需要jpa命名空间:

xmlns:jpa="

xsi:schemaLocation="
       http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
       "

具体的配置参加如下:各参数的含义配置文件里面已经给出了详细的解释,同时给出了相关配置类的源码。

技术分享

一些配置的属性,大家在源码里面也是可以找到的。

技术分享


 		 
<!-- 启用扫描并自动创建代理 Spring 初始化容器时将会扫描 base-package 指定的包目录及其子目录,
	为继承 Repository 或其子接口的接口创建代理对象,并将代理对象注册为 Spring Bean,
	业务层便可以通过 Spring autowired来直接使用该对象。 -->
	<jpa:repositories base-package="com.example.service"
		 entity-manager-factory-ref="entityManagerFactory" 
 		 transaction-manager-ref="transactionManager"/> 
 
 <!-- 通过entityManagerFactory的createEntityManager()方法获取EntityManager -->
    <bean id="entityManagerFactory"
          class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
          <!-- 指定数据源 -->
        <property name="dataSource" ref="dataSource"/>
        <property name="packagesToScan" value="com.example"/>
        <!-- 用于指定持久化实现厂商类 -->
        <property name="persistenceProvider">
            <bean class="org.hibernate.jpa.HibernatePersistenceProvider"/><!-- 替换 org.hibernate.ejb.HibernatePersistence -->
        </property>
        <!-- jpaVendorAdapter :用于设置实现厂商JPA实现的特定属性,
        	目前Spring提供了HibernateJpaVendorAdapter、OpenJpaVendorAdapter、EclipseLinkJpaVendorAdapter、
      		 三个实现。 TopLinkJpaVendorAdapter在Spring4里面已经删除了,
      		 目前支持的数据库如下: DB2, DERBY, H2, HSQL, INFORMIX, mysql, ORACLE, POSTGRESQL, SQL_SERVER, SYBASE,
      		 这个类型在Spring提供的枚举类型 Database 里面有详细定义-->
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="generateDdl" value="false"/>
                <property name="database" value="MYSQL"/>
                <property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
                <property name="showSql" value="true"/>
            </bean>
        </property>
        <!--    jpaDialect:用于指定一些高级特性,如事务管理,获取具有事务功能的连接对象等,
		        目前Spring提供HibernateJpaDialect、OpenJpaDialect 、EclipseLinkJpaDialect -->
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
        </property>
        <!-- 用于指定JPA属性,跟之前hibernateProperties是一致的 -->
        <property name="jpaPropertyMap">
            <map>
        
                <entry key="hibernate.dialect" value="${hibernate.dialect}"/> 
				<entry key="hibernate.show_sql" value="${hibernate.show_sql}"/>
				<entry key="hibernate.format_sql" value="false"/>
				<entry key="hibernate.query.substitutions" value="${hibernate.query.substitutions}"/>
				<entry key="hibernate.default_batch_fetch_size" value="${hibernate.default_batch_fetch_size}"/>
				<entry key="hibernate.max_fetch_depth" value="${hibernate.max_fetch_depth}"/>
				<entry key="hibernate.generate_statistics" value="${hibernate.generate_statistics}"/>
				<entry key="hibernate.bytecode.use_reflection_optimizer" value="${hibernate.bytecode.use_reflection_optimizer}"/>

				<!-- 缓存Cache配置 -->
				<entry  key="hibernate.cache.provider_class" value="${hibernate.cache.provider_class}"/>
				<entry key="hibernate.cache.use_second_level_cache" value="${hibernate.cache.use_second_level_cache}"/>
				<entry key="hibernate.cache.use_query_cache" value="${hibernate.cache.use_query_cache}"/>
				<entry key="hibernate.cache.region.factory_class" value="${hibernate.cache.region.factory_class}"/>
				<entry key="net.sf.ehcache.configurationResourceName" value="${net.sf.ehcache.configurationResourceName}"/>
				<entry key="hibernate.cache.use_structured_entries" value="${hibernate.cache.use_structured_entries}"/>
                
            </map>
        </property>
    </bean>
    
    <!--指定事务管理器-->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
 		


jpaVendorAdapter 相关参数的设置AbstractJpaVendorAdapter 类里面有详细说明:如下图所示:

技术分享

技术分享

五、测试

package com.example.action;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

import com.example.entity.UserInfo;
import com.example.service.impl.UserInfoService;
import com.google.gson.Gson;

@Controller
public class UserInfoAction {
	 
	@Autowired
	private UserInfoService userInfoService;
	 
	private Logger log = Logger.getLogger(this.getClass());

	@RequestMapping("findByUserName.do")
	public void findByUserName(HttpServletRequest request,
			HttpServletResponse response, ModelMap map) throws IOException{
		List<UserInfo> listUserInfo = userInfoService.findByUsername("wj");
		
		for(UserInfo userInfo:listUserInfo){
			log.info(userInfo.getUsername()+":"+userInfo.getEmail());
		}
		
		Gson gson = new Gson();
		String jsonStr = gson.toJson(listUserInfo);
		response.getWriter().println(jsonStr);
	}
	
	@RequestMapping("saveUser.do")
	public void saveUser(HttpServletRequest request,
			HttpServletResponse response, ModelMap map) throws IOException{
		List<UserInfo> listUserInfo = new ArrayList<UserInfo>();
		
		for(int i=0;i<10;i++){
			UserInfo userInfo = new UserInfo();
			
			userInfo.setId(UUID.randomUUID().toString());
			userInfo.setUsername(Math.random()+"wj"+i);
			userInfo.setPassword(Math.random()+"ss"+i);
			listUserInfo.add(userInfo);
		}
		
		listUserInfo = userInfoService.save(listUserInfo);//可以直接保存一个list集合,当然这里只是测试,实际的批量新增,批量更新的时候,是需要到一定的条数之后,flush一下的,比如20条,这根hibernate是类似的。
		
		userInfoService.delete("21");//删除
		
		UserInfo userInfo = userInfoService.findOne("2eab2884-e0e9-419c-8871-1d198b399813");
		userInfo.setUsername("zhangsan");
		userInfoService.saveAndFlush(userInfo);//更新
		Gson gson = new Gson();
		String jsonStr = gson.toJson(listUserInfo);
		response.getWriter().println(jsonStr);
	}
}

经过测试,大家发现 新增、查询、删除、修改都是正常的

Hibernate: select userinfo0_.id as id1_4_, userinfo0_.birthday as birthday2_4_, userinfo0_.contact as contact3_4_, userinfo0_.create_time as create_t4_4_, userinfo0_.create_user as create_u5_4_, userinfo0_.delete_flag as delete_f6_4_, userinfo0_.email as email7_4_, userinfo0_.last_login_ip as last_log8_4_, userinfo0_.last_login_time as last_log9_4_, userinfo0_.last_logout_time as last_lo10_4_, userinfo0_.modify_time as modify_11_4_, userinfo0_.online_state as online_12_4_, userinfo0_.password as passwor13_4_, userinfo0_.register_time as registe14_4_, userinfo0_.sex as sex15_4_, userinfo0_.user_state as user_st16_4_, userinfo0_.username as usernam17_4_ from rbac.user_info userinfo0_ where userinfo0_.username=?

Hibernate: insert into rbac.user_info (birthday, contact, create_time, create_user, delete_flag, email, last_login_ip, last_login_time, last_logout_time, modify_time, online_state, password, register_time, sex, user_state, username, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)

insert 语句打印了10条,


delete from rbac.user_info where id=?

Hibernate: update rbac.user_info set birthday=?, contact=?, create_time=?, create_user=?, delete_flag=?, email=?, last_login_ip=?, last_login_time=?, last_logout_time=?, modify_time=?, online_state=?, password=?, register_time=?, sex=?, user_state=?, username=? where id=?


本文出自 “幽灵柯南的技术blog” 博客,请务必保留此出处http://enetq.blog.51cto.com/479739/1784106

以上是关于Spring Data JPA 1.10.1 详解二之快速Demo的主要内容,如果未能解决你的问题,请参考以下文章

spring data jpa详解

spring-data详解之spring-data-jpa:简单三步快速上手spring-data-jpa开发

Spring-data-jpa详解

纯干货,Spring-data-jpa详解(转)

Spring-data-jpa详解,全方位介绍。

Spring-data-jpa详解,全方位介绍。