持久化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
package com.ejb.entitybean;  
 
import java.io.Serializable;  
import java.util.Date;  
import javax.persistence.Column;  
import javax.persistence.Entity;  
import javax.persistence.GeneratedValue;  
import javax.persistence.Id;  
import javax.persistence.Table;  
 
@SuppressWarnings("serial")  
@Entity 
@Table(name = "Student")  
public class Student implements Serializable {  
    private Integer studentid;      //學號  
    private String name;        //姓名  
    private boolean sex;            //性別  
    private Short age;          //年齡  
    private Date birthday;      //出生日期  
    private String address;     //地址  
    private String telephone        //電話  
 
    @Id 
    @GeneratedValue 
    public Integer getStudentid() {  
        return studentid;  
    }  
 
    public void setStudentid(Integer studentid) {  
        this.studentid = studentid;  
    }  
 
    @Column(name = "name", length = 50)  
    public String getName() {  
        return name;  
    }  
 
    public void setName(String name) {  
        this.name = name;  
    }  
 
    @Column(nullable = false)  
    public boolean getSex() {  
        return sex;  
    }  
 
    public void setSex(boolean sex) {  
        this.sex = sex;  
    }  
 
    @Column(nullable = false)  
    public Short getAge() {  
        return age;  
    }  
 
    public void setAge(Short age) {  
        this.age = age;  
    }  
 
    public Date getBirthday() {  
        return birthday;  
    }  
 
    public void setBirthday(Date birthday) {  
        this.birthday = birthday;  
    }  
 
    @Column(name = "address", length = 100)  
    public String getAddress() {  
        return address;  
    }  
 
    public void setAddress(String address) {  
        this.address = address;  
    }  
 
    @Column(name = "telephone", length = 20)  
    public String getTelephone() {  
        return telephone;  
    }  
 
    public void setTelephone(String telephone) {  
        this.telephone = telephone;  
    }  
} 

實體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:容器不負責主鍵的生成,由調用程序來完成。

例如:

@Id 
@GeneratedValue(strategy = GenerationType.IDENTITY)  
public Integer getId() {  
    return this.id;  
} 

這樣就開發完實體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

<span style="font-family:SimSun;">package com.ejb.dao;  
 
import java.util.List;  
import javax.ejb.Remote;  
import com.ejb.entitybean.Student;  
 
@Remote 
public interface StudentDAORemote {  
    public boolean insert(Student student);  
} </span>

2)實現類StudentDAO.java
        實現了遠程接口StudentDAORemote.java,並通過@Stateless標識爲無狀態會話Bean。
        首先它包含了一個EntityManager類型的變量em,EntityManager是實體管理器,顧名思義,它是實體Bean的管理容器。通過該對象,我們能夠實現與數據庫的各種交互,包括增、刪、改、查等。
        該實體變量em還通過註釋@PersistenceContext來實現動態注入EntityManager對象,如果persistence.xml文件中配置了多個不同的持久化內容,則還需要指定持久化名稱注入EntityManager 對象,可以通過@PersistenceContext註釋的unitName屬性進行指定,例如:

@PersistenceContext(unitName="exam-entity")  
EntityManager em; 

如果只有一個持久化內容配置,則不需要明確指定。
        然後開發該類實現接口中的函數insert(),只需要調用em的persist()函數,就能夠將Student對象持久化到數據庫中,即往數據庫中新增一條記錄。
實現類StudentDAO.java

package com.ejb.dao;  
 
import java.util.List;  
import javax.ejb.Stateless;  
import javax.persistence.EntityManager;  
import javax.persistence.PersistenceContext;  
import javax.persistence.Query;  
import com.ejb.entitybean.Student;  
 
@Stateless 
public class StudentDAO implements StudentDAORemote {  
    @PersistenceContext 
    protected EntityManager em;  
 
    public boolean insert(Student student) {  
        try {  
            em.persist(student);  
        } catch (Exception e) {  
            e.printStackTrace();  
            return false;  
        }  
        return true;  
    }  
}


六、打包並部署到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

import java.text.ParseException;  
import java.text.SimpleDateFormat;  
import java.util.Properties;  
 
import javax.naming.InitialContext;  
import javax.naming.NamingException;  
 
import com.ejb.dao.StudentDAORemote;  
import com.ejb.entitybean.Student;  
 
public class StudentDAOClient {  
    public static void main(String[] args) throws NamingException {  
        Properties props = new Properties();  
        props.setProperty("java.naming.factory.initial",  
                "org.jnp.interfaces.NamingContextFactory");  
        props.setProperty("java.naming.provider.url", "localhost:1099");  
        props.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming");  
        try {  
            InitialContext ctx = new InitialContext(props);  
            StudentDAORemote studentDAO = (StudentDAORemote) ctx.lookup("StudentDAO/remote");  
              
            Student student = new Student();  
            student.setName("劉中兵");  
            student.setSex(true);  
            student.setAge((short)25);  
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");  
            student.setBirthday(format.parse("1981-05-04"));  
            student.setTelephone("12345678");  
            student.setAddress("北京");  
              
            studentDAO.insert(student);  
            System.out.println("已經插入一個學生記錄!");  
              
        } catch (NamingException e) {  
            e.printStackTrace();  
        } catch (ParseException e) {  
            e.printStackTrace();  
        }  
    }  
} 
        該類通過訪問遠程JNDI服務StudentDAO/remote,取得了遠程會話Bean實例studentDAO。然後創建了一個Student實體對象,調用insert()函數插入該對象。運行該程序後,會在控制檯中輸出如下信息:
        已經插入一個學生記錄!
        這就表明客戶端的Java類已正確地將Student對象提交到遠程會話Bean組件中了。
        經過第一次加載後的實體Bean對象已經被實體管理器EntityManager緩存了,再次訪問時,就會直接從緩存中取得該實體對象。

發佈了134 篇原創文章 · 獲贊 28 · 訪問量 53萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章