引言
JPA(Java Persistence API),即 Java 持久层 API,它是 Java 平台上用于实现对象关系映射 (Object-Relational Mapping,简称ORM) 的规范。它定义了 Java 对象如何映射到关系型数据库中的表,并提供了一套标准的 API 来管理这些映射关系以及数据库中的持久化对象。
为了方便开发人员后续快速接入 和 使用 JPA 操作数据库,本篇 Huazie 将向大家介绍笔者 Flea 框架下的 flea-db 模块封装JPA操作数据库的内容。
1. 参考
2. 依赖
MySQL 的 JDBC 驱动 mysql-connector-java-5.1.25.jar
1 | <dependency> |
JPA 实现 EclipseLink eclipselink-2.5.0.jar
1 | <dependency> |
3. 内容讲解
目前示例用的是 JPA + MySQL 模式,需要各位本地自行装下 MySQL 数据库。
3.1 Flea JPA查询对象
FleaJPAQuery 用于实现 JPA 标准化方式的数据库查询操作,可以自行组装查询条件。下面对一些关键点进行讲解,且听我细细道来 (这一版并发环境下 可能存在问题,后面我会专门写一篇博文讲解 Flea JPA查询对象的问题,其中引入了对象池的概念 )。
获取FleaJPAQuery实例,并初始化内部成员变量
EntityManager entityManager
:JPA 中用于增删改查的持久化接口Class sourceClazz
: 实体类类对象Class resultClazz
: 操作结果类类对象Root root
: 根SQL表达式对象CriteriaBuilder criteriaBuilder
: 标准化生成器CriteriaQuery criteriaQuery
: 标准化查询对象List<Predicate> predicates
: Where条件集合List<Order> orders
: 排序集合List<Expression> groups
: 分组集合getQuery()
: 获取Flea JPA查询对象。新版本已废弃(单例模式,本身没有问题,但是由于获取之后 Flea JPA 查询对象还要使用,这在有点并发的环境下就存在问题了;后面我会单独写一篇博文讲解基于对象池的多例模式,既保证并发下各个线程获取的 Flea JPA 查询对象之间互不影响,同时也能保证尽可能少的新建 Flea JPA 查询对象)init(EntityManager entityManager, Class sourceClazz, Class resultClazz)
:获取FleaJPAQuery
实例之后,一定要调用该方法进行初始化initQueryEntity(Object entity)
:初始化查询实体,主要用来构建查询条件值,以及分库分表
拼接查询条件,添加排序和分组
equal(String attrName, Object value)
: 等于条件 (单个属性列)equal(Map<String, Object> paramMap)
: 等于条件 (多个属性列)notEqual(String attrName, Object value)
: 不等于条件 (单个属性列)notEqual(Map<String, Object> paramMap)
: 不等于条件 (多个属性列)isNull(String attrName)
:is null
条件,某属性值为空isNotNull(String attrName)
:is not null
条件,某属性值为非空in(String attrName, Collection value)
:in
条件,attrName
属性的值在value
集合中notIn(String attrName, Collection value)
:not in
条件,attrName
属性的值不在value
集合中like(String attrName, String value)
:like
条件, 模糊匹配le(String attrName, Number value)
: 小于等于条件lt(String attrName, Number value)
: 小于条件ge(String attrName, Number value)
: 大于等于条件gt(String attrName, Number value)
: 大于条件between(String attrName, Date startTime, Date endTime)
:between and
条件, 时间区间查询greaterThan(String attrName, Date value)
: 大于某个日期值条件greaterThanOrEqualTo(String attrName, Date value)
: 大于等于某个日期值条件lessThan(String attrName, Date value)
: 小于某个日期值条件lessThanOrEqualTo(String attrName, Date value)
: 小于等于某个日期值条件count()
: 统计数目,在getSingleResult
调用之前使用countDistinct()
: 统计数目(带distinct
参数),在getSingleResult
调用之前使用max(String attrName)
: 设置查询某属性的最大值,在getSingleResult
调用之前使用min(String attrName)
: 设置查询某属性的最小值,在getSingleResult
调用之前使用avg(String attrName)
: 设置查询某属性的平均值,在getSingleResult
调用之前使用sum(String attrName)
: 设置查询某属性的值的总和,在getSingleResult
调用之前使用sumAsLong(String attrName)
: 设置查询某属性的值的总和(Long),在getSingleResult
调用之前使用sumAsDouble(String attrName)
: 设置查询某属性的值的总和(Double),在getSingleResult
调用之前使用distinct(String attrName)
: 去重某一列addOrderby(String attrName, String orderBy)
: 添加order by
子句addGroupBy(String attrName)
: 添加group by
子句
获取查询结果(记录行 或 单个结果)
getResultList()
: 获取查询的记录行结果集合getResultList(int start, int max)
: 获取查询的记录行结果集合(设置查询范围)getSingleResultList()
: 获取查询的单个属性列结果集合。需要先调用distinct
,否则默认返回行记录结果集合getSingleResultList(int start, int max)
: 获取查询的单个属性列结果集合(设置查询范围,可用于分页)。需要先调用distinct
,否则默认返回行记录结果集合。getSingleResult()
: 获取查询的单个结果。需要提前调用 (count, countDistinct, max, min, avg, sum, sumAsLong, sumAsDouble
)
3.2 数据处理的基本接口
IFleaJPABaseDataHandler 为基本的数据操作接口,其中包含了查询,(批量)添加,(批量)更新,删除等操作。
3.3 抽象Flea JPA DAO层接口
IAbstractFleaJPADAO 实现了基本的查询、(批量)添加、(批量)更新、删除接口
1 | public interface IAbstractFleaJPADAO<T> extends IFleaJPABaseDataHandler<T> { |
3.4 抽象Flea JPA DAO层实现
AbstractFleaJPADAOImpl 中实现上述3中查询、(批量)添加、(批量)更新、删除的接口的具体逻辑。
该类实现上述抽象 Flea JPA DAO 层接口,同样有类型T,由子类指定其操作的实体类。
1
public abstract class AbstractFleaJPADAOImpl<T> implements IAbstractFleaJPADAO<T>
无参构造方法,用于获取子类指定的实体类类对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19/**
* <p> 获取T类型的Class对象 </p>
*
* @since 1.0.0
*/
public AbstractFleaJPADAOImpl() {
// 获取泛型类的子类对象的Class对象
Class<?> clz = getClass();
// 获取子类对象的泛型父类类型(也就是AbstractDaoImpl<T>)
ParameterizedType type = (ParameterizedType) clz.getGenericSuperclass();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Type={}", type);
}
Type[] types = type.getActualTypeArguments();
clazz = (Class<T>) types[0];
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("ClassName={}", clazz.getName());
}
}实现接口方法,可参见上述类源码
持久化接口获取,由子类实现(可参考下面的持久化单元 DAO 层实现)
getEntityManager()
:获取实体管理器getEntityManager(T entity)
:获取实体管理器【entity
实体类对象实例】getEntityManager(T entity, boolean flag)
:获取实体管理器【entity
实体类对象实例,flag 获取实体管理器标识【true
:getFleaNextValue
获取实体管理器,false
: 其他场景获取实体管理器】】1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16protected abstract EntityManager getEntityManager();
public EntityManager getEntityManager(T entity) throws CommonException {
return getEntityManager(entity, false);
}
private EntityManager getEntityManager(T entity, boolean flag) throws CommonException {
EntityManager entityManager = getEntityManager();
// 实体类设置默认库名
setDefaultLibName(entity);
// 处理并添加分表信息,如果不存在分表则不处理
entityManager = LibTableSplitHelper.findTableSplitHandle().handle(entityManager, entity, flag);
return entityManager;
}
Flea JPA 查询对象获取【这里已经是使用 Flea JPA 查询对象池来获取
FleaJPAQuery
】1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27protected FleaJPAQuery getQuery(Class result) {
// 获取当前的持久化单元名
String unitName = FleaEntityManager.getPersistenceUnitName(this.getClass().getSuperclass());
FleaJPAQueryPool pool;
if (StringUtils.isBlank(unitName)) {
// 获取Flea JPA查询对象池 (使用默认对象池名"default"即可)
pool = FleaObjectPoolFactory.getFleaObjectPool(FleaJPAQuery.class, FleaJPAQueryPool.class);
} else {
// 获取Flea JPA查询对象池 (使用持久化单元名unitName作为对象池名)
pool = FleaObjectPoolFactory.getFleaObjectPool(unitName, FleaJPAQuery.class, FleaJPAQueryPool.class);
}
if (ObjectUtils.isEmpty(pool)) {
throw new RuntimeException("Can not get a object pool instance");
}
// 获取Flea JPA查询对象实例
FleaJPAQuery query = pool.getFleaObject();
if (LOGGER.isDebugEnabled()) {
Object obj = new Object() {};
LOGGER.debug1(obj, "FleaJPAQueryPool = {}", pool);
LOGGER.debug1(obj, "FleaJPAQuery = {}", query);
}
// 获取实例后必须调用该方法,对Flea JPA查询对象进行初始化
query.init(getEntityManager(), entityClass, result);
return query;
}
3.5 定义抽象Flea JPA SV层接口
IAbstractFleaJPASV 抽象 Flea JPA SV 层接口,继承 IFleaJPABaseDataHandler
接口,包含了通用的增删改查接口。
1 | public interface IAbstractFleaJPASV<T> extends IFleaJPABaseDataHandler<T> { |
3.6 抽象Flea JPA SV层实现
AbstractFleaJPASVImpl 实现上述抽象 Flea JPA SV 层接口,相关代码也比较简单,具体接口实现内部调用抽象 Flea JPA DAO 层实现。
1 |
|
3.7 持久化单元DAO层实现
FleaAuthDAOImpl 与持久化单元一一对应,如果新增一个持久化配置,即需要新增一个持久化单元 DAO 层实现,同时 Spring 配置中,需要加入对应的持久化单元事务管理者配置。
- 持久化单元名 —–
fleaauth
- 持久化事务管理者 —–
fleaauthTransactionManager
- 持久化接口对象 —–
entityManager
(该类由注解定义,由 Spring 配置中的 持久化接口工厂fleaAuthEntityManagerFactory
初始化,详细可见下面持久化单元相关配置)
FleaAuth数据源DAO层父类
1 | public class FleaAuthDAOImpl<T> extends AbstractFleaJPADAOImpl<T> { |
3.8 配置介绍
3.8.1 持久化单元配置
fleaauth-persistence.xml
1 |
|
3.8.2 Spring配置
defaultPersistenceManager
:持久化单元管理器defaultPersistenceProvider
:持久化提供者defaultLoadTimeWeaver
:加载时织入器defaultVendorAdapter
:JPA 厂商适配器,对外公开 EclipseLink 的持久性提供程序和EntityManager扩展接口defaultJpaDialect
:JpaDialect EclipseLink 持久化服务的实现fleaAuthEntityManagerFactory
:JPA 实体管理器工厂类fleaAuthTransactionManager
:JPA 事务管理器
1 | <bean id="defaultPersistenceManager" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager"> |
总结
至此,相关 JPA 使用已封装完毕,欢迎大家评论区讨论。下一篇博文将介绍 《JPA接入》 ,向大家演示使用 JPA 封装代码来操作数据库,敬请期待!!!