welcome to xlongwei.com

欢迎大家一起学习、交流、分享


QQ:9167702333 邮箱:admin@xlongwei.com

Spring Data JPA


分类 Java   关键字 分享   标签 java   spring   jpa   发布 hongwei  1425740528867
注意 转载须保留原文链接,译文链接,作者译者等信息。  
我要赚钱:注册财富箱,享投资12%收益!


JPA指Java Persistence API,hibernate提供了一种具体实现,spring框架将相关组件聚合在一起。Spring Data JPA提供CrudRepository等接口供继承以实现数据存取,还可以根据命名规范添加自定义接口方法而不需要写任何实现代码。
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="dataSource" ref="dataSource" />
	<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
	<property name="packagesToScan" value="com.itecheast.ite.domain.entity" />
	<property name="jpaProperties">
		<props>
			<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
			<!-- <prop key="hibernate.hbm2ddl.auto">update</prop> -->
			<prop key="hibernate.show_sql">true</prop>
			<prop key="hibernate.format_sql">false</prop>				
		</props>
	</property>
</bean>
<bean id="hibernateJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
	<property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
</bean>
entityManagerFactory会扫描包packagesToScan里的@Entity实体类,并根据dateSource与数据库表相关联(ImprovedNamingStrategy支持实体类名到数据库表名的驼峰式映射,例如TsUser对应ts_user)。这里省略dataSource和transactionManager的配置。
<jpa:repositories base-package="com.itecheast.ite.domain.impl.repository" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory" />
扫描包base-package里的Repository接口,自动生成相应的接口实现并注入bean,服务层service接口实现需要@Autowired依赖这些存储接口。
@NoRepositoryBean
public  interface BaseRepository<T> extends JpaRepository<T, Long>, JpaSpecificationExecutor<T> {}
JpaRepository接口提供crud和分页接口,JpaSpecificationExecutor提供Specification查询接口,@NoRepositoryBean让jpa:repositories扫描时忽略。
public interface UserRepository extends BaseRepository<User> {
	User findByUserName(String userName);
	User findByEmail(String email);
}
UserRepository添加了自定义接口,命名规范参考下图:

下面再介绍一下BaseEntity和BaseService
@MappedSuperclass
@SuppressWarnings("serial")
public abstract class BaseEntity implements Serializable {
	@Id	@GeneratedValue(generator = "ite")    
	@GenericGenerator(name = "ite", strategy = "assigned")    
	private Long id;
	
	@Temporal(TemporalType.TIMESTAMP) @Column(updatable=false)
	private Date createAt;
	@Column(insertable=false)
	private boolean deleted;
	@Version @Column(insertable=false)
	private Integer version;
//省略getters和setters
	public String toString() {
		return getClass().getSimpleName()+"@"+getId();
	}
}
BaseEntity提供基础字段id、createAt、deleted和version。id手动生成,与自增id相比还是有许多好处的,后面会有IdService专门生成id。createAt记录了创建日期,deleted是删除标记,数据不完全删除也是有好处的。version是乐观锁字段,记录数据更新次数。toString输出实体名称和id值便于分析日志。
public interface BaseService<Entity> {
	Result<Entity> create(Entity entity);//添加记录
	Result<Entity> retrieve(Long entityId);//获取记录
	Result<Entity> update(Entity entity);//更新记录
	Result<Entity> delete(Long entityId);//删除记录,仅标记
	Result<Entity> delete(Entity entity);//删除记录,仅标记
	Result<PageObject<Entity>> page(SpecParam<Entity> specs, Pager pager);//分页查询
	Result<List<Entity>> list(SpecParam<Entity> specs);//全部记录
	Result<List<Entity>> collect(SpecParam<Entity> specs, Pager pager);//分页收集,耗内存,参考ServiceUtil.iterator
}
BaseService封装了基础接口crud增删改查和page分页接口等,Repository作为底层接口最好不要直接在front或Controller里使用。list对于数据较少的表可以全部列出数据,比如Category等信息全部读出并缓存。collect用于分页多次读取数据,比如有10万条记录,其中1万条需要处理,可以每页读取100条分10次读取,可能内存消耗还是比较大,后面的ServiceUtil.iterator支持在page接口的基础上依次处理每一条数据。
public abstract class BaseServiceImpl<Entity extends BaseEntity> implements BaseService<Entity> {
	@Autowired IdService idService;

	public abstract BaseRepository<Entity> getRepository();
	
