JPA的泛型DAO设计及使用
2024-10-18 14:38:32
- 使用如Hibernate或者JPA作为持久化的解决方案时,设计一个泛型的DAO抽象父类可以方便各个实体的通用CRUD操作。由于此时大部分实体DAO的CRUD操作基本一样,采用泛型设计解决这个问题,带来了简洁代码的好处。
- 问题的关键在于我们需要在代码中获取抽象DAO父类(BaseEntityDAOImpl<T>)中的泛型信息。
- 由于Java的泛型是基于泛型擦除实现的,因此无法直接获取如果直接获取,在Java中,如果子类继承一个泛型的父类,会保存父类中泛型的信息,因此可以采用如下方法获取泛型信息。
public abstract class BaseEntityDAOImpl<T> {
protected Class<T> entityClass;
public BaseEntityDAOImpl() {
// 由于Java 方法的动态绑定getClass()调用的是子类方法
// getGenericSuperclass()返回直接父类的Type类型,并保存了泛型参数的实际类型信息。
Type genType = getClass().getGenericSuperclass();
Type[] params = ((ParameterizedType)genType).getActualTypeArguments();
// 获取实际的泛型参数的类型信息。
entityClass = (Class<T>) params[0];
} } - 在获取了泛型参数实际类型之后,以下使用JPA的EntityManager来对通用CRUD操作实现,如下:
public class BaseEntityDAOImpl<T> {
protected Class<T> entityClass;
//@PersistenceContext注解后,entityManager由Spring负责注入
@PersistenceContext
protected EntityManager entityManager;
public BaseEntityDAOImpl() {
Type genType = getClass().getGenericSuperclass();
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
entityClass = (Class<T>) params[0];
} public EntityManager getEntityManager(){
return entityManager;
}
public void setEntityManager(EntityManager entityManager){
this.entityManager=entityManager;
} public void add(T t){
entityManager.persist(t);
}
public void update(T t){
entityManager.merge(t);
}
public T getById(long id){
return entityManager.find(entityClass, id);
}
public void deleteById(long id){
T t=getById(id);
if(t!=null){
entityManager.remove(t);
}
}
public void delete(T t){
entityManager.remove(t);
} public List<T> getListByPage(int offset,int maxResult){ return (List<T>)getEntityManager().createQuery("from "+entityClass.getSimpleName()).setFirstResult(offset).setMaxResults(maxResult).getResultList();
} public List<T> getAll(){
return (List<T>)getEntityManager().createQuery("from "+entityClass.getSimpleName()).getResultList();
} }
- 使用客户Customer和订单Order两个实体的作为例子,我们可以通过继承泛型的DAO抽象父类来实现实体DAO接口的CRUD,而DAOImpl中没有相关的代码,类图如下:
- Spring 和JPA集成如下,事务的配置使用注解实现:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="cn.cjtblog.jpatest"/>
<context:property-placeholder location="classpath:jdbc.properties" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url"
value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- 对注解Jpa EntityManager的@PersistenceContext,进行注入 -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="cn.cjtblog.jpatest" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaDialect" ref="jpaDialect" />
<property name="persistenceProvider" ref="persistenceProvider" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property> </bean>
<bean id="persistenceProvider" class="org.hibernate.jpa.HibernatePersistenceProvider" />
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL" />
<property name="showSql" value="true" />
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" /> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
</beans>
- 结论 对于使用Hibernate和JPA这样的ORM框架来说,通用的CRUD操作,应该都有这么一个泛型的DAO抽象父类。这样可以省去很多相同功能的代码。
- Maven测试项目的地址如下:https://github.com/jintaocai/testcode/tree/master/jpatest
最新文章
- MySQL中优化sql语句查询常用的30种方法
- Android反编译(二)之反编译XML资源文件
- bzoj1102: [POI2007]山峰和山谷Grz
- How to display SSRS report based on customer/Vendor specific language [AX2012]
- Machine Learning for hackers读书笔记(七)优化:密码破译
- 一步步实现Promise
- JS each 跳出
- Redis和Memcache的区别分析 [转]
- linux中grep使用方法具体解释
- Visual studio 2013 bug:visual studio no editoroptiondefinition export found for the given option nam
- UOJ #278. 【UTR #2】题目排列顺序(排序水题)
- 【javascript】您好, 您要的ECMAScript6速记套餐到了
- 经典面试题目——250M内存处理10G大小的log文件
- word20161229
- 简单了解uuid
- remote connect to ubuntu unity
- Cocos2dx Android环境编译出错:jni/Android.mk: Cannot find module with tag &#39;scripting/lua-bindings&#39; in import path
- myEclipse和eclipse从debug视图自动跳回default视图。
- select()函数 的学习
- 阿里云栖大会 所有ppt
热门文章
- 潜语义分析(Latent Semantic Analysis)
- [二]java运行原理
- 让BOOTSTRAP默认SLIDER支持触屏设备
- 知道Form.Show()和Form.ShowDialog()的区别吗
- NAS、DAS和SAN三种存储究竟是什么?
- jQuery EasyUI, datagrid, treegrid formatter 参数比较 row index
- 理解 MEF
- ThinkPHP3.1新特性: 多层MVC支持
- @RenderBody()和@RenderSection()
- BZOJ 2049: [Sdoi2008]Cave 洞穴勘測 LCT