使用 JPA 时,我应该为 JBDC 模板使用什么事务管理器?

2024-06-25

我正在使用标准 JPA 事务管理器来处理 JPA 事务。但是,现在我想添加一些共享相同“数据源”的 JDBC 实体。如何使用 spring 事务使 JDBC 操作具有事务性?我需要切换到 JTA 事务管理器吗?是否可以将 JPA 和 JDBC 事务服务与同一数据源一起使用?更好的是,是否可以混合这两种交易?

更新: @埃斯彭:

我有一个从 SimpleJdbcDaoSupport 扩展的 dao,它使用 getSimpleJDBCTemplate.update 插入数据库行。当服务代码抛出 RuntimeException 时,使用 JPATransactionManager 时事务永远不会回滚。使用 DatasourceTransactionManager 时它会回滚。我尝试调试 JPATransactionManager ,似乎它永远不会对底层 JDBCConnection 执行回滚(我猜是因为数据源不一定必须是 JPA 的 JDBC)。我的配置设置与您在这里解释的完全一样。

这是我的测试代码:

<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>

这是道:

@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;
}

}

这是调用dao并抛出异常的客户端代码(spring服务)

@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();
}

注意:使用 DatasourceTransactionManager 时代码按预期工作

更新 - 2:

好的,我已经找到问题的根本原因了。感谢埃斯彭。

我的实体管理器配置是这样的(从 spring pet-clinic 应用程序复制):

    <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="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>

现在一切似乎都正常了!谁能解释这两种方法之间的区别?


可以使用以下方法在同一事务中混合 JPA 和 JDBC 代码JpaTransactionManager.

Spring 3 的一个片段JavaDoc http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/orm/jpa/JpaTransactionManager.html:

该事务管理器还支持 直接访问数据源 事务(即纯 JDBC 代码 使用相同的数据源)。 这允许混合服务 访问 JPA 和使用的服务 普通 JDBC(不知道 日本PA)!

您应该知道,JPA 会缓存查询并在事务结束时执行所有查询。因此,如果您想使用 JPA 在事务中保留一些数据,然后使用 JDBC 检索数据,那么在您尝试使用 JDBC 代码检索数据之前,如果不显式刷新 JPA 的持久性上下文,它将无法工作。

使用 JDBC 代码断言 JPA 代码删除了事务内的一行的代码示例:

@Test
@Transactional
@Rollback(false)
public void testDeleteCoffeeType() {

    CoffeeType coffeeType = coffeeTypeDao.findCoffeeType(4L);
    final String caffeForte = coffeeType.getName();

    coffeeTypeDao.deleteCoffeeType(coffeeType);
    entityManager.flush();

    int rowsFoundWithCaffeForte = jdbcTemplate
        .queryForInt("SELECT COUNT(*) FROM COFFEE_TYPES where NAME = ?", 
            caffeForte);
    assertEquals(0, rowsFoundWithCaffeForte);
}

如果您更喜欢使用JpaTemplate类,只需替换entityManager.flush() with jpaTemplate.flush();

回应 Sajids 的评论: 使用 Spring,您可以配置一个同时支持 JPA 和 JDBC 的事务管理器,如下所示:

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

<!-- Transaction manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa
            .JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

和注释驱动版本

@Bean
public JpaTransactionManager transactionManager(EntityManagerFactory emf) {
    JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
    jpaTransactionManager.setEntityManagerFactory(emf);
    return jpaTransactionManager;
}

为了使其工作,必须使用 JdbcTemplate 或 SimpleJdbcTemplate 类执行 JDBC 查询。对于扩展 SimpleJdbcDaoSupport 的 DAO,您应该使用 getSimpleJdbcTemplate(..) 方法。

最后,要让两个 DAO 方法参与同一事务,请从使用 @Transactional 注释的服务类方法调用这两个 DAO 方法。随着<tx:annotation-driven>元素在你的配置中,Spring 将使用给定的事务管理器为你处理事务。

在业务层:

public class ServiceClass {..

@Transactional
public void updateDatabase(..) {
  jpaDao.remove(..);
  jdbcDao.insert(..);
}
}

