Ich verwende Standard-JPA-Transaktionsmanager für meine JPA-Transaktionen. Jetzt möchte ich jedoch einige JDBC-Entitäten hinzufügen, die die gleiche 'Datenquelle' teilen. Wie kann ich die JDBC-Vorgänge mit der Transaktion im Frühling transaktionsfähig machen? Muss ich zu JTA Transaktionsmanagern wechseln? Ist es möglich, beide JPA & JDBC Transaktionsservice mit derselben Datenquelle zu verwenden? Noch besser, ist es möglich, diese beiden Transaktionen zu mischen?Welchen Transaktionsmanager sollte ich für die JBDC-Vorlage verwenden, wenn JPA verwendet wird?
UPDATE: @Espen:
Ich habe ein dao von SimpleJdbcDaoSupport erweitert, die getSimpleJDBCTemplate.update eine Datenbank Zeile einzufügen verwendet. Wenn eine RuntimeException vom Dienstcode ausgelöst wird, wird die Transaktion bei Verwendung von JPATransactionManager nie zurückgesetzt. Bei Verwendung von DatasourceTransactionManager wird ein Rollback ausgeführt. Ich habe versucht, den JPATransactionManager zu debuggen und scheint, dass es Rollback auf zugrundeliegendem JDBCConnection nie durchführt (ich denke, aufgrund der Tatsache, dass die Datenquelle nicht notwendigerweise JDBC für JPA sein muss). Meine Konfigurationseinstellungen sind genau so, wie Sie es hier erklärt haben.
Hier sind meine Testcode:
<context:property-placeholder location="classpath:*.properties"/>
<!-- JPA EntityManagerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceXmlLocation"
value="classpath:/persistence-test.xml" />
<property name="persistenceProvider">
<bean class="org.hibernate.ejb.HibernatePersistence" />
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!--
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
-->
<!-- Database connection pool -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${database.driverClassName}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.username}" />
<property name="password" value="${database.password}" />
<property name="testOnBorrow" value="${database.testOnBorrow}" />
<property name="validationQuery" value="${database.validationQuery}" />
<property name="minIdle" value="${database.minIdle}" />
<property name="maxIdle" value="${database.maxIdle}" />
<property name="maxActive" value="${database.maxActive}" />
</bean>
<!-- Initialize the database -->
<!--<bean id="databaseInitializer" class="com.vantage.userGroupManagement.logic.StoreDatabaseLoader">
<property name="dataSource" ref="storeDataSource"/>
</bean>-->
<!-- ANNOTATION SUPPORT -->
<!-- Enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- JPA annotations bean post processor -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<!-- Exception translation bean post processor (based on Repository annotation) -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<!-- throws exception if a required property has not been set -->
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
<bean id="userService" class="com.rfc.example.service.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
<property name="contactDao" ref="contactDao"></property>
<property name="callRecordingScheduledProgramTriggerDAO" ref="com.rfc.example.dao.CallRecordingScheduledProgramTriggerDAO"></property>
</bean>
<bean id="userDao" class="com.rfc.example.dao.UserDaoJPAImpl" />
<bean id="contactDao" class="com.rfc.example.dao.ContactDaoJPAImpl"></bean>
<bean id="com.rfc.example.dao.CallRecordingScheduledProgramTriggerDAO" class="com.rfc.example.dao.CallRecordingScheduledProgramTriggerDAOJDBCImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
und hier ist die DAO:
@Transactional
public class CallRecordingScheduledProgramTriggerDAOJDBCImpl extends SimpleJdbcDaoSupport implements CallRecordingScheduledProgramTriggerDAO{
private static final Log log = LogFactory.getLog(CallRecordingScheduledProgramTriggerDAOJDBCImpl.class);
@SuppressWarnings("unchecked")
public CallRecordingScheduledProgramTrigger save(
CallRecordingScheduledProgramTrigger entity) {
log.debug("save -> entity: " + entity);
String sql = null;
Map args = new HashMap();
String agentIdsString = getAgentIdsString(entity.getAgentIds());
String insertSQL = "insert into call_recording_scheduled_program_trigger" +
" ( queue_id, queue_id_string, agent_ids_string, caller_names, caller_numbers, trigger_id, note, callcenter_id, creator_id_string, creator_id) " +
" values(:queueId, :queueIdString, :agentIdsString, :callerNames, :callerNumbers, :triggerId, :note, :callcenterId , :creatorIdString, :creatorId )";
args.put("queueId", entity.getQueueId());
args.put("agentIdsString",agentIdsString);
args.put("callerNames", entity.getCallerNames());
args.put("queueIdString", entity.getQueueIdString());
args.put("callerNumbers", entity.getCallerNumbers());
args.put("triggerId", entity.getTriggerId());
args.put("note", entity.getNote());
args.put("callcenterId", entity.getCallcenterId());
args.put("creatorId", entity.getCreatorId());
args.put("creatorIdString", entity.getCreatorIdString());
sql = insertSQL;
getSimpleJdbcTemplate().update(sql, args);
System.out.println("saved: ----------" + entity);
return entity;
}
}
Hier ist der Client-Code, der die dao nennt und wirft Ausnahme (Frühjahr Dienst)
@Transactional(propagation=Propagation.REQUIRED)
public void jdbcTransactionTest() {
System.out.println("entity: ");
CallRecordingScheduledProgramTrigger entity = new CallRecordingScheduledProgramTrigger();
entity.setCallcenterId(10L);
entity.setCreatorId(22L);
entity.setCreatorIdString("sajid");
entity.setNote(System.currentTimeMillis() + "");
entity.setQueueId(22);
entity.setQueueIdString("dddd");
String triggerId = "id: " + System.currentTimeMillis();
entity.setTriggerId(triggerId);
callRecordingScheduledProgramTriggerDAO.save(entity);
System.out.println("entity saved with id: " + triggerId);
throw new RuntimeException();
}
HINWEIS: der Code funktioniert wie erwartet, wenn DatasourceTransactionManager
UPDATE - 2:
Ok Ich habe die Ursache des Problems gefunden. Danke an Espen.
Konfiguration Meine Einheit Manager war wie folgt (von Frühling Haustier-Klinik App kopiert):
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceXmlLocation"
value="classpath:/persistence-test.xml" />
<property name="persistenceProvider">
<bean class="org.hibernate.ejb.HibernatePersistence" />
</property>
</bean>
Dann habe ich es änderte sich dies mögen:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation"
value="classpath:/persistence-test.xml" />
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
</bean>
</property>
</bean>
Jetzt ist alles scheint zu funktionieren! Kann jemand den Unterschied zwischen diesen beiden Ansätzen erklären?
Vielleicht http://stackoverflow.com/questions/2650409/implement-custom-jta-xaresource-for-using-with-hibernate/2651580#2651580 Zusammenhang – ewernli
Versuchen Sie, die persistenceXmlLocation Eigenschaft zu entfernen. Es ist eine Alternative zur Eigenschaft dataSource. Die Anforderungen, damit der JpaTransactionManager sowohl mit JPA- als auch JDBC-Abfragen arbeiten kann, ist, dass Ihr entityManager die gleiche dataSource wie Ihre JDBC-Abfragen verwendet und Sie den JPA-Dialekt wie bereits beschrieben angeben. – Espen