📄 16. ejb note.txt
字号:
<enterprise-beans>
<session>
<ejb-name>BeanName</ejb-name>
<remote>package.IBeanName</remote>
<local>package.IBeanName</local>
<ejb-class>package.IBeanImplements</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
</ejb-jar>
2) 特定应用服务器部署描述符:
JBoss:jboss.xml
Weblogic:weblogic-ejb-jar.xml
Sun:sun-ejb-jar.xml
标注和部署描述符的区别:
标注 部署描述符
简单便利,直观 复杂,容易出错
分散管理,无法应付复杂应用 集中管理,可以应付较复杂应用
EJB提供者和部署者不是同一人 适合于EJB提供者和部署者不是同一人的情况
容易出错
注意:标注与部署描述符同时使用,部署描述符的优先级更高,会覆盖标注!!!
6. Session Bean(会话Bean)
业务组件: 由客户端程序调用的一段业务逻辑, 作用相当于Spring管理的服务组件。一个EJB组件在容器中可能包含多个实例。
会话Bean:对业务逻辑建模:用程序模拟处理一件事情的流程和步骤
7. 会话Bean的分类:
Stateless Sesssion Bean(无状态会话Bean,简称:SLSB)
1)一次方法调用代表一次会话
2)多次方法请求之间不保存状态 (只能调用方法,不能访问属性)
3)Bean的对象实例可以被任何客户调用
Stateful session Bean(有状态会话Bean,简称:SFSB)
1)会话贯穿于多次方法调用之间
2)多次方法请求之间保存状态
SFSB像servlet中的Session对象,可以访问SFSB的属性,SFSB的属性值会自动保留,供下次访问
3)只有一个客户能访问这个Bean的对象实例和它的状态
8. 无状态会话Bean的对象和并发服务
1)实例数量是容器根据客户端数量,来创建的。创建以后不会销毁,容器销毁或删除此项目时才销毁
2)不能区分不同的客户。由哪个实例响应客户端,是由容器决定的。按静态方法来使用。
3)实例可共享,和客户stub是多对多。不能拥有实例变量,即使有,也不能暴露给客户
4)生命周期:不存在 -> 就绪
5)回调方法和Remove方法
6)并发访问
a.没有状态,因此也无需做并发处理
b.串行共享
c.对象池 --- 容器会初始化n个Bean对象应付成千上万的客户端的并发请求。
9. 无状态会话Bean的生命周期(状态图)
1)不存在 -> 就绪
过程: 1创建Bean实例 2依赖注入 3@PostConstrcut回调方法)
2)就绪 -> 不存在
过程: @PreDestroy回调方法
3)回调方法@PostConstrcut和@PreDestroy,可以定义在Bean类中,也可以定义在单独的类中
@PostConstrcut 进行初始化工作,比如获取一些不能用依赖注入获得的资源
@PreDestroy 释放初始化时获得的资源
4)独立的回调类
@Interceptors(Callback.class)
10.有状态会话Bean的对象池和并发服务
1)能区分不同的客户,可以记住客户信息
2)跨越多个请求(方法调用),维护会话状态(bean类的实例变量)
3)Bean对象和stub一对一
4)生命周期:不存在 -> 就绪 -> 钝化
状态包括:
成员变量是非transient类型的java基本类型或对象
本地或者远程接口的EJB引用
容器管理的资源
JNDI命名上下文Context
5)回调方法和Remove方法(初始化实例变量,获得或关掉外部资源等)
6)多用户并发访问:
a.容器考虑,开发人员无需处理并发
b.钝化和激活过程
c.容器的并发策略(annotaion和DD)
需导包:jboss-annotation-ejb3.jar (这个包在 %jboss_home%/client/ 下)
d.Bean编写的要求,必须具备序列化能力(serializable)
7)占用更多资源:cpu(查找bean、激活、钝化)和内存(有多少个在线用户就有多少stateful bean)
有状态会话Bean:
1.一个Stub就是一个客户,lookup到Stub以后,保存在servlet的session中
2.EJB重新部署之后,需要lookup一个新的Stub
生命周期:不存在 -> 就绪 -> 钝化
1.当客户端lookup时,Bean并不存在;直到客户端首次请求调用时,服务器才构造bean实例,并调用postConstruct方法进入就绪状态;然后客户端才可以正常调用
2.如果客户端太久不用,服务器会调用prePassivate方法使bean钝化;当客户端再次请求调用时,又构造新实例,调用postActivate重新激活;然后客户端才正常调用
3.客户端调用remove后,服务器端会调用preDestroy方法令bean不存在;此后不能再使用这个bean,如需再用要再次lookup
11. 示例:购物篮
购物篮EJB组件
包含状态:产品信息(产品,数量)
业务功能:1添加产品 2生成订单
数据源 模板的位置: %jboss_home%/docs/examples/jca/
数据源配置文件位置: %jboss_home%/server/default/deploy/mysql-ds.xml
mysql驱动程序位置: %jboss_home%/server/default/lib/
issue:
无法访问数据库时,注意:
1. 检查数据库驱动程序
2. 检查mysql-ds.xml是否正确(url,username,password);放到 %jboss_home%/server/default/deploy/
3. 检查数据源是否部署成功,JNDI引用名称是否正确( 以 "java:/" 开始)
-----------------------------------------------------------
Day3
1. JPA(Java Persistence API)简介
1)ORM(object relational mapping): 实现对象到关系数据库中的表的自动持久化(翻译)
通过元数据描述对象于数据库间的映射。
2)JPA, Sun提出的又一套Java持久化规范标准
3)整合当前各种ORM框架和技术,为各种ORM框架提供统一编程接口
4)只是一套接口,要求持久化提供商实现支持
5)使用Annotation和XML描述对象和关系表的关系
6)EJB和普通Java程序都可使用
2. JPA编程
EntityManager接口
J2SE环境下JPA 编程步骤:
a.导入包: Java EE 5 Libraries(MyEclipse的类库,javaee.jar);
数据库驱动包; PP(持久化提供者)的包
b.配置persistence.xml(名字固定)
提供访问数据库的信息 和指定具体的PP(persistence provider)
c.开发实体(注解或orm.xml)
1)在POJO类上添加@Entity
2)实体必须声明主键@Id,(可以使用@GeneratedValue配置主键产生的策略)
3)默认情况下,实体类名和属性名等同于表的字段名(可用@Table/@Column 加上(name="new_name")另外起名)
//4)实体能够包括业务方法(不建议这么做,会导致实体的职责不清)
d.Session Bean(注入EntityManager)
e.开发客户程序
3. JPA支持两种事务类型
本地资源事务(RESOURCE_LOCAL):使用JDBC驱动管理的本地事务。不需发布。
Java事务API(JTA):容器管理的事务。要使用JTA必须使用服务器的DataSource。
JavaEE环境下
容器管理的EntityManager(@PersistenceContext注入)必须使用JTA事务。
应用程序管理的EntityManager可以使用本地资源事务,也可以使用JTA事务
在JavaSE环境下,使用本地资源事务
比较 Hibernate 与 JPA 的开发过程:
Hibernate jpa
1.POJO(entity) 1.entity
2.xxx.hbm.xml 2.Annotation(orm.xml)
3.hibernate.cfg.xml 3.persistence.xml
4.SessionFactory 4.EntityManagerFactory
-----------------------------------------------------------
Day4
4. EntityManager接口
find(Class<T> entityClass, Object primaryKey):<T> T //根据主键查找,没有符合条件记录,返回null
Hibernate:get();
getReference(Class<T> entityClass,Object primaryKey):<T>T //根据主键查找,没有符合条件记录,抛出异常
Hibernate:load(); //EntityNotFoundException
persist(Object entity):void //将实体变成受管态,并持久化它,将在数据库中增加一条记录
Hibernate:save();
merge(T entity):T //合并一个实体到持久化上下文中,将更新数据库记录,并返回持久化对象
Hibernate:merge();
remove(Object entity):void //删除一个实体,将删除数据库记录
clear():void //清除持久化上下文,将导致托管态对象变成游离态对象
contains(Object entity):boolean //检查一个实体对象是否包在持久化上下文中
close(); //关闭持久化上下文
flush(); //对象同步到数据库,有两种同步方式
FlushModeType.AUTO //事务提交和执行查询时同步
FlushModeType.COMMIT; //只有事务提交时同步
setFlushMode(FlushModeType flushMode) //设置同步方式
refresh(); //数据库同步到对象
getTransaction().begin(); //开启事务
getTransaction().commit(); //提交事务,事务结束
5. 持久化上下文和实体的生命周期
新建 -> 托管(受管) -> 脱管(游离) -> 删除
1) 新建new:new Instance persist(); 新建一个实体对象,还未持久化,没有持久化标志
2) 托管managed:数据库里和持久化上下文中都有 实体对象
3) 游离detached:持久化上下文中没有,但是又具有持久化标志(oid) 可调用merge(),不能调用persist();
4) 删除removed:hibernate没有(数据库中和持久化上下文中都有,但是通过remove()标志实体是被删除的)
总结:
1) 不调用persist, 而是调用merge持久保存entity对象
2) 在事务当中(ejb默认一个方法是一个事务)或者持久化上下文中,先查询entity, 再进行操作
3) 调用find方法, 不要调用getReference()
6. 持久化上下文类型
容器管理的上下文
@PersistenceContext(type=PersistenceContextType.TRANSACTION)
1)事务范围的(默认方式):
事务结束时(一个方法默认为一个事务),上下文被关闭
@PersistenceContext(type=PersistenceContextType.EXTENDED)
2)扩展范围的(多个事务):
上下文跨越多个事务(事务结束时,上下文并不关闭)
*只有*有状态会话Bean适用,SFSB销毁时,上下文关闭
应用程序管理的上下文,是扩展的上下文
EntityManagerFactory emf;
EntityManager em = emf.createEntityManager();
7. 实体回调
1)注解方法
@PrePersist //insert into SQL执行之前调用
@PostPersist //insert into SQL执行之后调用
@PreUpdate //update SQL执行之前调用
@PostUpdate //update SQL执行之后调用
@PreRemove //delete SQL执行之前调用
@PostRemove //delete SQL执行之后调用
@PostLoad //加载实体之后,select SQL执行之后调用 (只有这个没有之前执行的)
2)独立的回调类
@EntityListeners(Callback.class)
回调方法多一个Object 参数,如:
Callback.java 里写: entity.java里写:
@PreUpdate @PreUpdate
public void preUpdate (Object obj); public void preUpdate ();
8. JPA查询(JPQL)
1)javax.persistence.Query接口
Query query = em.createQuery("select 别名 from entity类 别名"); //也可写 "from entity类"
List<entity类> list = query.getResultList();
for(entity类 obj : list){System.out.println(obj.getOid() + " : " + obj.getName());}
2)本地查询
Query query = em.createNativeQuery("select * from 表名", entity类.class);
List<entity类> list = query.getResultList();
for(entity类 obj :list){System.out.println(obj.getOid() + " : " + obj.getName());}
3)命名查询
a)在Entity里添加标注
@NamedQuery(name="命名1", query="select h from entity类 h where h.age>?2 and h.name like ?1")
//上面 ?1 ?2 的数字决定参数下标。也可以只用 ? ,但代码得保证对应这语句的顺序。(h是 entity类 的别名)
//query 语句也可写成:"from entity类 where age>:age and name like :name"
//分号表示用名称代号代替之前的下标,来表示参数。这种方式更常用,不易出错
b)查询代码
Query query = em.createNamedQuery("命名1");
query.setParameter(1, "%始%"); //如果query 语句用分号的,则query.setParameter("name", str);
query.setParameter(2, 70);
List<entity类> list = (List) query.getResultList();
for (entity类 obj : list){
System.out.println(obj.getOid() + " : " + obj.getName());}
4)本地命名查询
a)在Entity里添加标注
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -