文章转载自拥抱JPA规范-segmentfault,若有侵权,请留言删除。
前言
在上文Hibernate使用中曾经提到过Hibernate是JPA实现的一个超集,但当时使用的都是原生Hibernate,在本文中我们将拥抱JPA规范,重构持久化层。
JPA+HIbernate配置
下面是ApplicationContxt文件
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="sbeat.model" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="hibernateJpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="dataSource" ref="dataSource" />
</bean>
JPA动态查询
CriteriaBuilder cb=entityManager.getCriteriaBuilder();
CriteriaQuery<T> query=cb.createQuery(clazz);
//clazz是你想要转换的类型,就是你的Entity.claa,如果你查的是count,就是Long.claa
Root<T> root=query.from(clazz);
query.select(root);//选取实体
//选择的条件
List<Predicate> predicates=new ArrayList<Predicate>();
predicates.add(cb.equal(..));
predicates.add(..);
...
query.where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
上面通过数组来组合与条件,还有一种方式:
Predicate predicate=cb.conjunction();//交集
predicate=cb.and(predicate,cb.equal(root.get("sex"),condition.get("sex")));
Predicate predicate=cb.disjunction();//并集
predicate=cb.or(predicate,cb.equal(root.get("sex"),condition.get("sex")));
JPA里面对类型控制比较严格,如下所示:
//比较大小
cb.gt(root.<Integer>get("degree"),(Integer) condition.get("degree"));
//like
cb.like(root.get("user").<String> get("nickName"),keyword)
//in 条件
root.get("tags").in(condition.get("tag"))
对于关联映射,如果是ToOne,你可以连写get
root.get("user").get("account");
对于ToMany的,你可以使用Join
CriteriaQuery<Parent> criteria = cb.createQuery((Class<Parent>) Parent.class);
Root<Parent> parent = criteria.from(Parent.class);
criteria.select((Selection<T>) parent);
SetJoin<Parent, Children> children = parent.joinSet("children", JoinType.LEFT);
Predicate sexPredicate = cb.equal(children.get("sex"), "MALE");
parent.fetch(children);
//parent.fetch("children");//try also this
criteria.where(sexPredicate);
JPA分页
取分页内容
TypedQuery<T> typedQuery=entityManager.createQuery(query);
typedQuery.setFirstResult((pageNum-1)*PAGE_SIZE);
typedQuery.setMaxResults(PAGE_SIZE);
取查询数目
CriteriaBuilder cb=entityManager.getCriteriaBuilder();
CriteriaQuery<Long> query=cb.createQuery(Long.class);
query.select(cb.count(query.from(clazz)));//选取实体
return entityManager.createQuery(query).getSingleResult();
JPA 动态更新
CriteriaBuilder cb=entityManager.getCriteriaBuilder();
CriteriaUpdate<T> op=cb.createCriteriaUpdate(clazz);
Root<T> root=op.from(clazz);
op.set(fieldName, value);
op.where(cb.equal(root.get(keyName), delta.get(keyName)));
entityManager.createQuery(op).executeUpdate();
JPQL
JPA的JPQL语句和Hibernate的HQL语句十分类似
Query query=entityManager.createQuery("SELECT r FROM Resume r WHERE r.user.id=:userId");
query.setParameter("id", userId);
return (Resume) query.getSingleResult();
JPA CRUD
public interface GenericDAO<T> {
public void insert(T t);
public void update(T t);
public void simpleUpdate(Map<Object, Object> delta);
public void delete(T t);
public T load(Long id);
public void refresh(T t);
public List<T> list(int pageNum);
public Long count();
public List<T> findByCondition(Map<Object,Object> condition);
public Long countByCondition(Map<Object,Object> condition);
}
@SuppressWarnings("unchecked")
public class GenericDAOImpl<T> implements GenericDAO<T> {
private Class<T> clazz;
@PersistenceContext
protected EntityManager entityManager;
protected Session getCurrentSession() {
return entityManager.unwrap(Session.class);
}
public GenericDAOImpl(){
//取得T的类型变量
ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
clazz = (Class<T>) type.getActualTypeArguments()[0];
}
public void insert(T t) {
entityManager.persist(t);
}
public void update(T t) {
entityManager.merge(t);
}
public void simpleUpdate(Map<Object, Object> delta) {
Field[] fields=clazz.getDeclaredFields();
CriteriaBuilder cb=entityManager.getCriteriaBuilder();
CriteriaUpdate<T> op=cb.createCriteriaUpdate(clazz);
Root<T> root=op.from(clazz);
String keyName="id";//默认选择基准为Id
//调整选择域
if(delta.containsKey("keyName")) keyName=(String) delta.get("keyName");
for(Field field:fields){
String fieldName=field.getName();
if(fieldName==keyName) continue;
if(delta.containsKey(fieldName)){
op.set(fieldName, delta.get(fieldName));
}
}
op.where(cb.equal(root.get(keyName), delta.get(keyName)));
entityManager.createQuery(op).executeUpdate();
}
public void delete(T t) {
entityManager.remove(t);
}
public T load(Long id) {
return (T) entityManager.find(clazz, id);
}
public List<T> list(int pageNum) {
CriteriaBuilder cb=entityManager.getCriteriaBuilder();
CriteriaQuery<T> query=cb.createQuery(clazz);
Root<T> root=query.from(clazz);
query.select(root);//选取实体
query.orderBy(cb.desc(root.get("created")));//排序
TypedQuery<T> typedQuery=entityManager.createQuery(query);
if(pageNum>0){
typedQuery.setFirstResult((pageNum-1)*SbeatConfig.PAGE_SIZE);
typedQuery.setMaxResults(SbeatConfig.PAGE_SIZE);
}
return typedQuery.getResultList();
}
public void refresh(T t) {
entityManager.refresh(t);
}
public Long count() {
//返回数目
CriteriaBuilder cb=entityManager.getCriteriaBuilder();
CriteriaQuery<Long> query=cb.createQuery(Long.class);
query.select(cb.count(query.from(clazz)));//选取实体
return entityManager.createQuery(query).getSingleResult();
}
public List<T> findByCondition( Map<Object, Object> condition) {
Field[] fields=clazz.getDeclaredFields();
CriteriaBuilder cb=entityManager.getCriteriaBuilder();
CriteriaQuery<T> query=cb.createQuery(clazz);
Root<T> root=query.from(clazz);
query.select(root);//选取实体
//选择的条件
List<Predicate> predicates=new ArrayList<Predicate>();
for(Field field:fields){
String fieldName=field.getName();
if(condition.containsKey(fieldName)){
predicates.add(cb.equal(root.get(fieldName), condition.get(fieldName)));
}
}
query.where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
query.orderBy(cb.desc(root.get("created")));
TypedQuery<T> typedQuery=entityManager.createQuery(query);
Integer pageNum=0;
if(condition.containsKey(pageNum)){
pageNum=(Integer) condition.get("pageNum");
}
if(pageNum>0){
typedQuery.setFirstResult((pageNum-1)*SbeatConfig.PAGE_SIZE);
typedQuery.setMaxResults(SbeatConfig.PAGE_SIZE);
}
return typedQuery.getResultList();
}
public Long countByCondition(Map<Object, Object> condition) {
Field[] fields=clazz.getDeclaredFields();
CriteriaBuilder cb=entityManager.getCriteriaBuilder();
CriteriaQuery<Long> query=cb.createQuery(Long.class);
Root<T> root=query.from(clazz);
query.select(cb.count(root));//选取实体
List<Predicate> predicates=new ArrayList<Predicate>();
for(Field field:fields){
String fieldName=field.getName();
if(condition.containsKey(fieldName)){
predicates.add(cb.equal(root.get(fieldName), condition.get(fieldName)));
}
}
query.where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
return entityManager.createQuery(query).getSingleResult();
}
}