Tôi đang sử dụng trình quản lý giao dịch JPA tiêu chuẩn cho các giao dịch JPA của mình. Tuy nhiên, bây giờ tôi muốn thêm một số thực thể JDBC sẽ chia sẻ cùng một 'nguồn dữ liệu'. Làm thế nào tôi có thể thực hiện các hoạt động giao dịch JDBC với giao dịch mùa xuân? Tôi có cần chuyển sang người quản lý giao dịch JTA không? Có thể sử dụng cả dịch vụ giao dịch JDBC JPA & JDBC với cùng một nguồn dữ liệu không? Thậm chí tốt hơn, có thể trộn hai giao dịch này không?Tôi nên sử dụng trình quản lý giao dịch nào cho mẫu JBDC Khi sử dụng JPA?
UPDATE: @Espen:
Tôi có một dao kéo dài từ SimpleJdbcDaoSupport trong đó sử dụng getSimpleJDBCTemplate.update để chèn một hàng cơ sở dữ liệu. Khi một RuntimeException được ném từ mã dịch vụ, giao dịch không bao giờ quay trở lại khi sử dụng JPATransactionManager. Nó thực hiện rollback khi sử dụng DatasourceTransactionManager. Tôi đã cố gắng để gỡ lỗi các JPATransactionManager và có vẻ như nó không bao giờ thực hiện rollback trên JDBCConnection cơ bản (tôi đoán do thực tế là các nguồn dữ liệu không nhất thiết phải là JDBC cho JPA). Cài đặt cấu hình của tôi chính xác như bạn đã giải thích ở đây.
Dưới đây là mã thử nghiệm của tôi:
<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>
Và đây là 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;
}
}
Đây là mã khách hàng mà các cuộc gọi dao và ném ngoại lệ (dịch vụ xuân)
@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();
}
Chú ý: mã hoạt động như mong đợi khi sử dụng DatasourceTransactionManager
CẬP NHẬT - 2:
Ok Tôi đã tìm thấy nguyên nhân gốc rễ của vấn đề. Cảm ơn Espen.
cấu hình quản lý thực thể của tôi là như thế này (sao chép từ mùa xuân ứng dụng thú cưng-phòng khám):
<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>
Sau đó, tôi đã thay đổi nó như thế này:
<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>
Bây giờ tất cả mọi thứ dường như được làm việc! Bất cứ ai có thể giải thích sự khác biệt giữa hai cách tiếp cận này?
lẽ liên quan http://stackoverflow.com/questions/2650409/implement-custom-jta-xaresource-for-using-with-hibernate/2651580#2651580 – ewernli
Hãy cố gắng loại bỏ các tài sản persistenceXmlLocation. Đó là một thay thế cho thuộc tính dataSource. Các yêu cầu cho JpaTransactionManager hoạt động với cả hai truy vấn JPA và JDBC là thực thể của bạnManager sử dụng cùng một nguồn dữ liệu như các truy vấn JDBC và bạn chỉ định phương ngữ JPA như bạn đã làm. – Espen