	public Result<Entity> create(Entity entity) {
		if(NumberUtil.validateID(entity.getId())) return DomainErrors.Bad_ID(entity.getId());
		Result<Long> nextID = idService.next();
		if(!nextID.hasObject()) return Result.newFailure(nextID);
		entity.setId(nextID.getObject());
		Entity save = getRepository().save(entity);
		return Result.newSuccess(save);
	}

	public Result<Entity> update(Entity entity) {
		if(NumberUtil.validateID(entity.getId())) {
			Entity save = getRepository().save(entity);
			return Result.newSuccess(save);
		}
		return DomainErrors.Bad_ID(entity.getId());
	}

	public Result<Entity> retrieve(Long entityId) {
		if(NumberUtil.validateID(entityId)) {
			Entity entity = getRepository().findOne(entityId);
			if(entity!=null) return Result.newSuccess(entity);
		}
		return DomainErrors.Bad_ID(entityId);
	}

	public Result<Entity> delete(Long entityId) {
		if(NumberUtil.validateID(entityId)) {
			Entity entity = getRepository().findOne(entityId);
			if(entity!=null) {
				entity.setDeleted(true);
				Entity save = getRepository().save(entity);
				return Result.newSuccess(save);
			}
		}
		return DomainErrors.Bad_ID(entityId);
	}

	public Result<Entity> delete(Entity entity) {
		if(NumberUtil.validateID(entity.getId())) {
			entity.setDeleted(true);
			Entity save = getRepository().save(entity);
			return Result.newSuccess(save);
		}
		return DomainErrors.Bad_ID(entity.getId());
	}

	public Result<PageObject<Entity>> page(SpecParam<Entity> specs, Pager pager) {
		Page<Entity> findAll = getRepository().findAll(SpecUtil.spec(specs), PagerUtil.pagable(pager));
		return Result.newSuccess(PagerUtil.pageObject(findAll));
	}

	public Result<List<Entity>> list(SpecParam<Entity> specs) {
		List<Entity> findAll = getRepository().findAll(SpecUtil.spec(specs));
		return Result.newSuccess(findAll);
	}

	public Result<List<Entity>> collect(SpecParam<Entity> specs, Pager pager) {
		List<Entity> list = new ArrayList<>();
		Result<PageObject<Entity>> page = page(specs, pager);
		while(page.hasObject()) {
			if(pager.notInitialized()) pager.init(page.getObject().getTotal());
			list.addAll(page.getObject().getList());
			
			int currentPage = pager.getCurrentPage();
			if(currentPage>=pager.getTotalPages()) break;
			pager.page(pager.getCurrentPage()+1);
			
			page = page(specs, pager);
		}
		return Result.newSuccess(list);
	}

}
service实现类继承BaseServiceImpl后就已经具备了基础接口了,实现类主要就是提供底层存储接口FeedbackRepository。
@Service("feedbackService")
public class FeedbackServiceImpl extends BaseServiceImpl<Feedback> implements FeedbackService {
	@Autowired FeedbackRepository feedbackRepository;
	
	public BaseRepository<Feedback> getRepository() {
		return feedbackRepository;
	}
}
ServiceUtil.iterator代码供参考,iterator会自动获取下一页数据。
public class ServiceUtil {

	public static <Entity> Iterator<Entity> iterator(final BaseService<Entity> service, final SpecParam<Entity> specs, final Pager pager) {
		return new Iterator<Entity>() {
			private int page = 1, row = 0;
			private boolean hasNext = false;
			public boolean hasNext() {
				if(pager.notInitialized()) {//get page data
					Result<PageObject<Entity>> pageResult = service.page(specs, pager);
					if(pageResult.hasObject()) {
						PageObject<Entity> page = pageResult.getObject();
						pager.init(page.getTotal());
						pager.setElements(page.getList());
					}else {
						pager.init(0);
						pager.setElements(Collections.EMPTY_LIST);
					}
				}else if(row>=pager.getPageSize() && page<pager.getTotalPages()) {//get more data
					pager.page(++page);
					Result<PageObject<Entity>> pageResult = service.page(specs, pager);
					if(pageResult.hasObject()) {
						PageObject<Entity> page = pageResult.getObject();
						pager.setElements(page.getList());
						row = 0;
					}else {
						pager.setElements(Collections.EMPTY_LIST);
					}
				}
				hasNext = row<pager.getElements().size();
				return hasNext;
			}
			@SuppressWarnings("unchecked")
			public Entity next() {
				if(hasNext) {
					return (Entity)pager.getElements().get(row++);
				}
				return null;
			}
			public void remove() {
			}
		};
	}

}
评论列表