持久化API(JPA)系列(三)实体Bean的开发技术-建立与数据库的连接

   在EJB 2.x中,EJB有3种类型的Bean,分别是会话Bean(Session Bean)、消息驱动Bean(Message-Driven Bean)和实体Bean(Entity Bean)。

        随着EJB 3的推出,EJB2.x中的实体Bean逐渐被JPA规范所替代,JPA不仅能在EJB环境中使用,而且能在Java SE、Java EE环境中使用,相对于EJB 2.x中的实体Bean,它的使用范围更广。

        但这里我们仍然将其称做实体Bean。

        与会话Bean和消息驱动Bean类似,新的实体Bean也是一个加了注释符(@Entity)的简单Java对象(POJO),实体关系和O/R映射也是通过注释符来定义的,并提供几种不同的数据库操作规范。

        一旦被EntityManager访问,它就成为了一个持久化对象,并且成为了持久化上下文的一部分。此时我们就可以像使用Hibernate、iBATIS、MYBATIS一样来使用实体对象了。

        本文主要将详细讲解实体Bean的开发技术。

1、建立与数据库的连接,演示实体Bean的开发与调用过程。
2、实体管理器:执行数据库更新的方法。
3、生命周期:实体Bean的监听和回调。
4、关系实体映射:开发实体的方法。
5、JPQL查询语言:执行数据库实体查询。
6、原生SQL查询:执行原生SQL语句。


        它们之间的关系如图所示,通过实体管理器操作实体Bean,来实现对数据库的更新、JPQL查询和原生SQL查询。实体管理器是工具,实体Bean是数据。

下面首先来讲解实体Bean的调用过程,然后通过开发第一个实体Bean,演示该配置与开发的过程,包括以下内容:

1、配置数据源。
2、指定数据源。
3、开发第一个实体Bean--Student.java。
4、开发会话Bean进行调用--StudentDAORemote.java和StudentDAO.java。
5、打包并部署到JBoss服务器。
6、开发客户端进行测试--StudentDAOClient.java。


最终实现,通过实体Bean的建立与MySQL数据库的连接,往数据表中插入一条记录。

一、实体Bean的工作原理

实体Bean是作为持久化类被EJB容器管理的,要实现对该持久化类的调用,必须经过以下步骤。
(1)配置数据源连接。
(2)在配置文件persistence.xml中指定数据源。
(3)开发实体Bean。
(4)在会话Bean、Java SE或Java EE中调用实体Bean。

        实体Bean不仅可以被会话Bean调用,还可以被任何的Java类、JSP和Servlet调用,调用的目的是实现对数据库的操作。它的意义与Hibernate、iBATIS完全相同,就是作为系统的DAO层,实现对数据库的访问。
        下面我们就按照从底层到上层的顺序,来演示创建与数据库的连接的过程。

二、配置数据源


jndi-name:指定JNDI命名。
connection-url:数据库连接URL。
driver:数据库驱动类。
user-name:数据库登录用户名。
password:数据库登录密码。
我们只需要通过引用JNDI命令KsMysqlDS来引用该数据源,引用的方法很简单,只需要在persistence.xml中指定该别名即可

三、指定数据源--persistence.xml
以上配置的数据源由JBoss服务器加载和管理,要使用这些数据源,还需要在我们的应用中指定引用哪一个数据源。引用的方法很简单,只需要在应用的/项目/META-INF目录下添加一个配置文件persistence.xml即可,并在该文件中指定引用的数据源JNDI名称,同时可以设置该数据源的相关操作属性。
配置文件persistence.xml


其中包含3个配置元素,分别如下。
persistence-unit元素:可以有一个或多个,每个persistence-unit元素定义了持久化内容名称、使用的数据源名称及Hibernate属性。其中的name属性用于设置持久化名称。
jta-data-source元素:用于指定实体Bean使用的数据源名称KsMysqlDS,当指定数据源名称时java:/前缀不能缺少,并注意数据源名称的大小写。
properties元素:用于指定Hibernate的各项属性,如果hibernate.hbm2ddl.auto的值设为update,这样实体Bean添加一个属性时能同时在数据表增加相应字段。
(1)properties元素属性在各个应用服务器使用的持久化产品中都不一样,如JBoss使用Hibernate,WebLogic10使用Kodo,GlassFish/Sun Application Server/Oralce使用Toplink。
(2)JBoss服务器在启动或关闭时会引发实体Bean的发布及卸载。

四、开发第一个实体
实体Bean实际上对应了数据库中的表,它是数据库中表在Java类中的表现,通常为最普通的POJO类。EJB容器能够根据实体Bean自动在数据库中创建数据表,这就需要将实体类与数据表的结构进行对应,包括表名、字段名、字段长度、字段类型、主键等信息。
为了开发一个与数据库表对应的单表实体Bean,我们首先设计一个学生表student的数据结构,该表共包括7个字段,如表6-1所示。
学生表student
其中的字段类型对应了MySQL数据库中的字段类型,Java类型为相应的POJO类中的字段类型,即实体Bean中的变量类型。
要开发一个与该表对应的实体Bean很简单,只需要新建一个POJO类,添加7个与表的字段同名的变量,同时使用一些注释符来表示该实体Bean与数据表student的对应映射关系即可。
Bean类Student.java。首先我们来看看这个完整的实体类的代码,如下所示:

实体Bean类Student.java
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.ejb.entitybean;    
  2.    
  3. import java.io.Serializable;    
  4. import java.util.Date;    
  5. import javax.persistence.Column;    
  6. import javax.persistence.Entity;    
  7. import javax.persistence.GeneratedValue;    
  8. import javax.persistence.Id;    
  9. import javax.persistence.Table;    
  10.    
  11. @SuppressWarnings("serial")    
  12. @Entity   
  13. @Table(name = "Student")    
  14. public class Student implements Serializable {    
  15.     private Integer studentid;      //学号    
  16.     private String name;        //姓名    
  17.     private boolean sex;            //性别    
  18.     private Short age;          //年龄    
  19.     private Date birthday;      //出生日期    
  20.     private String address;     //地址    
  21.     private String telephone        //电话    
  22.    
  23.     @Id   
  24.     @GeneratedValue   
  25.     public Integer getStudentid() {    
  26.         return studentid;    
  27.     }    
  28.    
  29.     public void setStudentid(Integer studentid) {    
  30.         this.studentid = studentid;    
  31.     }    
  32.    
  33.     @Column(name = "name", length = 50)    
  34.     public String getName() {    
  35.         return name;    
  36.     }    
  37.    
  38.     public void setName(String name) {    
  39.         this.name = name;    
  40.     }    
  41.    
  42.     @Column(nullable = false)    
  43.     public boolean getSex() {    
  44.         return sex;    
  45.     }    
  46.    
  47.     public void setSex(boolean sex) {    
  48.         this.sex = sex;    
  49.     }    
  50.    
  51.     @Column(nullable = false)    
  52.     public Short getAge() {    
  53.         return age;    
  54.     }    
  55.    
  56.     public void setAge(Short age) {    
  57.         this.age = age;    
  58.     }    
  59.    
  60.     public Date getBirthday() {    
  61.         return birthday;    
  62.     }    
  63.    
  64.     public void setBirthday(Date birthday) {    
  65.         this.birthday = birthday;    
  66.     }    
  67.    
  68.     @Column(name = "address", length = 100)    
  69.     public String getAddress() {    
  70.         return address;    
  71.     }    
  72.    
  73.     public void setAddress(String address) {    
  74.         this.address = address;    
  75.     }    
  76.    
  77.     @Column(name = "telephone", length = 20)    
  78.     public String getTelephone() {    
  79.         return telephone;    
  80.     }    
  81.    
  82.     public void setTelephone(String telephone) {    
  83.         this.telephone = telephone;    
  84.     }    
  85. }   