编辑2: 那么有些事情是错误的。它对我来说完全按照 Javadoc 中的指定工作。 您的实体管理器是否有像下面我的 bean 一样的数据源属性?仅当您将相同的数据源注入实体管理器和扩展的 JpaDaoSupport 类时,它才会起作用。

<bean id="entityManagerFactoryWithExternalDataSoure" primary="true"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor
                .HibernateJpaVendorAdapter" />
    </property>
    <property name="jpaProperties">
        <value>
            hibernate.format_sql=true
        </value>
    </property>
</bean>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 JPA 时,我应该为 JBDC 模板使用什么事务管理器? 的相关文章

  • Spring批处理2.2 JavaConfig

    我正在尝试让 Spring Batch 2 2 与 JavaConfig 一起使用 如今他们有一个 EnableBatchProcessing设置很多东西的注释 默认情况下 该注释使用数据源作为其作业数据 但我们不想保存此数据 也不想为其创
  • HQL - 分页的行标识符

    有谁知道HQL是否有一个关键字来标识行 例如ROWID或ROWNUM 我想使用 HQL 实现分页 但我无法使用 setMaxResult 或 setFirstResult 因为我不直接使用会话对象 因此不使用 Query 对象 而只是将查询
  • 在java中将HTML转换为RTF?

    我需要将 HTML 转换为 RTF 我正在使用以下代码 private static String convertToRTF String htmlStr OutputStream os new ByteArrayOutputStream
  • Java(正则表达式)-获取句子中的所有单词

    我需要将 java 字符串拆分为单词数组 假设该字符串是 Hi I need to split this string into a serie s of words 目前我正在尝试使用这个String strs str split w 但
  • 在运行时后期更改 SessionFactory 数据源 jdbcurl

    我正在为没有网络连接的环境编写一个桌面java应用程序 我试图将应用程序数据尽可能安全地存储在加密的进程内 hsqldb 中 并使用未加密的用户信息 hsqldb Hsqldb 要求在创建连接时在 jdbcurl 中设置 crypto ke
  • 如何从 ByteBuffer 转换为 Integer 和 String?

    我转换了一个int使用 ByteBuffer 的字节数组putInt 方法 我该如何做相反的事情 那么将这些字节转换为 int 吗 此外 我使用 String 的将字符串转换为字节数组getBytes 方法 我如何将其反过来转换 这byte
  • 如何从资源服务器中的 Spring Security OAuth2 Boot 中提取声明?

    我有一个使用 Net Core 内置的授权服务器身份服务器4 https identityserver4 readthedocs io en latest 它正在按预期工作 从 Node Js 和 Net 授权客户端和资源 现在我尝试添加
  • Java写入ByteArrayOutputStream内存泄漏

    我正在将图像字节写入ByteArrayOutputStream然后通过套接字发送它 问题是 当我这样做时 ImageIO write image gif byteArray 内存增加很多 有点内存泄漏 我用这个发送 ImageIO writ
  • 无法在 PHP 中接收 JSON POST 请求

    我正在将 JSON 对象从 Java 传递到 PHP 我正在使用 jdk 1 8 和 WAMPserver 下面是Java代码 import java io IOException import org apache http client
  • 运行 mvn install 时如何指定 spring.profiles.active

    在这个使用 Spring 的 Web 应用程序中 我为不同的部署环境创建了多个应用程序属性文件 他们指定不同的数据库连接配置 application dev properties application qa properties appl
  • Java 多态性中的字段如何工作? [复制]

    这个问题在这里已经有答案了 我正在读书面试问题 http javabypatel blogspot in 2016 04 java interview questions html关于java 发现了很好的例子 但感到困惑 因为没有很好 更
  • StringBuilder - 重置或创建新的

    我有一个条件 StringBuilder 不断存储与大型平面文件 数百 MB 中的模式匹配的行 但是 在达到条件后 我将 StringBuilder 变量的内容写入文本文件 现在我想知道是否应该通过重置对象来使用相同的变量 gt strin
  • Java XPath API - 获取表示子树的字符串

    我的问题不是关于 xpath 语法 而是与 xpath 周围的 java API 有关 考虑以下 xml
  • 控制台中的 Java msg - 两个方法具有相同的方法签名但不提供可分配的类?

    在迁移到 java 1 8 时 我升级了项目中的许多依赖项 它是基于spring 4 3的应用程序 有很多外部依赖 例如 JMS HTTP客户端 FTP XML等 当应用程序启动时 我现在在控制台中收到以下消息 两个方法具有相同的方法签名但
  • 使用 ProGuard 混淆代码后如何保持 javadoc 可见?

    我使用 progured 4 7 混淆了我的代码 并保留了 A 类 其中包含描述该类功能的 javadoc keep public class com mysite ClassA public keepattributes InnerCla
  • SwingWorker 和 Executor 的区别

    我正在使用 SwingWorker 在我正在制作的应用程序上执行一些重负载任务 虽然今天我遇到了 Executor 类和这个例子 Executors newCachedThreadPool execute new Runnable publ
  • JPA2+Hibernate 3.6.0 中的 JTA 还是 LOCAL 事务?

    我们正在重新思考我们的技术堆栈 以下是我们的选择 由于应用程序的复杂性等 我们不能没有 Spring 和 Hibernate 我们还从 J2EE 1 4 迁移到 Java EE 5 技术栈 Java EE 5 JPA 2 0 我知道Java
  • GridLayout 中的 JLabel

    如何添加JLabel出于GridLayout 我有一个 8x8 网格布局 Container content getContentPane content setLayout new GridLayout 8 8 2 2 for int f
  • Tomcat 中 JNDI 的 Java Mail API 配置文档

    我花了几天时间弄清楚如何通过 JNDI 在 Tomcat 中配置 javax mail Session有认证 现在我明白了 但只是在深入研究代码之后 这次我看到了有史以来最糟糕的代码 javax mail Service connect S
  • 从 google play 中提取统计信息

    我正在建立一些统计数据 并希望获得来自 google play 应用程序商店 的统计数据 最受欢迎 下载量 价格等信息 有谁知道是否有这个 API 或者我必须自己抓取它 有一个名为 android market api 的项目http co

