Java EJB事务未回滚

Java EJB事务未回滚,java,transactions,ejb,Java,Transactions,Ejb,我已经完成了上述EJB: @Stateless public class ItilEJB { @PersistenceContext protected EntityManager em; public <T> T find(Class<T> clazz, Long id) { if (clazz == null || id == null) { return null; }

我已经完成了上述EJB:

    @Stateless
public class ItilEJB  {
    @PersistenceContext
    protected EntityManager em;

    public <T> T find(Class<T> clazz, Long id) {
        if (clazz == null || id == null) {
            return null;
        }

        return em.find(clazz, id);
    }


public Chamado atender(Long chamadoId) {

        Chamado chamado = find(Chamado.class, chamadoId);

        if (!isChamadoAtendido(chamadoId)) {
            Status emAndamento = new Status(Status.EM_ANDAMENTO);

            HistoricoChamado historico = new HistoricoChamado();
            historico.setDescricao("Início do atendimento do chamado.");
            historico.setChamado(chamado);
            historico.setStatus(emAndamento);
            historico.setSla(chamado.getSla());

            chamado.setStatus(emAndamento);

            save(historico);

            save(chamado);
        }

        return chamado;
    }

public void save(BaseEntity entity) {

        if (entity.getId() == null) {
            if (!helper.canInsert(this, entity)) {
                throw new AlertMessageRuntimeException("user.db.constraint");
            }
            em.persist(entity);
        } else {
            if (!helper.canUpdate(this, entity)) {
                throw new AlertMessageRuntimeException("user.db.constraint");
            }
            em.merge(entity);
        }
    }

}
@无状态
公共类ItilEJB{
@持久上下文
受保护的实体管理器em;
公共找不到(类clazz,长id){
if(clazz==null | | id==null){
返回null;
}
返回em.find(clazz,id);
}
公共Chamado atender(长chamadoId){
Chamado Chamado=find(Chamado.class,chamadoId);
如果(!isChamadoAtendido(chamadoId)){
状态emAndamento=新状态(Status.EM_ANDAMENTO);
HistoricoChamado historico=新的HistoricoChamado();
historico.Setdescripao(“Início do atendemento do chamado.”);
塞查马多历史博物馆(查马多);
塞斯塔图斯历史公司(伊曼达曼托);
historico.setSla(chamado.getSla());
查马多·塞斯塔图斯(伊曼达曼托);
拯救(历史公司);
拯救(查马多);
}
返回查马多;
}
公共作废保存(基本实体){
if(entity.getId()==null){
如果(!helper.canInsert(此,实体)){
抛出新的AlertMessageRuntimeException(“user.db.constraint”);
}
em.persist(实体);
}否则{
如果(!helper.canUpdate(此,实体)){
抛出新的AlertMessageRuntimeException(“user.db.constraint”);
}
合并(实体);
}
}
}
如果我第二次保存,保存(chamado);抛出一个异常(无论运行时与否)第一次保存未回滚,我不明白为什么。 对我来说,每个EJB调用都将封装在一个事务中,如果发生异常,与DB层的整个交互都将回滚

我怎样才能完成这个行为?如果第二次保存引发错误,我希望回滚第一次保存操作

谢谢


我使用MySQL作为DBMS,使用Wildfly 8.1作为应用服务器。 我没有更改任何默认设置,因此我认为自动提交模式不是启用的

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
    xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="primary">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>java:jboss/datasources/MySQLDS</jta-data-source>

        <properties>
            <property name="hibernate.show_sql" value="true" />
        </properties>
    </persistence-unit>
</persistence>

org.hibernate.ejb.HibernatePersistence
java:jboss/datasources/MySQLDS
这是我在standalone.xml中的数据源配置

<datasource jndi-name="java:jboss/datasources/MySQLDS" enabled="${mysql.enabled}" use-java-context="true" pool-name="MySQLDS" use-ccm="true">
                    <connection-url>jdbc:mysql://${env.OPENSHIFT_MYSQL_DB_HOST}:${env.OPENSHIFT_MYSQL_DB_PORT}/${env.OPENSHIFT_APP_NAME}</connection-url>
                    <driver>mysql</driver>
                    <security>
                      <user-name>${env.OPENSHIFT_MYSQL_DB_USERNAME}</user-name>
                      <password>${env.OPENSHIFT_MYSQL_DB_PASSWORD}</password>
                    </security>
                    <validation>
                        <check-valid-connection-sql>SELECT 1</check-valid-connection-sql>
                        <background-validation>true</background-validation>
                        <background-validation-millis>60000</background-validation-millis>
                        <!--<validate-on-match>true</validate-on-match>-->
                    </validation>
                    <pool>
                        <flush-strategy>IdleConnections</flush-strategy>
                    </pool>
                </datasource>

jdbc:mysql://${env.OPENSHIFT\u mysql\u DB\u HOST}:${env.OPENSHIFT\u mysql\u DB\u PORT}/${env.OPENSHIFT\u APP\u NAME}
mysql
${env.OPENSHIFT\u MYSQL\u DB\u USERNAME}
${env.OPENSHIFT\u MYSQL\u DB\u PASSWORD}
选择1
真的
60000
空闲连接

您没有提到save()方法是如何定义的。如果它使用BMP,则无法从CMP加入事务,例如atender()

如果没有,请尝试以下方法:

在atender(Long chamadoId)上放置注释@TransactionAttribute(TransactionAttributeType.REQUIRED)。在save()方法的定义上,将这个注释放在@TransactionaAttribute(TransactionaAttribute.employment)上


希望您能提供帮助

如果您碰巧正在使用JBoss,则datasoruce很可能错误地定义不使用JTA事务。检查是否有
应该回滚。您使用的是哪种数据库管理系统?持久化单元是如何配置的?它应该失败的唯一原因是如果有某种自动提交模式被激活。你有部署描述符吗?您是否可以在描述符中覆盖save方法的TransactionAttribute?谢谢您的回复!我想我已经,把问题看得有点低了。对不起,我没有注意到滑动条。不过,你可以试试我的第二个建议。我已经读到,如果事务存在,所需的属性类型并不总是转换为加入事务,有时它会创建一个新事务,就好像定义了REQUIRES\u新属性一样。老实说,我不记得我在哪里找到这个,但我有一个类似的问题,你的;但是,尝试使用我上一个回复的第二部分,它应该强制save()方法不启动新事务并加入调用者的事务。还有,tryHi Gas,谢谢!这是真的,我在standalone.xml中添加了数据源的定义,但它没有jta=“true”属性。我现在就试试这个。