EJB学习笔记十一(EntityManager几种管理方式)

1.前言

今天来谈一下,几种管理EntityManger的方式。

 2.从一个Demo说起

最近做了一个Demo,通过JBOSS数据源来管理EntityManager对象,下面为大家展示一下。

用到的工具有JBOSS5.1,mysql3.13

1.配置JBOSS数据源

可以从JBOSS的安装路径\jboss-5.0.1.GA\docs\examples\jca的安装路径中拷贝相关的数据源配置文件,其中在这个路径中有好多数据库的配置,选择Mysql.xml拷贝到\jboss-5.0.1.GA\server\default\deploy下面,具体配置如下

<span style="font-family:SimSun;font-size:18px;"><?xml version="1.0" encoding="UTF-8"?>

<!-- $Id: mysql-ds.xml 41017 2006-02-07 14:26:14Z acoliver $ -->
<!--  Datasource config for MySQL using 3.0.9 available from:
http://www.mysql.com/downloads/api-jdbc-stable.html
-->

<datasources>
  <local-tx-datasource>
  <!-- JNDI名称-->
    <jndi-name>firstds</jndi-name>
	 <!-- 数据库的配置-->
    <connection-url>jdbc:mysql://localhost:3306/test</connection-url>
	 <!-- 驱动配置-->
    <driver-class>com.mysql.jdbc.Driver</driver-class>
	 <!-- 数据库的用户名和密码-->
    <user-name>root</user-name>
    <password></password>
    <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>

    <metadata>
       <type-mapping>mySQL</type-mapping>
    </metadata>
  </local-tx-datasource>
</datasources>
</span>

2.JPA实体编写

<span style="font-family:SimSun;font-size:18px;">package org.crazyit.model;

import javax.persistence.*;
@Entity
@Table(name="news_table")
public class News
{
	//消息类的标识属性
	@Id /* 用于修饰标识属性 */
	/* 指定该主键列的主键生成策略 */
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private int id;
	//消息标题
	/* @Column指定该Field映射的列信息,此处指定了列名、长度 */
	@Column(name="news_title" , length=50)
	private String title;
	//消息内容
	/* @Column指定该Field映射的列信息,此处指定允许为null */
	@Column(nullable=true)
	private String content;
	//构造器
	public News()
	{
	}
	//标识属性的setter和getter方法
	public void setId(int id)
	{
		this.id = id;
	}
	public int getId()
	{
		return (this.id);
	}
	//消息标题的setter方法和getter方法
	public void setTitle(String title)
	{
		this.title = title;
	}
	public String getTitle()
	{
		return (this.title);
	}
	//消息内容的setter方法和getter方法
	public void setContent(String content)
	{
		this.content = content;
	}
	public String getContent()
	{
		return (this.content);
	}
}
</span>

3.测试的Servlet

<span style="font-family:SimSun;font-size:18px;">package lee;

import javax.persistence.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import javax.annotation.*;
import javax.transaction.*;
import javax.naming.*;

import org.crazyit.model.*;