实体Bean通常需要实现Serializable接口,这样就可以有EJB客户端创建该对象,并将该对象传送到服务端,否则将引发java.io.InvalidClassException例外。

该类是一个Java POJO类,其中包含了7个变量,并为每个变量添加了getter/setter函数。为了将该POJO类表现为一个实体Bean,添加了一些注释符,来与数据表student进行对应,这些注释如下。

@Entity注释指明这是一个实体Bean,每个实体Bean类映射数据库中的一个表。
@Table注释的name属性指定映射的数据表名称,Student类映射的数据表为Student。
@Column注释定义了映射到列的所有属性,如列名是否唯一,是否允许为空,是否允许更新等,其属性介绍如下。

name:映射的列名。如映射Student表的name列,可以在name属性的getName()方法上面加入@Column(name = "name"),如果不指定映射列名,则容器会将属性名称作为默认的映射列名。
unique:是否唯一。
nullable:是否允许为空。
length:对于字符型列,length属性指定列的最大字符长度。
insertable:是否允许插入。
updatable:是否允许更新。
columnDefinition:定义建表时创建此列的DDL。
secondaryTable:从表名。如果此列不建在主表上(默认建在主表上),则该属性定义该列所在的从表的名字。
@Lob注释指定某一个字段为大的文本字段类型。
@Id注释指定studentid属性为表的主键。
@GeneratedValue注释定义了标识字段的生成方式,本例中的studentid的值由MySQL数据库自动生成,它可以有以下多种生成方式。

TABLE:容器指定用底层的数据表确保唯一。
SEQUENCE:使用数据库的SEQUENCE 列来保证唯一。
IDENTITY:使用数据库的INDENTIT列来保证唯一。
AUTO:由容器挑选一个合适的方式来保证唯一。
NONE:容器不负责主键的生成,由调用程序来完成。

例如:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Id   
  2. @GeneratedValue(strategy = GenerationType.IDENTITY)    
  3. public Integer getId() {    
  4.     return this.id;    
  5. }   

这样就开发完实体Bean了,它除了在POJO上添加了一些注释外,与普通的POJO类没有任何区别。


五、开发会话Bean进行调用

1、开发会话Bean进行调用--StudentDAORemote.java和StudentDAO.java       。
        下面我们来开发一个远程的会话Bean组件,通过调用实体Bean类Student.java,来实现往数据表student中插入一条记录。
        首先在项目EntityBeanTest中新建一个包com.ejb.dao,然后按照会话Bean的开发方法,在该包中新建一个远程的会话Bean组件StudentDAO,新建完后会产生一个远程接口类StudentDAORemote.java和实现类StudentDAO.java。

1)远程接口类StudentDAORemote.java

        通过注释符@Remote进行标识。

        函数insert()执行插入student功能

远程接口类StudentDAORemote.java

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-family:SimSun;">package com.ejb.dao;    
  2.    
  3. import java.util.List;    
  4. import javax.ejb.Remote;    
  5. import com.ejb.entitybean.Student;    
  6.    
  7. @Remote   
  8. public interface StudentDAORemote {    
  9.     public boolean insert(Student student);    
  10. </span>  

2)实现类StudentDAO.java
        实现了远程接口StudentDAORemote.java,并通过@Stateless标识为无状态会话Bean。
        首先它包含了一个EntityManager类型的变量em,EntityManager是实体管理器,顾名思义,它是实体Bean的管理容器。通过该对象,我们能够实现与数据库的各种交互,包括增、删、改、查等。
        该实体变量em还通过注释@PersistenceContext来实现动态注入EntityManager对象,如果persistence.xml文件中配置了多个不同的持久化内容,则还需要指定持久化名称注入EntityManager 对象,可以通过@PersistenceContext注释的unitName属性进行指定,例如:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @PersistenceContext(unitName="exam-entity")    
  2. EntityManager em;   

如果只有一个持久化内容配置,则不需要明确指定。
        然后开发该类实现接口中的函数insert(),只需要调用em的persist()函数,就能够将Student对象持久化到数据库中,即往数据库中新增一条记录。
