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); }
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 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>
<?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-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