【JavaEE】经典JAVA EE企业应用实战-读书笔记14
来源:互联网 发布:国泰安金融数据库 编辑:程序博客网 时间:2024/06/07 15:41
JPA的核心API就是EntityManager,负责管理JPA持久化上下文中的所有实体,负责跟踪所有实体的保存、更新和修改情况,并根据指定的flush模式将这些修改保存到数据库中。
在应用程序中使用EntityManager,大致分为3种情况
1)在EJB中使用EntityManager:直接使用依赖注入来管理EntityManager。
2)在Servle、JSF的托管Bean中使用EntityManager:不能直接使用依赖注入。因为多请求线程可能共享同一个Servlet或JSF的托管Bean,而EntityManager并没有被设计成线程安全的。两种解决方法,一是使用JNDI查找来获得EntityManager对象。二是使用依赖注入管理EntityManagerFactory对象(他是线程安全的),在通过EntityManagerFactory来获取EntityManager对象。
3)在JavaSE应用中使用EntityManager:需要通过应用程序显式地创建EntityManager。
现在介绍第三种的使用步骤
1)通过javax.persistence.Persistence工厂提供的createEntityManagerFactory()静态方法创建EntityManagerFactory对象。调用该方法时需要传入persistence.xml文件中持久化单元的名称。
2)调用EntityManagerFactory的createEntityManager()或createEntityManager(Map map)方法来创建EntityManager对象。第二个createEntityManager方法可以传入一个Map参数,这个Map参数传入的属性会补充或覆盖persistence.xml文件中配置的属性
Hibernate
JPA
数据库、连接池配置信息
hibernate.cfg.xml
persistence.xml
持久化组件
持久化对象(Persistence Object)
实体(Entity)
持久化管理组件
Session(线程不安全)
EntityManager(线程不安全)
工厂类
SessionFactory(线程安全)
EntityManagerFactory(线程安全)
public class JpaQs {private static final EntityManagerFactory emf =Persistence.createEntityManagerFactory("qs");public static void main(String[] args) {final EntityManager em = emf.createEntityManager();News news = new News();news.setTitle("this is a title");news.setContent("this is a content");try {em.getTransaction().begin();em.persist(news);em.getTransaction().commit();} finally {em.close();}}}
EntityManager中常用方法如下:
方法
简介
void persistent(Object entity)
将指定实体保存到数据库中,转换为持久化状态
T merge(T entity)
将指定合并到底层数据库
void remove(Object entity)
删除指定实体,转换为瞬态
T find(Class<T> entityClass,Object pk)
根据实体的主键加载实体
void setFlushMode(FlushModeType flushMode)
设置持久化上下文的flush模式,可以是AUTO(默认值,即EntityManager自动管理实体和数据库同步)或COMMIT
void flush()
将持久化上下文中的实体状态同步到底层数据库
void refresh(Object entity)
刷新指定实体状态
Query createQuery(String jpql)
根据指定JPQL语句创建查询
Query createNamedQuery(String name)
根据配置中的查询名创建命名查询
Query createNativeQuery(String sqlString)
根据指定SQL语句创建原生SQL查询
void close()
关闭EntityManager
boolean isOpen()
判断EntityManager是否打开
JPA除了使用注解之外还可使用orm.xml文件来管理实体和数据表之间的映射关系,类似于*.hbm.xml文件。
News.orm.xml文件例子如下:
<entity-mappings><persistence-unit-metadata><access>PROPERTY</access></persistence-unit-metadata><!-- 指定实体默认所在的包 --><package>com.kingdz.model</package><entity class="News"><!-- 指定将实体类映射到表 --><table name="news_table"/><attributes><!-- 配置主键映射 --><id name="id"><!-- 指定主键生成策略 --><generated-value strategy="IDENTITY"/></id><basic name="title"><column name="news_title" length="50"/></basic><basic name="content"/></attributes></entity></entity-mappings>
这样在persistence.xml文件中需要增加对文件的引用,使用<mapping-file>来指定,片段如下
<persistence-unit>
<mapping-file>com/kingdz/model/News.orm.xml</mapping-file>
</persistence-unit>
JPA的主要思想就是让实体来映射底层数据表。
在JPA规范中涉及两个常用的概念:持久化上下文(persistence context)和持久化单元(persistence unit)。
EntityManager负责跟踪持久化上下文中所有实体的状态,当应用程序改变了持久化上下文中的实体状态后,EntityManager将会根据指定的flush模式将实体的状态写入底层数据库。如果持久化上下文关闭,该上下文中所有实体都将会脱离EntityManager的管理,进入脱管状态,此时对实体所做的修改将不会自动同步到底层数据库。
持久化单元由persistence.xml文件定义,该文件必须位于META-INF路径下,关于该文件的存放位置说明如下:
1)对于一个JavaSE应用,如果程序没有将persistence.xml文件打包成JAR,则应该将该文件放在应用类加载路径的META-INF路径下
2)如果将persistence.xml文件打包到EJB JAR包中,则应该将该文件放在该JAR包的META-INF路径下
3)如果将persistence.xml文件打包到某个web应该的WAR包中,则应该将该文件放在该WAR的WEB-INF/classes/META-INF路径下。即使对于不打包成WAR包的web应用,该文件也应该放在web应用的WEB-INF/classes/META-INF路径下。
JPA对实体类没有太多的要求,但是我们还是应该遵守几个基本原则
1)提供一个无参数的构造器,该构造器的访问控制符至少是包可见的,即大于或等于默认的访问控制符。
2)提供一个标识属性,通常映射数据库表的主键字段。如果使用联合主键,甚至可以用一个用户自定义的类,通常不推荐这么做。
注意:虽然JPA可以允许实体类没有标识属性,但这样做将导致JPA的许多功能无法使用。而且JPA建议使用允许接受null值的类型来作为标识属性的类型,因此应该尽量避免使用基本数据类型,可以考虑使用包装类。
3)为实体类的每个属性提供set和get方法。JPA持久化JavaBean风格的属性,认可如下方法名getFoo、isFoo和setFoo。如果需要也可以切换属性的访问策略。
4)使用非final类:许多JPA实现都需要在运行时生成动态代理。如果实体没有实现任何接口,那么JPA就需要为他动态地生成CGLIB代理类,该代理对象是实体类的子类的实例。
5)重写equals和hashCode方法:如果需要把实体类放入set中,则应该重写这两个方法。
JPA的实体状态演化图
持久化实体可以也可以使用EntityManager提供的persist(Object obj)方法。
与find方法查询相似的还有getReference方法,也可以根据实体主键类加载实体。区别是当调用find方法获取实体时如果不存在会返回null;getReference方法使用了代理模式,JPA会延迟加载该实体的状态,会抛出EntityNotFoundException。
当程序修改托管实体的属性后,程序应该使用新的EntityManager来保存这些修改。EntityManager提供了merge方法来保存这些修改。典型的应用场景就是:服务器端程序使用EntityManager从底层数据库加载指定实体,然后将该实体送到远程客户端,客户端对该实体进行修改,修改完后在送给服务器端,服务器端就需要将该实体的状态合并到底层数据库。
News n=firstEm.load(News.class,1);
//第一个EntityManager已经关闭了
firstEm.close();
//修改脱管状态下的实体
n.setTitle(“新标题”);
//打开第二个EntityManager
EntityManager secondEm=...
//保存脱管对象所做的修改
n=secondEm.merge(n);
//接下来实体n将处于托管状态
对于不同状态的实体,merge方法行为如下
1)如果实体处于新建状态,merge方法将会把该实体状态保存到底层数据库。并创建该实体的副本,将该副本纳入EntityManager管理之下,并返回该副本
2)如果实体处于托管状态,该操作会忽略
3)如果实体处于被删除状态(或不是一个实体),将导致IllegalArgumentException异常
4)如果该实体处于脱管状态,merge方法将会把该实体状态合并到底层数据库。并且创建改实体的副本,将该副本纳入EntityManager管理之下,并返回该副本。
删除实体使用remove方法
底层使用delete from table where id=?的语句处理
对于不同状态的实体,remove方法行为如下
1)如果实体处于新建状态。remove方法将被忽略
2)如果实体处于托管状态,remove方法将会把实体转换到被删除状态。
3)如果实体处于脱管状态(或不是一个实体),将导致IllegalArgumentException异常
4)如果实体处于被删除状态,remove方法将被忽略
如果怀疑当前实体的状态与底层数据库对应的记录不一致,可以调用EntityManager的refresh方法来刷新实体。
对于不同状态的实体,refresh方法行为如下
1)如果实体处于新建状态(或不是一个实体),将导致IllegalArgumentException异常
2)如果实体处于托管状态,refresh方法将会刷新该实体
3)如果实体处于脱管状态(或不是一个实体),将导致IllegalArgumentException异常
4)如果实体处于被删除状态,将导致IllegalArgumentException异常
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记14
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记1
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记2
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记3
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记4
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记5
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记6
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记7
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记8
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记9
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记10
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记11
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记12
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记13
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记15
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记16
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记18
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记19
- linux学习笔记
- oracle没有sum if函数,但是有替代的decode函数
- 【PythonWEB】LAMP微信公众平台开发准备流程
- java基础学习IO流之字节流 十一 -4
- Cordova 原生插件编写总结
- 【JavaEE】经典JAVA EE企业应用实战-读书笔记14
- 日期计算
- Android之ButterKnife在AndroidStudio中的使用步骤
- poj 1273 网络流板子题
- Freemarker实例教程
- 分布式一致性算法--Paxos
- 递归的基本原理
- Mac下让terminal复用上次会话
- RegExp 用一点心学,就不会觉得复杂