实现类StudentDAO.java

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.ejb.dao;    
  2.    
  3. import java.util.List;    
  4. import javax.ejb.Stateless;    
  5. import javax.persistence.EntityManager;    
  6. import javax.persistence.PersistenceContext;    
  7. import javax.persistence.Query;    
  8. import com.ejb.entitybean.Student;    
  9.    
  10. @Stateless   
  11. public class StudentDAO implements StudentDAORemote {    
  12.     @PersistenceContext   
  13.     protected EntityManager em;    
  14.    
  15.     public boolean insert(Student student) {    
  16.         try {    
  17.             em.persist(student);    
  18.         } catch (Exception e) {    
  19.             e.printStackTrace();    
  20.             return false;    
  21.         }    
  22.         return true;    
  23.     }    
  24. }  


六、打包并部署到JBOSS服务器

打成jar包并部署到JBoss服务器,JBoss服务器就会自动加载该服务。形成JNDI服务供外部访问了。

该发布过程如下:

1、加载persistence.xml文件。

2、创建数据库表student,此时查看MySQL数据库就会看到新建的表student。

3、发布JNDI服务StudentDAO/remote。

这样我们就可以通过客户端访问JNDI服务StudentDAO/remote了。


七、开发客户端进行测试-StudentDAOClient.java

        开发客户端进行测试--StudentDAOClient.java
        以上我们开发了实体Bean和会话Bean组件,并发布到了JBoss服务器中,下面我们来开发一个Java客户端程序,在该客户端创建一个实体对象,然后调用会话Bean组件插入该对象,往数据表中插入一条记录。
        首先将实体类Student.java和接口类StudentDAORemote.java复制添加到测试项目EJBTestJava的对应包中,然后新建测试类

测试类StudentDAOClient.java

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. import java.text.ParseException;    
  2. import java.text.SimpleDateFormat;    
  3. import java.util.Properties;    
  4.    
  5. import javax.naming.InitialContext;    
  6. import javax.naming.NamingException;    
  7.    
  8. import com.ejb.dao.StudentDAORemote;    
  9. import com.ejb.entitybean.Student;    
  10.    
  11. public class StudentDAOClient {    
  12.     public static void main(String[] args) throws NamingException {    
  13.         Properties props = new Properties();    
  14.         props.setProperty("java.naming.factory.initial",    
  15.                 "org.jnp.interfaces.NamingContextFactory");    
  16.         props.setProperty("java.naming.provider.url""localhost:1099");    
  17.         props.setProperty("java.naming.factory.url.pkgs""org.jboss.naming");    
  18.         try {    
  19.             InitialContext ctx = new InitialContext(props);    
  20.             StudentDAORemote studentDAO = (StudentDAORemote) ctx.lookup("StudentDAO/remote");    
  21.                 
  22.             Student student = new Student();    
  23.             student.setName("刘中兵");    
  24.             student.setSex(true);    
  25.             student.setAge((short)25);    
  26.             SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");    
  27.             student.setBirthday(format.parse("1981-05-04"));    
  28.             student.setTelephone("12345678");    
  29.             student.setAddress("北京");    
  30.                 
  31.             studentDAO.insert(student);    
  32.             System.out.println("已经插入一个学生记录!");    
  33.                 
  34.         } catch (NamingException e) {    
  35.             e.printStackTrace();    
  36.         } catch (ParseException e) {    
  37.             e.printStackTrace();    
  38.         }    
  39.     }    
  40. }   
        该类通过访问远程JNDI服务StudentDAO/remote,取得了远程会话Bean实例studentDAO。然后创建了一个Student实体对象,调用insert()函数插入该对象。运行该程序后,会在控制台中输出如下信息:
        已经插入一个学生记录!
        这就表明客户端的Java类已正确地将Student对象提交到远程会话Bean组件中了。
        经过第一次加载后的实体Bean对象已经被实体管理器EntityManager缓存了,再次访问时,就会直接从缓存中取得该实体对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值