休眠 + EJB 中的容器管理事务 (CMT)
Container managed transcation (CMT) in hibernate + EJB
With CMT, transaction demarcation is declared in session bean deployment descriptors, rather than performed in a programmatic manner.
但我找不到有关如何执行此操作的任何完整示例。
这就是我的想法,我的代码应该如下所示:
@Stateless
public class Dao{
@Inject // or some other annotation
private SessionFactory factory;
public void doDaoStuff(){
Object obj = factory.getCurrentSession().get(Entity.class, "Id");
// do something with obj
return;
}
}
它没有 hibernate 的所有样板,因为事务应该由容器启动、提交和回滚。
那么,这有可能吗?虽然文档说需要的声明应该在 bean 部署描述符 中指定,但是用注释来做会很棒。
默认情况下,EJB 方法是事务性的。
您可以使用 TransactionAttribute 注释调整它们的行为。
您可以在此处阅读有关 CMT 的更多信息:
https://docs.oracle.com/javaee/7/tutorial/transactions003.htm#BNCIJ
https://docs.oracle.com/javaee/7/tutorial/transactions.htm#BNCIH
你的典型例子就像--
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
@TransactionManagement(TransactionManagementType.CONTAINER)
@Stateless(..)
public class YourBean{
@TransactionAttribute(TransactionAttributeType.REQUIRED) // if in case you wanted to use 'existing' transaction
public void DoStuff(){
}
}
并且在您的服务器配置中,您需要在 <enterprise-beans>
下添加以下标记
<transaction-type>Container</transaction-type>
在 JavaEE 环境中,Hibernate 可以使用 CMT(容器管理事务)策略,该策略将 hibernate 事务与底层 JTA 事务绑定,从而无需手动开始、提交和回滚事务。示例 here.
但是,有问题:
这不适用于所有 Java EE 容器。不支持较新版本的 Websphere 并引用 source code of hibernate - WebSphere,但是,它不是一个正常的 JEE/JTA 容器...
这限制为一会话一交易成语。这样在调用一个EJB业务方法时,只能有一个JTA或Hibernate事务。
幸运的是,使用 CDI, and some custom interceptors this can be solved and a lot of Hibernate boilerplate can be removed. I wrote a sample on github。
此方法为 Hibernate SessionFactory and provides most commonly used APIs. Using CDI, @RequestScoped
创建一个包装器,会话会自动打开和关闭。使用拦截器管理事务。 @RequestScoped
确保每个请求一个 Session
,因此会话不会在多个请求之间共享。
import javax.annotation.PreDestroy;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StatelessSession;
@RequestScoped
public class MySessionFactory implements SessionFactoryTemplate{
@Inject
private SessionFactory sessionFactory;// Inject after creating the singleton instance
private Session currentSession;
public Session openSession(){
return sessionFactory.openSession();
}
public Session getCurrentSession(){
if(currentSession == null){
currentSession = sessionFactory.openSession();
}
return currentSession;
}
public StatelessSession openStatelessSession() {
return sessionFactory.openStatelessSession();
}
@PreDestroy
private void closeSession(){
if(currentSession!=null && currentSession.isOpen()) {
currentSession.close();
}
}
}
然后将此实现注入数据库层并用于获取会话。
import org.ares.cdi.hibernate.sf.MySessionFactory;
import org.ares.cdi.hibernate.interceptors.Transactional;
public class Dao {
@Inject
private MySessionFactory sf;
public void get(int id){
sf.getCurrentSession().get(clazz,id);
}
@Transactional
public void add(Object entity){
sf.getCurrentSesion().add(entity);
}
}
事务由 TranscationManager
拦截器管理并由 @Transactional
注释声明。
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import org.ares.cdi.hibernate.sf.MySessionFactory;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.resource.transaction.spi.TransactionStatus;
@Interceptor
@Transactional
public class TransactionManager {
@Inject
private MySessionFactory sessionFactory;
@AroundInvoke
public Object handleTransaction(InvocationContext context) throws Exception{
Session session = sessionFactory.getCurrentSession();
Transaction tx = null;
try{
tx = session.beginTransaction();
return context.proceed();
}
catch(Exception e){
tx.rollback();
throw e;
}
finally{
if(tx.getStatus().equals(TransactionStatus.ACTIVE)){
try{
tx.commit();
}
catch(Exception e){
tx.rollback();
throw e;
}
}
}
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.interceptor.InterceptorBinding;
@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Transactional {
}
With CMT, transaction demarcation is declared in session bean deployment descriptors, rather than performed in a programmatic manner.
但我找不到有关如何执行此操作的任何完整示例。
这就是我的想法,我的代码应该如下所示:
@Stateless
public class Dao{
@Inject // or some other annotation
private SessionFactory factory;
public void doDaoStuff(){
Object obj = factory.getCurrentSession().get(Entity.class, "Id");
// do something with obj
return;
}
}
它没有 hibernate 的所有样板,因为事务应该由容器启动、提交和回滚。
那么,这有可能吗?虽然文档说需要的声明应该在 bean 部署描述符 中指定,但是用注释来做会很棒。
默认情况下,EJB 方法是事务性的。
您可以使用 TransactionAttribute 注释调整它们的行为。
您可以在此处阅读有关 CMT 的更多信息:
https://docs.oracle.com/javaee/7/tutorial/transactions003.htm#BNCIJ
https://docs.oracle.com/javaee/7/tutorial/transactions.htm#BNCIH
你的典型例子就像--
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
@TransactionManagement(TransactionManagementType.CONTAINER)
@Stateless(..)
public class YourBean{
@TransactionAttribute(TransactionAttributeType.REQUIRED) // if in case you wanted to use 'existing' transaction
public void DoStuff(){
}
}
并且在您的服务器配置中,您需要在 <enterprise-beans>
<transaction-type>Container</transaction-type>
在 JavaEE 环境中,Hibernate 可以使用 CMT(容器管理事务)策略,该策略将 hibernate 事务与底层 JTA 事务绑定,从而无需手动开始、提交和回滚事务。示例 here.
但是,有问题:
这不适用于所有 Java EE 容器。不支持较新版本的 Websphere 并引用 source code of hibernate - WebSphere,但是,它不是一个正常的 JEE/JTA 容器...
这限制为一会话一交易成语。这样在调用一个EJB业务方法时,只能有一个JTA或Hibernate事务。
幸运的是,使用 CDI, and some custom interceptors this can be solved and a lot of Hibernate boilerplate can be removed. I wrote a sample on github。
此方法为 Hibernate SessionFactory and provides most commonly used APIs. Using CDI, @RequestScoped
创建一个包装器,会话会自动打开和关闭。使用拦截器管理事务。 @RequestScoped
确保每个请求一个 Session
,因此会话不会在多个请求之间共享。
import javax.annotation.PreDestroy;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StatelessSession;
@RequestScoped
public class MySessionFactory implements SessionFactoryTemplate{
@Inject
private SessionFactory sessionFactory;// Inject after creating the singleton instance
private Session currentSession;
public Session openSession(){
return sessionFactory.openSession();
}
public Session getCurrentSession(){
if(currentSession == null){
currentSession = sessionFactory.openSession();
}
return currentSession;
}
public StatelessSession openStatelessSession() {
return sessionFactory.openStatelessSession();
}
@PreDestroy
private void closeSession(){
if(currentSession!=null && currentSession.isOpen()) {
currentSession.close();
}
}
}
然后将此实现注入数据库层并用于获取会话。
import org.ares.cdi.hibernate.sf.MySessionFactory;
import org.ares.cdi.hibernate.interceptors.Transactional;
public class Dao {
@Inject
private MySessionFactory sf;
public void get(int id){
sf.getCurrentSession().get(clazz,id);
}
@Transactional
public void add(Object entity){
sf.getCurrentSesion().add(entity);
}
}
事务由 TranscationManager
拦截器管理并由 @Transactional
注释声明。
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import org.ares.cdi.hibernate.sf.MySessionFactory;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.resource.transaction.spi.TransactionStatus;
@Interceptor
@Transactional
public class TransactionManager {
@Inject
private MySessionFactory sessionFactory;
@AroundInvoke
public Object handleTransaction(InvocationContext context) throws Exception{
Session session = sessionFactory.getCurrentSession();
Transaction tx = null;
try{
tx = session.beginTransaction();
return context.proceed();
}
catch(Exception e){
tx.rollback();
throw e;
}
finally{
if(tx.getStatus().equals(TransactionStatus.ACTIVE)){
try{
tx.commit();
}
catch(Exception e){
tx.rollback();
throw e;
}
}
}
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.interceptor.InterceptorBinding;
@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Transactional {
}