知识大全 在WEB容器中获取持久化上下文

Posted

篇首语:最好的治疗是在温暖、干净、干燥的环境下养猪。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 在WEB容器中获取持久化上下文相关的知识,希望对你有一定的参考价值。

在WEB容器中获取持久化上下文  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  想写这篇文章 是因为看了网上相关的几篇文章 没有一篇能真正说清楚如何正确地在WEB容器中获取持久化上下文 要么根本就不知道如何获取 要么存在极度大的性能问题 要么存在线程安全性的隐患

  在EJB容器 如果你愿意 由容器注入一个EntityManager后 你可以把一切交给容器管理 如果你愿意使用可扩展事务 当然你已经了解如何管理EntityManager 规范在那儿定着 没有什么可多说的 在Java SE环境下 没有容器能帮助你做任何事 一切都要由你纯手工创建 当然一切也由你负责管理 关闭 销毁 都是你的事 所以反而变得简单(是说获取持久化手段简单了 不是操作单了)

  一 容器管理持久化上下文

  而在WEB容器中 一方面容器管理的持久化事务不能象EJB容器那样可以使用扩展性事务 要想让容器管理 那么只能是 JTA事务 而且数据源也一定是JTA DATA SOURCE 常有人在网上找到一些persistence xml 要么使用了本地事务 要么是非JTA的数据源 问我为什么在WEB容器中不能成功注EntityManager

  要在WEB容器中让容器管理持久化事务 可以通过两种方式 一是容器注入 一是JNDI查找 这两种方式并不是每个人都理解的 我看到一本叫<<EJB JPA数据库持久化编程详解>>的书 在网上受到太多的人的追捧(越是这样的书受害者就越多!) 作者明确说 容器托管的EntityManager只能运行在EJB容器中 也就是说只有在EJB JAR包中 才可以获得容器托管的 EntityManager对象 否则只能获得应用托管的EntityManager对象

  事实上确实一些WEB容器不能注入EntityManager 也不能通过JNDI查找到 但是容器不支持并不是规范不支持 如果你使用glassfish 或者用resin 以上(目前已经 )你就可以方便地获得容器管理的EntityManager     <?xml version= encoding= UTF ?>

  <persistence xmlns=

  xmlns:xsi= instance

  xsi:schemaLocation= persistence_ _ xsd

  version= >

  <persistence unit name= jpaUnit transaction type= JTA >

  <jta data source>jdbc/__axman</jta data source>

  <class> axman CustomerEO</class>

  </persistence unit>

  </persistence>

  <?xml version= encoding= UTF ?>

  <persistence xmlns=

  xmlns:xsi= instance

  xsi:schemaLocation= persistence_ _ xsd

  version= >

  <persistence unit name= jpaUnit transaction type= JTA >

  <jta data source>jdbc/__axman</jta data source>

  <class> axman CustomerEO</class>

  </persistence unit>

  </persistence>只要这个persistence xml文件在类路径中 就可以正确地注入EntityManager:

  //为了阅读方便删除了无关内容和注释

  <PRE class=java name= code >public class TestAxman extends HttpServlet

  @PersistenceContext(name= jpaUnit )

  private EntityManager em;

  @Resource

  private UserTransaction utx;

  protected void service(HttpServletRequest request HttpServletResponse response)

  throws ServletException IOException

  PrintWriter out = response getWriter();

  CustomerEO ce = new CustomerEO();

  ce setName( p );

  ce setEmail( );

  ce setAsset( d);

  ce setCreateDate(new java sql Date(new java util Date() getTime()));

  utx begin();

  em persist(ce);

  mit();

  //容器管理事务不需要自己手工回滚 只要告诉容器事务起止边界

  

  

  </PRE>

  public class TestAxman extends HttpServlet                   @PersistenceContext(name= jpaUnit )         private EntityManager em;         @Resource          private UserTransaction utx;              protected void service(HttpServletRequest request HttpServletResponse response)              throws ServletException IOException              PrintWriter out = response getWriter();             CustomerEO ce = new CustomerEO();             ce setName( p );             ce setEmail( );             ce setAsset( d);             ce setCreateDate(new java sql Date(new java util Date() getTime()));             utx begin();             em persist(ce);             mit();             //容器管理事务不需要自己手工回滚 只要告诉容器事务起止边界                    public class TestAxman extends HttpServlet

  @PersistenceContext(name= jpaUnit )

  private EntityManager em;

  @Resource

  private UserTransaction utx;

  protected void service(HttpServletRequest request HttpServletResponse response)

  throws ServletException IOException

  PrintWriter out = response getWriter();

  CustomerEO ce = new CustomerEO();

  ce setName( p );

  ce setEmail( );

  ce setAsset( d);

  ce setCreateDate(new java sql Date(new java util Date() getTime()));

  utx begin();

  em persist(ce);

  mit();

  //容器管理事务不需要自己手工回滚 只要告诉容器事务起止边界

  

  

  这样注入进来的EntityManager完全由容器管理 不要做任何EntityManager相关的工作 但是一切就这样完美了吗? 当然不是 和EJB容器不同的是 相当于有状态会话BEAN的Servlet是多线程服务的 一个实例变量的EntityManager 完全可能会被多个线程同时访问而出现极大的安全性隐患 那么这样的注入是否有意义呢?  当然有意义 一种情况是你可以在ServletContextListener这样的线程安全模块中注入 另一种情况只要你能控制不让多个线程同时访问一个实例变量的EntityManager 那么你就可以享受容器管理带来的方便性

  但是任何事物都有两面性 如果你要获取方便 就要牺牲应用范围的控制和性能 要让多个线程不同时访问一个实例变量EntityManager 最终还是要进行同步或互斥 即一个线程使用变量EntityManager时其它线程都要等待 如果能在线程的local方法中(doXXX或父类的service方法中)获取由容器管理的EntityManager 那将会大大提高程序的性能   容器管理 的意思 其实就是容器产生了一些对象 你只需要拿来使用 不需要负责它的产生和销毁 关键是容器产生了这样的对象后你如何 拿到 通过注入只能注入成实例字段 那么在线程方法中 可能通过JNDI 来即时获取 容器中的EntityManager (实事上 只要改一下容器实现的源码 还可以通过在service方法中获取ServletContext对象来动态即时注入 但这对于普通程序员是做不到的)

  通过JNDI查找的jndi ref也可以通过注释或通过web xml配置 两种方法都可以: 注入jndi ref:

  @PersistenceContext(name= persistence/jpaUnit unitName= jpaUnit )

  public class TestAxman extends HttpServlet

  protected void service(HttpServletRequest request HttpServletResponse response)

  throws ServletException IOException

  Context env =(Context)newInitialContext() lookup( java:p/env );

  EntityManager em = (EntityManager)env lookup( persistence/jpaUnit );

  Query query = em createQuery( SELECT c from CustomerEO c );

  List <CustomerEO> ls = query getResultList();

  

  

  @PersistenceContext(name= persistence/jpaUnit unitName= jpaUnit )

  public class TestAxman extends HttpServlet

  protected void service(HttpServletRequest request HttpServletResponse response)

  throws ServletException IOException

  Context env =(Context)newInitialContext() lookup( java:p/env );

  EntityManager em = (EntityManager)env lookup( persistence/jpaUnit );

  Query query = em createQuery( SELECT c from CustomerEO c );

  List <CustomerEO> ls = query getResultList();

  

  如果你不想用注释可以在web xml中配置:

  <persistence context ref>

  <persistence context ref name>persistence/jpaUnit</persistence context ref name>

  <persistence unit name>jpaUnit</persistence unit name>

  </persistence context ref>

  <persistence context ref>

  <persistence context ref name>persistence/jpaUnit</persistence context ref name>

  <persistence unit name>jpaUnit</persistence unit name>

  </persistence context ref>然后可以同样通过

  Context env =(Context)new InitialContext() lookup( java:p/env );

  EntityManager em = (EntityManager)env lookup( persistence/jpaUnit ); 查找到EntityManager

  需要说明的是 JNDI查看本身是耗时的 特别是new InitialContext() 所以应该在一个全局的位置创建一个env (相当于工场) 然后在service方法中通过这个env来查找EntityManager就可以大量地提升性能 比如:

  public class TestAxman extends HttpServlet

  Context env = null;

  protected void init(ServletConfig config) throws ServletException

  env = (Context)newInitialContext() lookup( java:p/env );

  

  protected void service(HttpServletRequest request HttpServletResponse response)

  throws ServletException IOException

  EntityManager em = (EntityManager)env lookup( persistence/jpaUnit );

  Query query = em createQuery( SELECT c from CustomerEO c );

  List <CustomerEO> ls = query getResultList();

  

  

  public class TestAxman extends HttpServlet

  Context env = null;

  protected void init(ServletConfig config) throws ServletException

  env = (Context)newInitialContext() lookup( java:p/env );

  

  protected void service(HttpServletRequest request HttpServletResponse response)

  throws ServletException IOException

  EntityManager em = (EntityManager)env lookup( persistence/jpaUnit );

  Query query = em createQuery( SELECT c from CustomerEO c );

  List <CustomerEO> ls = query getResultList();

  

  

  <PRE class=java name= code >如果你需要容器管理持久化 这种方案是最合适的方式 虽然EntityManager 每次要在service中lookup出来 但它是</PRE>    <PRE class=java name= code >方法内的local变量 不象注入成实例变量那样存在多线程安全隐患 </PRE>

  如果你需要容器管理持久化 这种方案是最合适的方式 虽然EntityManager 每次要在service中lookup出来 但它是  如果你需要容器管理持久化 这种方案是最合适的方式 虽然EntityManager 每次要在service中lookup出来 但它是    方法内的local变量 不象注入成实例变量那样存在多线程安全隐患   方法内的local变量 不象注入成实例变量那样存在多线程安全隐患     二 应用管理持久化上下文:

  应用管理持久化上下文 事实上就是EntityManager对象不是由容器负责产生和销毁 而是由应用程序来创建 当然是   由应用程序来销毁 要由应用程序来创建持久化上下文 就是要由EntityManagerFactory来进行createEntityManager    本着谁生产谁负责的原则 当然要程序来负责销毁 所以应用管理的EntityManager一定要在finally语句中调用close()   方法 这样多少给我们使用它带来不便 但它也因为是应用程序创建 所以有着广泛的应用范围 无论是EJB容器 还是WEB   容器 或者是纯Java SE环境 都可以使用JPA功能

  要在WEB容器获取EntityManagerFactory 同样可以通过注入和手工创建 明白 容器管理 的意义应该知道 注入  是容器已经产生了的对象 所以EntityManagerFactory如果是容器注入的 同样不需要你手工销毁 而如果是手工  创建的 则需要手工销毁 简单说EntityManagerFactory对象本身也可以容器管理的:    public class TestServlet extends HttpServlet

  @PersistenceUnit(unitName = jpaUnit )

  private EntityManagerFactory emf;

  public void service(……) throws xxxExceotion

  EntityManager em = emf createEntityManager();

  try

  //invoke em;

  

  finally em close(); // EntityManager本身是应用程序创建的

  //所以必须手工关闭 如果这里是写入操作 事务还必须在cacth块中手工回滚       

  

  public class TestServlet extends HttpServlet

  @PersistenceUnit(unitName = jpaUnit )

  private EntityManagerFactory emf;

  public void service(……) throws xxxExceotion

  EntityManager em = emf createEntityManager();

  try

  //invoke em;

  

  finally em close(); // EntityManager本身是应用程序创建的

  //所以必须手工关闭 如果这里是写入操作 事务还必须在cacth块中手工回滚     

  如果你不想通过容器注入EntityManagerFactory 只要调用

  EntityManagerFactory emf = Persistence createEntityManagerFactory( jpaUnit );

  就可以获取一个手工创建的EntityManagerFactory 但是要记得在创建它的对应位置手要销毁它 如:

  public class TestServlet extends HttpServlet

  private EntityManagerFactory emf;

  void init( )

  emf = Persistence createEntityManagerFactory( jpaUnit );

  

  void destory( )

  if(emf != null) emf close();

  

  public void service( ) throws xxxExceotion

  EntityManager em = emf createEntityManager();

  try

  //invoke em;

  

  finally em close(); // EntityManager本身是应用程序创建的

  //所以必须手工关闭

  

  

  public class TestServlet extends HttpServlet

  private EntityManagerFactory emf;

  void init( )

  emf = Persistence createEntityManagerFactory( jpaUnit );

  

  void destory( )

  if(emf != null) emf close();

  

  public void service( ) throws xxxExceotion

  EntityManager em = emf createEntityManager();

  try

  //invoke em;

  

  finally em close(); // EntityManager本身是应用程序创建的

  //所以必须手工关闭

  

  因为EntityManagerFactory是工场对象 所以上面的例子并不好 最好的位置是在SerlvetContextListener中注入然后放在 ServletContext中 或在ContextListener的contextInitialized中手工生成 在contextDestroyed中销毁 生成后放入 ServletContext中供全局访问 即一个应用只有一个工场 而EntityManager是在service方法中通过EntityManagerFactory 即时生成的 这样既可以提高性能 又保证了线程安全性 可以说是一个非常正确的方案

cha138/Article/program/Java/hx/201311/26497

相关参考

知识大全 使用SpringtUtil获取Spring IoC容器中的Bean

使用SpringtUtil获取SpringIoC容器中的Bean  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起

知识大全 解析web.xml中在Servlet中获取context-param和init-param内的参数

解析web.xml中在Servlet中获取context-param和init-param内的参数  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜

知识大全 使用XML文件作为Web持久层的OO分析过程

使用XML文件作为Web持久层的OO分析过程  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  在一

知识大全 深入理解Java Servlet与Web容器之间的关系

深入理解JavaServlet与Web容器之间的关系  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

知识大全 asp中获取内容中所有图片与获取内容中第一个图片的代码

  复制代码代码如下:cha138/Article/program/Web/201405/30991

知识大全 高效获取jpeg图片的尺寸

  获取图片的尺寸有三种方法  将整个图片文件加载成BufferedImage后获取其尺寸  用ImageReader快捷获取  即下文所陈述的方式  做过简陋的测试效率自至逐步递增  ImageIn

知识大全 web上存漏洞及原理分析、防范方法(文件名检测漏洞)

  我们通过前篇<web上存漏洞及原理分析防范方法(安全文件上存方法)>已经知道后端获取服务器变量很多来自客户端传入的跟普通的getpost没有什么不同下面我们看看常见出现漏洞代码检测文件

耦合电容器正常巡视要注意什么?

  耦合电容器正常巡视应注意:  (1)电容器瓷质部分有无破损或放电痕迹。  (2)上下引线是否牢固,接地线是否良好,接地开关是否位置正确。  (3)引线及各部有无放电响声。  (4)有无漏、渗油现象

耦合电容器正常巡视应注意什么?

  耦合电容器正常巡视应注意:  (1)电容器瓷质部分有无破损或放电痕迹。  (2)上下引线是否牢固,接地线是否良好,接地开关是否位置正确。  (3)引线及各部有无放电响声。  (4)有无漏、渗油现象

耦合电容器正常巡视要注意什么?

  耦合电容器正常巡视应注意:  (1)电容器瓷质部分有无破损或放电痕迹。  (2)上下引线是否牢固,接地线是否良好,接地开关是否位置正确。  (3)引线及各部有无放电响声。  (4)有无漏、渗油现象