public class AddNewsServlet extends HttpServlet
{
	//通过依赖注入来注入EntityManagerFactory对象
	@PersistenceUnit(unitName="newsUnit")
	private EntityManagerFactory emf;
	//依赖注入容器管理的JTA事务
	@Resource
	private UserTransaction tx;
	public void service(HttpServletRequest request
		, HttpServletResponse response)
		throws IOException , ServletException
	{
		request.setCharacterEncoding("GBK");
		//获取请求参数
		String title = request.getParameter("title");
		String content = request.getParameter("content");
		//创建实体对象
		News news = new News();
		news.setTitle(title);
		news.setContent(content);
		try
		{
			//开始事务
			tx.begin();
			//应用程序通过emf的createEntityManager()方法创建EntityManager
			EntityManager em = emf.createEntityManager();
			//持久化News实体
			em.persist(news);
			tx.commit();
			//应用程序关闭EntityManager对象
			em.close();
			PrintStream out = new PrintStream(response.getOutputStream());
			out.println("<h3>消息添加成功!</h3>");
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
	}
}</span>

注意:大家可以注意到,在上面的代码中通过容器管理的EntityManagerFactory,由容器通过依赖注入将JPA的EntityManagerFactory注入到Servlet。这样就保证在每次的创建过程中,都会创建新的EntityManager,防止了线程的冲突。另外需要注意的是,如果采用JTA全局事务,那么必须保证先执行UserTransaction对象的begn

4.配置Persistence.XML

<span style="font-family:SimSun;font-size:18px;"><?xml version="1.0" encoding="GBK"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
	http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
	<!-- 在应用服务器中使用JTA全局事务 -->
	<persistence-unit name="newsUnit" transaction-type="JTA">
		<!-- 直接使用应用服务器管理的数据源 -->
		<jta-data-source>java:/firstds</jta-data-source>
		<!-- 列出该应用所需要的所有Entity类 -->
		<class>org.crazyit.model.News</class>
		<!-- properties元素用于为特定JPA实现包配置属性 -->
		<!-- 下面列举的是Hibernate JPA实现中可以配置的部分属性 -->
		<properties>
			<!-- 指定连接数据库的方言 -->
			<property name="hibernate.dialect"
				value="org.hibernate.dialect.MySQLInnoDBDialect"/>
			<property name="hibernate.show_sql" value="true"/>
			<!-- 设置是否格式化SQL语句 -->
			<property name="hibernate.format_sql"
				value="true"/>
			<!-- 设置是否根据要求自动建表 -->
			<property name="hibernate.hbm2ddl.auto"
				value="update"/>
		</properties>
	</persistence-unit>
</persistence></span>

注意:在此需要注意的是<jta-data-source>java:/firstds</jta-data-source>,后面的firstds才是jboss中的jndi的名称,前面必须是java:/

3.依赖注入EntityManager

大致的过程与上述类似,不一样的地方如下

<span style="font-family:SimSun;font-size:18px;">package lee;

import javax.persistence.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import javax.annotation.*;
import javax.transaction.*;
import javax.naming.*;

import org.crazyit.model.*;

//为JPA持久化单元配置一个引用,指定引用名为newsUnit。
@PersistenceContext(name="newsUnit" , unitName="newsUnit")
public class AddNewsServlet extends HttpServlet
{
	//依赖注入容器管理的JTA事务
	@Resource
	private UserTransaction tx;
	public void service(HttpServletRequest request
		, HttpServletResponse response)
		throws IOException , ServletException
	{
		request.setCharacterEncoding("GBK");
		//获取请求参数
		String title = request.getParameter("title");
		String content = request.getParameter("content");
		//创建实体对象
		News news = new News();
		news.setTitle(title);
		news.setContent(content);
		try
		{
			tx.begin();
			//通过JNDI查找获取EntityManager
			Context ctx = new InitialContext();
			EntityManager em = (EntityManager)ctx.lookup("java:/comp/env/"
				+ "newsUnit");
			//持久化News实体
			em.persist(news);
			tx.commit();
			PrintStream out = new PrintStream(response.getOutputStream());
			out.println("<h3>消息添加成功!</h3>");
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
	}
}</span>

注意:在事务中通过依赖查找的方式,来管理EntityManager。

需要注意的地方是EntityManager em = (EntityManager)ctx.lookup("java:/comp/env/"+ "newsUnit");

4.直接注入

也可以通过JBOSS直接注入我们所需要的EntityManager

<span style="font-family:SimSun;font-size:18px;">package lee;

import javax.persistence.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import javax.annotation.*;
import javax.transaction.*;
import javax.naming.*;

import org.crazyit.model.*;

public class AddNewsServlet extends HttpServlet
{
	//采用依赖注入的方式注入EntityManager
	@PersistenceContext(unitName="newsUnit")
	private EntityManager em;
	//依赖注入容器管理的JTA事务
	@Resource
	private UserTransaction tx;
	public void service(HttpServletRequest request
		, HttpServletResponse response)
		throws IOException , ServletException
	{
		request.setCharacterEncoding("GBK");
		//获取请求参数
		String title = request.getParameter("title");
		String content = request.getParameter("content");
		//创建实体对象
		News news = new News();
		news.setTitle(title);
		news.setContent(content);
		try
		{
			tx.begin();
			//持久化News实体
			em.persist(news);
			tx.commit();
			PrintStream out = new PrintStream(response.getOutputStream());
			out.println("<h3>消息添加成功!</h3>");
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
	}
}</span>

注意:与第一种方式相比,只不过是换了一种标签而已。由原来的EntityManagerFactory上@PersistenceUnit(unitName="newsUnit"),换成了@PersistenceContext(unitName="newsUnit")。

