5

前言

在上文Hibernate使用中曾经提到过Hibernate是JPA实现的一个超集,但当时使用的都是原生Hibernate,在本文中我们将拥抱JPA规范,重构持久化层。

JPA+HIbernate配置

下面是ApplicationContxt文件

XML<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动态查询

javaCriteriaBuilder 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()])));

上面通过数组来组合与条件,还有一种方式:

javaPredicate 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里面对类型控制比较严格,如下所示:

java//比较大小
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

javaCriteriaQuery<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分页

取分页内容

javaTypedQuery<T> typedQuery=entityManager.createQuery(query);
typedQuery.setFirstResult((pageNum-1)*PAGE_SIZE);
typedQuery.setMaxResults(PAGE_SIZE);

取查询数目

javaCriteriaBuilder cb=entityManager.getCriteriaBuilder();
CriteriaQuery<Long> query=cb.createQuery(Long.class);
query.select(cb.count(query.from(clazz)));//选取实体
return entityManager.createQuery(query).getSingleResult();

JPA 动态更新

javaCriteriaBuilder 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语句十分类似

javaQuery query=entityManager.createQuery("SELECT r FROM Resume r WHERE r.user.id=:userId");
query.setParameter("id", userId);
return (Resume) query.getSingleResult();

JPA CRUD

javapublic 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();
    }

}


suemi
1.5k 声望102 粉丝

程序猿一只,研究僧一枚