EJB持久性 - EJB
EJB2.0中使用的实体bean持久化机制在很大程度上被EJB3.0取代。现在实体bean是一个简单的POJO映射表。
以下是持久性API的关键角色
Entity - 持久对象代表数据存储记录。这也是可序列化的。
EntityManager - 持久性接口做数据操作,如添加/删除/更新/找到持久化对象(实体)。它还有助于执行查询使用query接口
Persistence unit (persistence.xml) - 持久性单元介绍了持久性机制的属性。
Data Source (*ds.xml) - 数据源描述了数据存储相关的属性,如连接URL。用户名,密码等。
为了证明EJB的持久化机制,我们要做好以下几项工作。
Step 1. 在数据库中创建表.
Step 2. 创建实体类对应的表.
Step 3. 创建数据源和持久性单元
Step 4. 创建一个无状态EJB EntityManager实例.
Step 5. 更新无状态EJB。添加添加记录并获得通过实体管理器从数据库中记录的方法。
Step 6. 一个基于控制台应用程序客户端将访问无状态EJB的持久化数据库中的数据。
创建表
创建一个表 books 在默认的数据库 postgres.
CREATE TABLE books (
id integer PRIMARY KEY,
name varchar(50)
);
创建实体类
//mark it entity using Entity annotation
//map table name using Table annoation
@Entity
@Table(name="books")
public class Book implements Serializable{
private int id;
private String name;
public Book(){
}
//mark id as primary key with autogenerated value
//map database column id with id field
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
@Column(name="id")
public int getId() {
return id;
}
...
}
创建数据源和持久性单元
DataSource (jboss-ds.xml)
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>PostgresDS</jndi-name>
<connection-url>jdbc:postgresql://localhost:5432/postgres</connection-url>
<driver-class>org.postgresql.driver</driver-class>
<user-name>sa</user-name>
<password>sa</password>
<min-pool-size>5</min-pool-size>
<max-pool-size>20</max-pool-size>
<idle-timeout-minutes>5</idle-timeout-minutes>
</local-tx-datasource>
</datasources>
Persistence Unit (persistence.xml)
<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">
<persistence-unit name="EjbComponentPU" transaction-type="JTA">
<jta-data-source>java:/PostgresDS</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties/>
</persistence-unit>
<persistence-unit name="EjbComponentPU2" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/PostgresDS</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
Create Stateless EJB having EntityManager instance
@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {
//pass persistence unit to entityManager.
@PersistenceContext(unitName="EjbComponentPU")
private EntityManager entityManager;
public void addBook(Book book) {
entityManager.persist(book);
}
public List<Book> getBooks() {
return entityManager.createQuery("From Books").getResultList();
}
...
}
构建EJB模块后,我们需要一个无状态的bean,我们将在下一节要创建客户端来访问。
示例应用程序
让我们创建一个测试EJB应用程序来测试EJB的持久化机制。
Step | 描述 |
---|---|
1 | Create a project with a name EjbComponent under a package com.tutorialspoint.entity as explained in the EJB - Create Application chapter. You can also use the project created in EJB - Create Application chapter as such for this chapter to understand ejb persistence concepts. |
2 | Create Book.java under package com.tutorialspoint.entity and modify it as shown below. |
3 | Create LibraryPersistentBean.java and LibraryPersistentBeanRemote as explained in the EJB - Create Application chapter and modify them as shown below. |
4 | Create jboss-ds.xml in EjbComponent > setup folder and persistence.xml in EjbComponent > src > conf folder. These folder can be seen in files tab in Netbeans. Modify these files as shown above. |
5 | 清理并生成应用程序以确保业务逻辑是按要求工作。 |
6 | 最后,将应用程序部署在JBoss应用服务器上的jar文件的形式。 JBoss应用服务器将自动开始浏览网页,如果它尚未启动。 |
7 | Now create the ejb client, a console based application in the same way as explained in theEJB - Create Application chapter under topic Create Client to access EJB. Modify it as shown below. |
EJBComponent (EJB Module)
Book.java
package com.tutorialspoint.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="books")
public class Book implements Serializable{
private int id;
private String name;
public Book(){
}
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
@Column(name="id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
LibraryPersistentBeanRemote.java
package com.tutorialspoint.stateless;
import com.tutorialspoint.entity.Book;
import java.util.List;
import javax.ejb.Remote;
@Remote
public interface LibraryPersistentBeanRemote {
void addBook(Book bookName);
List<Book> getBooks();
}
LibraryPersistentBean.java
package com.tutorialspoint.stateless;
import com.tutorialspoint.entity.Book;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Stateless
public class LibraryPersistentBean implements LibraryPersistentBeanRemote {
public LibraryPersistentBean(){
}
@PersistenceContext(unitName="EjbComponentPU")
private EntityManager entityManager;
public void addBook(Book book) {
entityManager.persist(book);
}
public List<Book> getBooks() {
return entityManager.createQuery("From Book").getResultList();
}
}
As soon as you deploy the EjbComponent project on JBOSS, notice the jboss log.
JBoss has automatically created a JNDI entry for our session bean -LibraryPersistentBean/remote.
We'll using this lookup string to get remote business object of type -com.tutorialspoint.stateless.LibraryPersistentBeanRemote
JBoss应用服务器的日志输出
...
16:30:01,401 INFO [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
LibraryPersistentBean/remote-com.tutorialspoint.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibraryPersistentBeanRemote,service=EJB3
16:30:02,723 INFO [EJBContainer] STARTED EJB: com.tutorialspoint.stateless.LibraryPersistentBeanRemote ejbName: LibraryPersistentBean
16:30:02,731 INFO [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
LibraryPersistentBean/remote - EJB3.x Default Remote Business Interface
LibraryPersistentBean/remote-com.tutorialspoint.stateless.LibraryPersistentBeanRemote - EJB3.x Remote Business Interface
...
EJBTester (EJB Client)
jndi.properties
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
These properties are used to initialize the InitialContext object of java naming service
InitialContext object will be used to lookup stateless session bean
EJBTester.java
package com.tutorialspoint.test;
import com.tutorialspoint.stateless.LibraryPersistentBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EJBTester {
BufferedReader brConsoleReader = null;
Properties props;
InitialContext ctx;
{
props = new Properties();
try {
props.load(new FileInputStream("jndi.properties"));
} catch (IOException ex) {
ex.printStackTrace();
}
try {
ctx = new InitialContext(props);
} catch (NamingException ex) {
ex.printStackTrace();
}
brConsoleReader =
new BufferedReader(new InputStreamReader(System.in));
}
public static void main(String[] args) {
EJBTester ejbTester = new EJBTester();
ejbTester.testEntityEjb();
}
private void showGUI(){
System.out.println("**********************");
System.out.println("Welcome to Book Store");
System.out.println("**********************");
System.out.print("Options
1\. Add Book
2\. Exit
Enter Choice: ");
}
private void testEntityEjb(){
try {
int choice = 1;
LibraryPersistentBeanRemote libraryBean =
LibraryPersistentBeanRemote)ctx.lookup("LibraryPersistentBean/remote");
while (choice != 2) {
String bookName;
showGUI();
String strChoice = brConsoleReader.readLine();
choice = Integer.parseInt(strChoice);
if (choice == 1) {
System.out.print("Enter book name: ");
bookName = brConsoleReader.readLine();
Book book = new Book();
book.setName(bookName);
libraryBean.addBook(book);
} else if (choice == 2) {
break;
}
}
List<Book> booksList = libraryBean.getBooks();
System.out.println("Book(s) entered so far: " + booksList.size());
int i = 0;
for (Book book:booksList) {
System.out.println((i+1)+". " + book.getName());
i++;
}
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}finally {
try {
if(brConsoleReader !=null){
brConsoleReader.close();
}
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
}
EJBTester is doing the following tasks.
Load properties from jndi.properties and initialize the InitialContext object.
In testStatefulEjb() method, jndi lookup is done with name - "LibraryStatefulSessionBean/remote" to obtain the remote business object (stateful ejb).
Then user is shown a library store User Interface and he/she is asked to enter choice.
If user enters 1, system asks for book name and saves the book using stateless session bean addBook() method. Session Bean is persisting the book in database via EntityManager call.
If user enters 2, system retrieves books using stateful session bean getBooks() method and exits.
Then another jndi lookup is done with name - "LibraryStatelessSessionBean/remote" to obtain the remote business object (stateless ejb) again and listing of books is done.
运行客户端访问EJB
在项目资源管理器中找到EJBTester.java。右键点击上EJBTester类,并选择 run file.
在Netbeans控制台验证以下输出。
run:
**********************
Welcome to Book Store
**********************
Options
1\. Add Book
2\. Exit
Enter Choice: 1
Enter book name: Learn Java
**********************
Welcome to Book Store
**********************
Options
1\. Add Book
2\. Exit
Enter Choice: 2
Book(s) entered so far: 1
1\. learn java
BUILD SUCCESSFUL (total time: 15 seconds)
再次运行客户端来访问EJB。
访问EJB之前重新启动JBoss。
在项目资源管理器中找到EJBTester.java。右键点击上EJBTester类,并选择 run file.
在Netbeans控制台验证以下输出。
run:
**********************
Welcome to Book Store
**********************
Options
1\. Add Book
2\. Exit
Enter Choice: 1
Enter book name: Learn Spring
**********************
Welcome to Book Store
**********************
Options
1\. Add Book
2\. Exit
Enter Choice: 2
Book(s) entered so far: 2
1\. learn java
2\. Learn Spring
BUILD SUCCESSFUL (total time: 15 seconds)
- 上面显示的输出状态书存储在持久性存储,并从数据库中检索。