 5.ThreadLocal类来管理

也可以自定义一个EntityManagerUtil工具类,在这种工具类中使用ThreadLocal来保存EntityManager。

<span style="font-family:SimSun;font-size:18px;">package org.crazyit.util;

import javax.persistence.*;
public class EntityManagerUtil
{
	//保存系统中的EntityManagerFactory
	private static final EntityManagerFactory emf;
	//使用ThreadLocal来保证EntityManager的线程安全
	private static final ThreadLocal<EntityManager> threadLocal;
	/**初始化*/
	static
	{
		//初始化EntityManagerFactory对象
		emf = Persistence.createEntityManagerFactory("newsUnit");
		threadLocal = new ThreadLocal<EntityManager>();
	}
	//通过ThreadLocal获取EntityManager对象
	public static EntityManager getEntityManager()
	{
		//获取当前线程关联的EntityManager对象
		EntityManager em = threadLocal.get();
		//如果当前线程关联的EntityManager为null,或没有打开
		if (em == null || !em.isOpen())
		{
			//创建新的EntityManager
			em = emf.createEntityManager();
			threadLocal.set(em);
		}
		return em;
	}
	//关闭EntityManager对象
	public static void closeEntityManager()
	{
		EntityManager em = threadLocal.get();
		threadLocal.set(null);
		if (em != null)
		{
			em.close();
		}
	}
	//开始事务
	public static void beginTransaction()
	{
		getEntityManager().getTransaction().begin();
	}
	//提交事务
	public static void commit()
	{
		getEntityManager().getTransaction().commit();
	}
	//创建查询
	public static Query createQuery(String jpql)
	{
		return getEntityManager().createQuery(jpql);
	}
}</span>

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2025-01-04 22:21:30

EJB学习笔记十一(EntityManager几种管理方式)的相关文章

JAVA并发编程学习笔记------线程的三种创建方式

创建线程一般有如下几个方式: 1. 通过继承Thread类来创建一个线程: /** * 步骤1:定义一个继承Thread类的子类 * 步骤2:构造子类的一个对象 * 步骤3:启动线程: * */ public class ThreadTest{ public static void main(String[] args) { //构造子类对象 SubThread subThread = new SubThread(); //启动线程 subThread.start(); } } //定义继承Th

JAVA学习笔记-数组的三种初始化方式

package Study; public class TestArray02 { public static void main(String[] args){ //声明 int[] a; int b[]; //创建数组对象 a = new int[4]; b = new int[5]; //初始化(对数组元素的初始化) //默认初始化:数组元素相当于对象的成员变量,默认值跟成员变量的规则一样.数字0,布尔false,char\u0000,引用:null: //动态初始化: for(int i

【C#学习笔记】using 三种使用方式

1.using指令.using + 命名空间名字,这样可以在程序中直接用命令空间中的类型,而不必指定类型的详细命名空间,类似于Java的import,这个功能也是最常用的,几乎每个cs的程序都会用到. 例如:using System; 一般都会出现在*.cs中. 2.using别名.using + 别名 = 包括详细命名空间信息的具体的类型. 这种做法有个好处就是当同一个cs引用了两个不同的命名空间,但两个命名空间都包括了一个相同名字的类型的时候.当需要用到这个类型的时候,就每个地方都要用详细命

初探swift语言的学习笔记十一(performSelector)

作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/35842441 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号fengsh998来支持我,谢谢! 在OC中使用好好的performSelector,但不知为什么在swift有意的被拿掉了.更有甚者连IMP, objc_msgSend也不能用了.虽然想不通为什么,但应该有他的道理.就不纠结了. 大家可能在OC中使用得更多的就是延时处理,及后台处

第十七篇:实例分析(4)--初探WDDM驱动学习笔记(十一)

感觉有必要把 KMDDOD_INITIALIZATION_DATA 中的这些函数指针的意思解释一下, 以便进一步的深入代码. DxgkDdiAddDevice 前面已经说过, 这个函数的主要内容是,将BASIC_DISPLAY_DRIVER实例指针存在context中, 以便后期使用, 支持多实例. DxgkDdiStartDevice 取得设备信息, 往注册表中加入内容, 从POST设备中获取FRAME BUFFER以及相关信息(DxgkCbAcquirePostDisplayOwnershi

C++ Primer 学习笔记_57_类与数据抽象 --管理指针成员

复制控制 --管理指针成员 引言: 包含指针的类需要特别注意复制控制,原因是复制指针时只是复制了指针中的地址,而不会复制指针指向的对象! 将一个指针复制到另一个指针时,两个指针指向同一对象.当两个指针指向同一对象时,可能使用任一指针改变基础对象.类似地,很可能一个指针删除了一对象时,另一指针的用户还认为基础对象仍然存在.指针成员默认具有与指针对象同样的行为. 大多数C++类采用以下三种方法之一管理指针成员: 1)指针成员采取常规指针型行为:这样的类具有指针的所有缺陷但无需特殊的复制控制! 2)类

Git 学习笔记&lt;远程仓库与标签管理&gt; (四)

什么是远程仓库? 就像第一章介绍的那样,远程仓库可以储存你编写的所有源码和资源文件. 甚至也可以当网盘使,不过当然有很多契合git管理文本的特性. 下面就要以 github 为示例远程仓库进行介绍.  (也可以自己弄一台服务器作远程仓库). 创建仓库 在主页找到 +New repository 或者右上角的加号里有.输入名字 描述 然后没钱只能public就能确定了.然后呢,点名字打开你的仓库.(主页右下角可以找到) 关于与远程仓库的连接 首先你打开你的保险箱得先证明身份吧,不然我怎么知道你是客

Linux System Programming 学习笔记(十一) 时间

1. 内核提供三种不同的方式来记录时间: Wall time (or real time):actual time and date in the real world Process time:the time that a process spends executing on a processor 包括用户时间user time 和 系统时间system time Monotonic time:use the system's uptime (time since boot) for t

《Hibernate学习笔记十一》:树状结构设计

<Hibernate学习笔记十一>:树状结构设计 这是马士兵老师讲解Hibernate的一个作业题,树状结构设计,这是一个比较典型的例子,因此有必要写篇博文记录下. 树状结构的设计,它是在同一个类中使用了多对一(ManyToOne)和一对多(OneToMany). 在完成这个题目我们应该按照如下的步骤进行: 1.先思考数据库的模型应该是什么样的?? 数据库中的模型应该如下:即存在id p_id 2.思考面向对象的模型,及如何来进行映射??? 根据数据库中表的特点,对象应该有id name;由于