EJB3的实体查询 本文 使用的是JPA规范进行操作 产品实现用的是Hibernate
主要涉及到增加、删除、更新、对象查询带排序、查询条件中使用构造器、运算符查询、字符串函数、计算函数、聚合函数
先来看看 提供EJB服务的无状态bean
package com.undergrowth.bean.impl;
import java.util.List;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import com.undergrowth.bean.Person;
import com.undergrowth.bean.SimplePerson;
import com.undergrowth.bean.service.IPerson;
@Stateless
@Remote(IPerson.class)
public class PersonDao implements IPerson {
//依赖注入实体管理器
@PersistenceContext
EntityManager em;
@Override
public void save(Person person) {
// TODO Auto-generated method stub
//由新建状态转为托管
em.persist(person);
}
@Override
public void delete(Integer personId) {
// TODO Auto-generated method stub
//由托管转为销毁
em.remove(getReferencesById(personId));
}
@Override
public void update(Person person) {
// TODO Auto-generated method stub
//由游离转为托管
em.merge(person);
}
@Override
public Person getById(Integer personId) {
// TODO Auto-generated method stub
return em.find(Person.class, personId);
}
@Override
public Person getReferencesById(Integer personId) {
// TODO Auto-generated method stub
//使用懒加载 返回代理对象 只有在使用get方法获取数据时 才加载对象
return em.getReference(Person.class, personId);
}
/**
* 通过sql来获取对象
* @param sql
* @return
*/
@SuppressWarnings("unchecked")
@Override
public List<Person> getBySql(String sql) {
// TODO Auto-generated method stub
Query query=em.createQuery(sql);
return (List<Person>)query.getResultList();
}
/**
* 通过sql来进行删除 添加 修改 数据
* @param sql
* @return
*/
@Override
public int cudBySql(String sql) {
// TODO Auto-generated method stub
Query query=em.createQuery(sql);
int num=query.executeUpdate();
return num;
}
@SuppressWarnings("unchecked")
@Override
public List<Person> getAllPersons() {
// TODO Auto-generated method stub
//使用JPQL进行查询结果集
return (List<Person>)em.createQuery("select p from Person p").getResultList();
}
/**
* 返回部分对象
*/
@SuppressWarnings("unchecked")
@Override
public List<SimplePerson> getSimplePersonThroSql(String sql) {
// TODO Auto-generated method stub
return (List<SimplePerson>)em.createQuery(sql).getResultList();
}
/**
* 通过查询返回单一的结果集
*/
@Override
public Object getBySqlRetSimple(String sql) {
// TODO Auto-generated method stub
Query query=em.createQuery(sql);
return query.getSingleResult();
}
}
package com.undergrowth.bean.service;
import java.util.List;
import javax.persistence.Query;
import com.undergrowth.bean.Person;
import com.undergrowth.bean.SimplePerson;
public interface IPerson {
//增删改查
public void save(Person person);
public void delete(Integer personId);
public void update(Person person);
/**
* 通过sql来进行删除 添加 修改 数据
* @param sql
* @return
*/
public int cudBySql(String sql);
public Person getById(Integer personId);
public Person getReferencesById(Integer personId);
/**
* 通过sql来获取对象
* @param sql
* @return
*/
public List<Person> getBySql(String sql);
public List<Person> getAllPersons();
/**
* 获取只有id name age的Person
* @param sql
* @return
*/
public List<SimplePerson> getSimplePersonThroSql(String sql);
public Object getBySqlRetSimple(String sql);
}
一对一的实体bean
package com.undergrowth.bean;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
/*
* 步骤
* 1.一对一的相互关联 各自实体中拥有对方
* 2.设置关系维护端与被维护端 指定级联的关系
* 3.指明外键
* 4.添加数据
*/
@Entity
@Table(name="person_info")
public class Person implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
@Id @GeneratedValue
private Integer id;
@Column(length=10,nullable=false)
private String name;
@Column(nullable=false)
private Integer age;
//all表示当person进行增删改查的时候 级联的增删改查idcard
//optional为false表示外键不能为空
@OneToOne(cascade=CascadeType.ALL,optional=false)
//JoinColumn指明idcard_id作为外键 来维护两个表的关系
@JoinColumn(name="idcard_id")
private IDCard idCard;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Person(){} //用于给反射机制使用
public IDCard getIdCard() {
return idCard;
}
public void setIdCard(IDCard idCard) {
this.idCard = idCard;
}
public Person(String name, Integer age, IDCard idCard) {
super();
this.name = name;
this.age = age;
this.idCard = idCard;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", age=" + age
+ ", idCard=" + idCard + "]";
}
}
package com.undergrowth.bean;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name="idcard_info")
public class IDCard implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
@Id @GeneratedValue
private Integer id;
@Column(length=18,nullable=false)
private String cardNum;
@Column(length=20,nullable=false)
private String issuedBy;
//mappedBy指定使用person对象的idCard这个属性来进行维护表间关系 并指明自己是关系的被维护端
@OneToOne(mappedBy="idCard")
private Person person;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCardNum() {
return cardNum;
}
public void setCardNum(String cardNum) {
this.cardNum = cardNum;
}
public String getIssuedBy() {
return issuedBy;
}
public void setIssuedBy(String issuedBy) {
this.issuedBy = issuedBy;
}
public IDCard(){} //用于给反射机制使用
public IDCard(String cardNum, String issuedBy) {
this.cardNum = cardNum;
this.issuedBy = issuedBy;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
@Override
public String toString() {
return "IDCard [id=" + id + ", cardNum=" + cardNum + ", issuedBy="
+ issuedBy + "]";
}
}
封装部分实体属性的SimplePerson
package com.undergrowth.bean;
import java.io.Serializable;
public class SimplePerson implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "SimplePerson [id=" + id + ", name=" + name + ", age=" + age
+ "]";
}
public SimplePerson(Integer id, String name, Integer age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public SimplePerson() {
super();
}
}
哦 persistence.xml文件
<persistence 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_2_0.xsd"
version="2.0">
<persistence-unit name="under" transaction-type="JTA">
<jta-data-source>java:/myDataSource</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
ant的编译build.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- ================================================ -->
<!-- Sample buildfile for jar components -->
<!-- -->
<!-- ================================================ -->
<project name="EJB3QL" basedir=".">
<!-- 定义属性 -->
<property name="src.dir" value="${basedir}\src" />
<!-- 访问操作系统的环境变量 -->
<property environment="env" />
<!-- 设置jboss的目录 -->
<property name="jboss.home" value="${env.JBOSS_HOME}"/>
<!-- 设置jboss的服务器名 -->
<property name="jboss.server.home" value="standalone" />
<property name="dep" value="deployments" />
<property name="build.dir" value="${basedir}\build" />
<!--构建path路径 -->
<path id="build.classpath">
<fileset dir="${basedir}\lib">
<include name="*.jar" />
</fileset>
<!--<pathelement location="${build.dir}" /> -->
</path>
<!-- - - - - - - - - - - - - - -->
<!-- target: init -->
<!-- - - - - - - - - - - - - - -->
<target name="init">
<delete dir="${build.dir}"></delete>
<mkdir dir="${build.dir}"></mkdir>
</target>
<!-- ========================= -->
<!-- target: compile -->
<!-- ========================= -->
<target name="compile" depends="init"
description="--> compile this component" >
<!-- 编译src目录下以com开头的所有子包中的类
'*' matches zero or more characters, '?' matches one character.
When ** is used as the name of a directory in the pattern, it matches zero or more directories
-->
<javac srcdir="${src.dir}" destdir="${build.dir}" includes="com/**" includeAntRuntime="false">
<classpath refid="build.classpath" />
</javac>
</target>
<!-- 打包 -->
<target name="ejbjar" depends="compile" description="打包ejb">
<jar jarfile="${basedir}\${ant.project.name}.jar">
<fileset dir="${build.dir}">
<!-- 将build目录下的所有已class结尾的文件打包进去 -->
<include name="**/*.class"></include>
</fileset>
<!--将src目录下的META-INF目录下的文件打包进去 -->
<metainf dir="${src.dir}\META-INF"></metainf>
</jar>
</target>
<!-- 部署 -->
<target name="delopy" depends="ejbjar" description="部署ejb">
<copy file="${basedir}\${ant.project.name}.jar" todir="${jboss.home}\${jboss.server.home}\${dep}\" />
</target>
<!-- 卸载ejb -->
<target name="undeploy" description="卸载ejb">
<delete file="${jboss.home}\${jboss.server.home}\${dep}\${ant.project.name}.jar"></delete>
</target>
<!-- 打包接口 -->
<target name="package_inter" depends="compile" description="打包接口">
<jar jarfile="${basedir}\${ant.project.name}Interface.jar">
<fileset dir="${build.dir}">
<!-- 将build目录下中impl目录下的已class结尾的文件不打包进去 -->
<exclude name="**/impl/*.class"></exclude>
</fileset>
</jar>
</target>
<!-- 删除生成的class和打包的文件 -->
<target name="clean" description="清除项目">
<delete dir="${build.dir}"></delete>
<delete file="${basedir}\${ant.project.name}.jar"></delete>
<delete file="${basedir}\${ant.project.name}Interface.jar"></delete>
</target>
</project>
将无状态bean使用ant工具进行发布到jboss 中 后 即可通过客户端进行访问无状态的服务bean了
2、
客户端
工具类 用于获取EJB服务
package com.client.undergrowth.util;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.undergrowth.bean.service.IPerson;
public class JndiUtil {
/**
* 获取EJB PersonDao的服务
* @return
* @throws NamingException
*/
public static IPerson lookupIPersonRemoteBean() throws NamingException{
return (IPerson)lookupRemoteBean("EJB3QL","PersonDao",IPerson.class.getName());
}
/**
* 通过模块名,Bean名称,接口名称获取远程服务
* @param moduleName
* @param beanName
* @param viewClassName
* @return
* @throws NamingException
*/
public static Object lookupRemoteBean(String moduleName,String beanName,String viewClassName) throws NamingException {
final Hashtable jndiProperties = new Hashtable();
jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
final Context context = new InitialContext(jndiProperties);
// The app name is the application name of the deployed EJBs. This is typically the ear name
// without the .ear suffix. However, the application name could be overridden in the application.xml of the
// EJB deployment on the server.
// Since we haven't deployed the application as a .ear, the app name for us will be an empty string
final String appName = "";
// This is the module name of the deployed EJBs on the server. This is typically the jar name of the
// EJB deployment, without the .jar suffix, but can be overridden via the ejb-jar.xml
// In this example, we have deployed the EJBs in a jboss-as-ejb-remote-app.jar, so the module name is
// jboss-as-ejb-remote-app
//final String moduleName = "EJB3QL";
// AS7 allows each deployment to have an (optional) distinct name. We haven't specified a distinct name for
// our EJB deployment, so this is an empty string
final String distinctName = "";
// The EJB name which by default is the simple class name of the bean implementation class
// final String beanName = "PersonDao";
// the remote view fully qualified class name
// final String viewClassName = HelloWorldRemote.class.getName();
// final String viewClassName = IPerson.class.getName();
// let's do the lookup
return context.lookup("ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName);
}
}
单元测试类
package com.junit.test;
import static org.junit.Assert.*;
import java.util.Iterator;
import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
import com.client.undergrowth.util.JndiUtil;
import com.undergrowth.bean.IDCard;
import com.undergrowth.bean.Person;
import com.undergrowth.bean.SimplePerson;
import com.undergrowth.bean.service.IPerson;
public class PersonDaoTest {
static IPerson personDao = null;
final int cudNum=8;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
// 获取服务
personDao = JndiUtil.lookupIPersonRemoteBean();
}
/**
* 保存
*/
@Test
public void testSave() {
IDCard idCard = new IDCard("333333333", "太平洋美国");
// 将关系被维护端的数据传递给关系维护端的数据 用于外键的更新
Person person = new Person("奥巴马", 5, idCard);
// 因为级联关系设置了级联保存 所以这里保存person 同时也会保存idCard
personDao.save(person);
}
/**
* 删除
*/
@Test
public void testDelete() {
personDao.delete(cudNum);
}
/**
* 更新
*/
@Test
public void testUpdate() {
Person person=personDao.getById(cudNum);
person.setName("普京");
personDao.update(person);
}
/**
* 通过id获取对象
*/
@Test
public void testGetById() {
System.out.println(personDao.getById(cudNum));
}
/**
* 获取对象代理
*/
@Test
public void testGetReferencesById() {
//可避免数据库加载的持久化开销
//因为返回的是代理对象 没有持久化操作 所以这里会报错 无法获取对象
//System.out.println(personDao.getReferencesById(8));
}
/**
* 对象查询
*/
@Test
public void testGetBySql() {
String sqlString="select p from Person p where p.age>12";
outListPerson(personDao.getBySql(sqlString));
}
/**
* 对象查询带排序
* order by asc/desc
*/
@Test
public void testGetBySqlOrderBy() {
String sqlString="select p from Person p order by p.age desc";
outListPerson(personDao.getBySql(sqlString));
}
/**
* 查询条件中使用构造器 返回构造器对象的结果集
*/
@Test
public void testGetSimplePersonThroSql() {
String sqlString="select new com.undergrowth.bean.SimplePerson(p.id,p.name,p.age) from Person p where p.age>8 order by p.age desc";
outListSimplePerson(personDao.getSimplePersonThroSql(sqlString));
}
/**
* 测试运算符 not 、between and 、like、in、is null、exists
*/
@Test
public void testOperatorBetween() {
String sqlString="select p from Person p where p.age between 2 and 15";
outListPerson(personDao.getBySql(sqlString));
}
/**
* 测试运算符 not 、between and 、like、in、is null、exists
*/
@Test
public void testOperatorLike() {
String sqlString="select p from Person p where p.name like '%奥%' ";
outListPerson(personDao.getBySql(sqlString));
}
/**
* 测试运算符 not 、between and 、like、in、is null、exists
*/
@Test
public void testOperatorExists() {
String sqlString="select p from Person p where exists(select pe from IDCard pe where pe.id>13) ";
outListPerson(personDao.getBySql(sqlString));
}
/**
* 测试字符串函数 upper lower concat length substring trim locate
*/
@Test
public void testStrFunc() {
String sqlString="select p from Person p where length(p.name)>2 ";
outListPerson(personDao.getBySql(sqlString));
}
/**
* 测试计算函数 abs mod sqrt size
*/
@Test
public void testNumberFunc() {
String sqlString="select p from Person p where mod(p.age,10) > 1 ";
outListPerson(personDao.getBySql(sqlString));
}
/**
* 返回单一的结果集 聚合函数 count max min avg sum
*/
@Test
public void testGetBySqlRetSimple() {
//这里不能使用count(1) 因为这是基于对象的查询 1被当做值 导致报错
String sqlString="select count(*) from Person p where p.age>8";
System.out.println("年龄大于8岁的人有"+personDao.getBySqlRetSimple(sqlString));
}
/**
* 使用语句进行更新 删除 增加
*/
@Test
public void testCudBySql() {
String sqlUpdateString="update Person p set p.name='刘德华' where p.age=20";
System.out.println("影响结果集为:"+personDao.cudBySql(sqlUpdateString)+"条");
}
/**
* 获取所有对象
*/
@Test
public void testGetAllPersons() {
List<Person> list=personDao.getAllPersons();
outListPerson(list);
}
/**
* 遍历输出结果集
* @param list
*/
private void outListPerson(List<Person> list) {
// TODO Auto-generated method stub
for (Person person : list) {
System.out.println(person);
}
}
/**
* 输出SimplePerson
* @param list
*/
private void outListSimplePerson(List<SimplePerson> list) {
// TODO Auto-generated method stub
for (SimplePerson person : list) {
System.out.println(person);
}
}
}
客户端连接jboss的jndi配置文件
jboss-ejb-client.properties
endpoint.name=client-endpoint
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=default
remote.connection.default.host= localhost
remote.connection.default.port = 4447
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.default.username=qq
remote.connection.default.password=q