2

Lors de la création d'un utilisateur d'application (EntityManager.persist), je dois également créer un utilisateur DB et lui accorder des privilèges (c'est pourquoi j'ai besoin d'hibernate nativeQuery).La requête native executeUpdate semble valider des données dans la transaction Spring

J'ai une méthode @Transactional Spring qui appelle mon DAO avec les deux appels:

@Transactional 
public Integer createCompany(Company company) throws Exception { 
    companyDao.createReportUser(ReportUser user); 
    ... 
} 

Ma méthode DAO ressemble à ceci:

getEm().persist(companyReportsUser); 
getEm().createNativeQuery("CREATE USER [email protected] IDENTIFIED BY :password").setParameter("password", password).executeUpdate(); 
getEm().createNativeQuery("GRANT SELECT ON appdb.v_company TO [email protected]").executeUpdate(); 
//several grants 

Maintenant, dès la première ligne avec executeUpdate() est exécuté Je peux voir companyReportsUser persistant dans la base de données avec utilisateur DB (user1 @ localhost).

Toutes les NativeQueries sont exécutées et immédiatement validées une par une. Comme ils sont validés, ils ne peuvent pas être annulés. Il n'y a pas paramètre de validation automatique défini n'importe où dans ma configuration, donc je suppose qu'il est 'faux' comme trouvé dans les documents Hibernate.

  1. Je l'ai testé le comportement @Transactional sans requêtes natives et il fonctionne comme supposé (transaction est annulée quand je jette un RuntimeException et aucune donnée sont insérées à la base de données)

  2. Lors du débogage I » Nous avons vu que l'opération persistante retarde l'exécution lorsqu'elle est invoquée dans une transaction en cours d'exécution.

  3. requête native semble créer et exécuter un PreparedStatement immédiatement (au moins je ne l'ai pas trouvé une file d'attente d'aucune sorte.

  4. Je suppose que je ne pourrais pas obtenir l'interaction entre mise en veille prolongée requête et opération Spring native , mais j'ai pris le temps de lire les documents Spring et Hibernate concernant les transactions et les requêtes natives et je n'ai rien trouvé qui puisse m'aider

  5. Peut-être qu'il existe une meilleure façon de créer un utilisateur de base de données et d'accorder des privilèges que les requêtes natives (bien que je n'en ai trouvé aucun)

ci-dessous est ma config d'application:

applicationContext.xml

<tx:annotation-driven transaction-manager="txManager" /> 

<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
    <property name="entityManagerFactory"> 
     <ref local="entityManagerFactory" /> 
    </property> 
</bean> 

<bean id="entityManagerFactory" 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="dataSource" ref="dataSource" /> 
    <property name="persistenceUnitName" value="domainPU" /> 
    <property name="loadTimeWeaver"> 
     <bean 
      class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" /> 
    </property> 
    <property name="jpaVendorAdapter"> 
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" /> 
    </property> 
</bean> 

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 
    destroy-method="close"> 
    <property name="driverClassName" value="com.mysql.jdbc.Driver" /> 
    <property name="url" value="${db.url}" /> 
    <property name="username" value="${db.user.name}" /> 
    <property name="password" value="${db.user.password}" /> 
    <property name="validationQuery" value="select 1 as dbcp_connection_test" /> 
    <property name="testOnBorrow" value="true" /> 
</bean> 

persistence.xml

<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_1_0.xsd" version="1.0"> 
<persistence-unit name="domainPU" transaction-type="RESOURCE_LOCAL"> 

    <provider>org.hibernate.ejb.HibernatePersistence</provider> 

    <class>com.domain.Entity1</class> 
    .... 

    <exclude-unlisted-classes>true</exclude-unlisted-classes> 

    <properties> 
     <property name="hibernate.show_sql" value="true" /> 
     <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" /> 
     <property name="hibernate.jdbc.batch_size" value="100"></property> 
     <property name="hibernate.order_inserts" value="true"></property> 
     <property name="hibernate.order_updates" value="true"></property> 

     <property name="hibernate.c3p0.min_size" value="5"></property> 
     <property name="hibernate.c3p0.max_size" value="30"></property> 
     <property name="hibernate.c3p0.timeout" value="300"></property> 
     <property name="hibernate.c3p0.max_statements" value="100"></property> 
     <property name="hibernate.c3p0.idle_test_period" value="${hibernate.c3p0.idle_test_period}"></property> 
    </properties> 
</persistence-unit> 

bibliothèques utilisées:

  • Hibernate 4.1.6.FINAL
  • Spring 3.2.2.RELEASE
  • mysql-connector-java-1.5.21
  • MySQL 5.5

Répondre

2

Après avoir creusé plus profondément dans la façon dont les transactions dans MySQL J'ai trouvé une réponse:

problème était dans les déclarations spécifiques contenues dans la requête SQL native.

De la documentation MySQL:

13.3.3 qui peuvent causer une validation implicite des déclarations

  • données linguistiques définition (DDL) qui définissent ou modifier des objets de base de données (... CREATE TABLE, DROP DATABASE ...)

  • Instructions qui utilisent ou modifient implicitement les tables de la base de données mysql (CREATE USER, DROP US ER et Rename USER ..., GRANT, REVOKE, ...)

  • ...

Plus de détails ici:

http://dev.mysql.com/doc/refman/5.1/en/implicit-commit.html

I avons décidé de scinder cette action en deux parties:

  • déclarations de mise en veille prolongée ordinaires (dans une transaction),
  • états de requête native

et l'utilisateur de l'offre avec un outil/action en relançant la deuxième partie dans le cas où quelque chose va mal.

Une autre solution serait de migrer vers un autre SGBDR prenant en charge les transactions autour des opérations DDL.