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>


你可能感兴趣的:(EJB学习笔记十一(EntityManager几种管理方式))