随机推荐

  • 循环遍历多维数组

    我正在使用 php 和 dropbox api 开发一个应用程序 并尝试循环遍历多维数组并输出到表中 到目前为止 这是我的代码
  • 在使用 Phoenix 4.5 的 CDH 5.4 上运行 Spark 作业时未找到 PhoenixOutputFormat

    我通过重新编译源代码设法在 Cloudera CDH 5 4 上配置 Phoenix 4 5 sqlline py效果很好 但火花有问题 spark submit class my JobRunner master yarn deploy
  • UICollectionView 和补充视图(标题)

    尝试将补充视图添加到我的UICollectionView作为标题 我在让它工作时遇到问题 我用的是自定义的UICollectionViewFlowLayout返回一个contentSize总是比框架大至少 1 像素 我使用的是UIFresh
  • SAS 显示管理器命令

    SAS 显示管理器是 SAS 系统的命令行界面 它作为遗留设施保留在 Base SAS 中 然而 关于如何使用此功能的在线文档充其量也很少 而且谷歌搜索也没有什么成果 常见的 DM 命令是 CLEAR LOG 清晰的输出 WPGM 我的问题
  • 各种 ISubject 实现的作用是什么以及何时使用它们?

    我非常清楚Subject类的作用以及何时使用它 但我刚刚浏览了msdn上的语言参考 发现还有各种其他ISubject实现 例如 异步主题 行为主体 重播主题 由于文档非常薄弱 因此每种类型的意义是什么 在什么情况下您会使用它们 这些主题都有
  • Structure 中的无参数构造函数

    继从这个问题 https stackoverflow com q 32122660 592111关于在中使用不同的 Visual Basic 版本Visual Studio 2015 http en wikipedia org wiki M
  • 如何在 SignalR 客户端中将 async/await 与 hub.On 一起使用

    我有一个与 SignalR Hub 服务器 通信的 Net Windows 服务 客户端 大多数客户端方法都需要时间才能完成 当收到来自服务器的调用时 我如何 或需要 包装目标方法 hub On以避免警告 由于不等待此调用 因此在调用完成之
  • heroku 上的 Sidekiq - 错误 R14(超出内存配额)

    我有一个在 heroku 上运行的 sidekiq 进程 在运行一段时间后崩溃并显示以下错误消息 错误 R14 超出内存配额 谁能给我任何关于如何开始诊断正在发生的事情的指示 没有任何明显的原因可能导致这种情况 尝试降低并发数 Sideki
  • 类型定义:期望UnionAll,得到TypeVar

    在 v0 6 的 Julia 手册中 我发现以下内容 abstract type Pointy T end struct Point T lt Pointy T x T y T end 这工作得很好 我认为以下也应该 abstract ty
  • 替换VBA中的变量字符串

    我需要替换字符串中的某些内容 但替换的内容可能会有所不同 有可能 XY test XXxY test XXyyXx TEST yXyy Test 以及几乎任何其他空格和上述情况的组合 我需要替换 test 部分并保留 XXX 所以 当使用简
  • jtwitter 的 getPublicTimeline 替代方案

    编辑 从 MANIFEST MF 文件粘贴 Main Class winterwell jtwitter Twitter Implementation Version 2 9 0 Implementation Title JTwitter
  • Python - 单击 JavaScript 按钮

    我在页面上有一个按钮 需要单击该按钮才能按顺序转到下一页 我想知道如何使用 Python 实现这一点 该按钮似乎是 HTTP POST 请求和 Javascript 的混合体 以下是该按钮的代码
  • 如何修复错误消息“__builtin_avr_delay_cycles 需要编译时整数常量 make”?

    我的程序没有使用 GCC AVR 编译器进行编译 这是一款微处理器和液晶屏上的小游戏 move delay 200 delay ms move delay 它不喜欢这个 delay ms 是一个变量 但它需要是一个变量 因为我可以通过 AD
  • 使用 Android 精确定位室内位置 - 不够准确

    我正在尝试寻找一种在室内进行精确定位的解决方案 特别是在大型拥挤的地方 例如购物中心 我尝试构建一个简单的应用程序 尝试仅使用网络服务或 Wifi 网络来精确定位手机 通常当Wifi开启时 精度可以达到40 60米 而当Wifi关闭且仅使用
  • 如何使 ion-grid 像 Ionic 2 中的按钮一样可点击

    我使用 ion grid 设计了表格 但我的问题是要使其像按钮一样可点击 我只能使用 click functionX 来调用函数 例如这是我的网格
  • 在 r 中使用 dbplyr 时,last() 函数的结果错误/错误

    我正在尝试跑步sql using r dbplyr并遇到了一个错误 错误结果使用时last 功能与dbplyr代码 我不确定我是否做错了或者是否确实存在错误 客观的 使用 dbplyr 从表中获取每个员工的最新状态 我尝试使用下面的代码来复
  • 如何查找 Visual Studio 项目的 .NET Framework 版本?

    我在 Visual Studio 中有一个项目 如何找出它适用于哪个 NET Framework 版本 这取决于 Visual Studio 的版本 In 2002 所有项目均使用 Net 1 0 In 2003 所有项目均使用 Net 1
  • pandas 替换列子集的空值

    我有一个包含许多列的数据框 例如 df name salary age title John 100 35 eng Bill 200 NaN adm Lena NaN 28 NaN Jane 120 45 eng 我想替换工资和年龄中的空值
  • Android 模拟器支持 OpenGL ES 2.0 吗?

    本文http cobworks ca 2010 04 19 why android market has no games http cobworks ca 2010 04 19 why android market has no game
  • 使用 JPA 时,我应该为 JBDC 模板使用什么事务管理器?

    我正在使用标准 JPA 事务管理器来处理 JPA 事务 但是 现在我想添加一些共享相同 数据源 的 JDBC 实体 如何使用 spring 事务使 JDBC 操作具有事务性 我需要切换到 JTA 事务管理器吗 是否可以将 JPA 和 JDB