2016-06-15 6 views
1

を休止:コンテナが管理している私たちが望むすべての場合においてマルチテナンシー、我々は4.3マルチテナント、hikaricp接続プロバイダ休止状態を使用している4.3、Wildfly 9、Hikaricpの自動コミットEJB3 JTAコンテナ管理によるトランザクションを持つ偽モードとDAO

<property name="hibernate.multiTenancy" value="DATABASE"/> 
    <property name="hibernate.multi_tenant_connection_provider" value="multitenancy.HikariTenantConnectionProvider"/> 
    <property name="hibernate.tenant_identifier_resolver" value="multitenancy.ThreadLocalIdentifierResolver"/> 

を私たちのトランザクションは、java ee ejb standardを使用しています。

問題:

自動コミット

オートモードでのコミット処理次は起こる私たちは、DAOパターンvoucherServiceで次のコードしていることを言うことができます:

@TransactionAttribute(TransactionAttributeType.MANDATORY) 
private Voucher save(Voucher entity, Boolean isCreate) throws Exception { 

     voucherPoolService.save(entity); 

     List<VoucherTag> tags = _detachTags(entity); 
     List<VoucherCaption> captions = _detachCaptions(entity); 

     if (isCreate) { 
      voucherDAO.save(entity); 
     } else { 
      voucherDAO.merge(entity); 
     } 

     retailerService.updateTime(entity); 

     _clearCollections(entity); 
     _attachTags(entity, tags); 
     _attachCaptions(entity, captions); 

     voucherDAO.merge(entity); 

     return entity; 
} 

休憩コール:

@POST 
    @Transactional(value = Transactional.TxType.REQUIRES_NEW, rollbackOn = {Exception.class}) 
    public Voucher create(Voucher entity) throws Exception { 
    if (getValidator() != null) { 
     getValidator().validateCreate(entity); 
    } 
    return getService().save(entity, true); // create 
    } 

自動コミットモードでの処理方法:

CONTAINER - > JTAトランザクション - > JDBC

START TRANSACTION; 
INSERT INTO voucher_pool ... 
COMMIT; 

START TRANSACTION; 
INSERT INTO voucher ... 
COMMIT; 

START TRANSACTION; 
INSERT INTO retailer ... 
COMMIT; 

START TRANSACTION; 
INSERT INTO voucher_tags ... 
COMMIT; 


START TRANSACTION; 
INSERT INTO voucher_tags ... 
COMMIT; 

は問題:

エンティティサービスの一つがライン上に例えばSQL例外をスローする場合:

retailerService.updateTime(entity); 

JTAトランザクションAPIだろうか?ロールバックすると、ロールバックする方法はありません。

START TRANSACTION; 
INSERT INTO voucher_pool ... 
COMMIT; 

START TRANSACTION; 
INSERT INTO voucher ... 
COMMIT; 

あなたは既に別のJDBCトランザクションとしてデータベースにコミットされているためです。 これをうまく処理するにはどうすればよいですか?

答えて

1

解決方法? Autocomit偽

<property name="hibernate.connection.autocommit" value="false"/> 

明示的に例のDAOマニュアルが実装コミットコミットするときに、各実装に言っていることで一つの大きな問題があります:それの

public void commit() throws Exception { 
    Session session = getEntityManager().unwrap(Session.class); 
    Transaction tx = session.getTransaction(); 
    if (tx.isActive()) { 
     session.doWork(new Work() { 
      @Override 
      public void execute(Connection connection) throws SQLException { 
       connection.commit(); 
      } 
     }); 
    } 
} 

使用法:

@TransactionAttribute(TransactionAttributeType.MANDATORY) 
private Voucher save(Voucher entity, Boolean isCreate) throws Exception { 

     voucherPoolService.save(entity); 

     List<VoucherTag> tags = _detachTags(entity); 
     List<VoucherCaption> captions = _detachCaptions(entity); 

     if (isCreate) { 
      voucherDAO.save(entity); 
     } else { 
      voucherDAO.merge(entity); 
     } 

     retailerService.updateTime(entity); 

     _clearCollections(entity); 
     _attachTags(entity, tags); 
     _attachCaptions(entity, captions); 

     voucherDAO.merge(entity); 
     // you have to explicitly say when to commit 
     getDao().commit(); 

     return entity; 
} 
は、

あなたはなぜ私はジェネリックDAOの実装に入れていないあなた自身を尋ねるでしょうか? しかし、あなたはオートコミットモードと同じ状況になり、あなたはそれを忘れないでください。

幸いにも私は明示的に定義せずにいることを処理するインターセプタ冬眠使用して素敵なソリューションを持っている:ここでは

getDao().commit(); 

はあなたの永続性の永続性単位の例です。XML:

<persistence-unit name="webservices" transaction-type="JTA"> 
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> 
<class>Your entitys here</class> 
<class>Your entitys here</class> 
<properties> 
    <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/> 
    <property name="hibernate.use_outer_join" value="true"/> 
    <property name="hibernate.connection.provider_class" 
       value="com.zaxxer.hikari.hibernate.HikariConnectionProvider"/> 
    <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/> 
    <property name="hibernate.connection.autoReconnect" value="true"/> 
    <property name="hibernate.connection.autocommit" value="false"/> 
    <property name="hibernate.connection.release_mode" value="after_transaction"/> 

    <property name="hibernate.ejb.use_class_enhancer" value="true"/> 
    <property name="hibernate.ejb.interceptor" 
       value="webservices.dao.transaction.TransactionInterceptor"/> 

    <property name="hibernate.multiTenancy" value="DATABASE"/> 
    <property name="hibernate.multi_tenant_connection_provider" 
       value="webservices.multitenancy.HikariTenantConnectionProvider"/> 
    <property name="hibernate.tenant_identifier_resolver" 
       value="webservices.multitenancy.ThreadLocalIdentifierResolver"/> 

    <property name="hibernate.current_session_context_class" value="thread"/> 

    <property name="hibernate.transaction.jta.platform" 
       value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform"/> 
    <property name="hibernate.transaction.auto_close_session" value="true"/> 

    <property name="hibernate.hikari.maximumPoolSize" value="30"/> 
    <property name="hibernate.hikari.connectionTestQuery" value="SELECT 1"/> 
    <property name="hibernate.hikari.leakDetectionThreshold" value="10000"/> 
    <property name="jboss.entity.manager.factory.jndi.name" value="webservicesEMF"/> 
    <property name="jboss.entity.manager.jndi.name" value="webservicesEM"/> 
    <property name="hibernate.hikari.idleTimeout" value="300000"/> 
    <property name="hibernate.hikari.transactionIsolation" value="TRANSACTION_SERIALIZABLE"/> 

</properties> 

ジェネリックDAOパーツ:

@Stateless 
public class GenericDAO<E, ID extends Serializable> extends GenericDAOImpl<E, ID> { 

    private Class<E> entityClass; 
    private Class<ID> idClass; 

    protected static Logger log = LogManager.getLogger(GenericDAO.class); 

    @PersistenceContext(name = "webservices") 
    protected EntityManager em; 

    private static final JPASearchProcessor searchProcessor = new JPASearchProcessor(new JPAAnnotationMetadataUtil()); 

    public GenericDAO() { 
    super(); 
    entityClass = (Class<E>) DAOUtil.getTypeArguments(GenericDAOImpl.class, this.getClass()).get(0); 
    init(); 
    } 

    @PostConstruct 
    protected void initialize() { 
    setEntityManager(em); 
    setSearchProcessor(searchProcessor); 
    }  

DAORegistryパーツ:

@Stateless 
public class DAORegistry { 

    public static EntityManager getEntityManager() { 
    EntityManager em = null; 
    try { 
     InitialContext ic = new InitialContext(); 
     em = (EntityManager) ic.lookup("webservicesEM"); 
    } catch (NamingException e) { 
     e.printStackTrace(); 
    } 
    return em; 
    } 

と魔法のトリック:

インターセプタを適用します。

<property name="hibernate.ejb.interceptor" value="webservices.dao.transaction.TransactionInterceptor"/> 

そして、あなたのインターセプタの実装:

public class TransactionInterceptor extends EmptyInterceptor { 

@Override 
public void beforeTransactionCompletion(Transaction noTx) { 
    DAORegistry.getEntityManager().unwrap(Session.class); 
    Transaction tx = session.getTransaction(); 
    if (tx.isActive() && !tx.wasRolledBack() && !tx.wasCommitted()){ 
      session.doWork(Connection::commit); 
    } 

} 

今、あなたは任意のより多くのマニュアルは、実装をコミットする必要はありません:素敵なJTA CMTの実装に期待通り

getDao().commit(); 

は、あなたのDAOコードはどこでも動作します。以下のコードは、魔法のように動作します:私は私に、このような素敵な実装を提供しますし、私はそのように私は私の教訓を共有したい見つけることができなかったいくつかの例を探していた一週間後、より多くの場合

@TransactionAttribute(TransactionAttributeType.MANDATORY) 
private Voucher save(Voucher entity, Boolean isCreate) throws Exception { 

    voucherPoolService.save(entity); 

    List<VoucherTag> tags = _detachTags(entity); 
    List<VoucherCaption> captions = _detachCaptions(entity); 

    if (isCreate) { 
     voucherDAO.save(entity); 
    } else { 
     voucherDAO.merge(entity); 
    } 

    retailerService.updateTime(entity); 

    _clearCollections(entity); 
    _attachTags(entity, tags); 
    _attachCaptions(entity, captions); 

    voucherDAO.merge(entity); 

    return entity; 
} 

を。あなたはそれが動作するはず予想通り

今、あなたは

は、以下のご意見や学んだ私を残し、あなたのEJB3標準を使用することができます。 :)

関連する問題