关于@Transactional(readOnly = false)注解,数据新增修改Connection is read-only

本文探讨了在使用@Transactional(readOnly=false)时遇到Connectionisread-only错误的原因及解决方案。主要分析了Spring配置文件中事务管理属性设置的影响,以及注解与XML配置之间的优先级关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于@Transactional(readOnly = false)注解,数据新增修改Connection is read-only

有时你新增或修改会报Connection is read-only

Cause: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed

这是因为你配置了数据库连接为只读,不能新增修改,而配置只读的方法有2个一个是xml里面配置事物的时候配置方法只读

<!-- 事务管理 属性 -->
    <tx:advice id="transactionAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="add*" propagation="REQUIRED" isolation="DEFAULT"/>
            <tx:method name="append*" propagation="REQUIRED" isolation="DEFAULT"/>
            <tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT" rollback-for="Exception"/>
            <tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT" rollback-for="Exception"/>
            <tx:method name="modify*" propagation="REQUIRED" isolation="DEFAULT"/>
            <tx:method name="edit*" propagation="REQUIRED" isolation="DEFAULT"/>
            <tx:method name="insert*" propagation="REQUIRED" isolation="DEFAULT" rollback-for="Exception"/>
            <tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT"/>
            <tx:method name="del*" propagation="REQUIRED" isolation="DEFAULT"/>
            <tx:method name="*Tran"  propagation="REQUIRED" isolation="DEFAULT" />
            <tx:method name="remove*" propagation="REQUIRED" isolation="DEFAULT"/>
            <tx:method name="repair" propagation="REQUIRED" isolation="DEFAULT"/>
            <tx:method name="get*" propagation="REQUIRED"/>
            <tx:method name="find*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="count*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="load*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="search*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="datagrid*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="do*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
            <tx:method name="send*" propagation="REQUIRED" isolation="DEFAULT" />
            <tx:method name="*" propagation="REQUIRED" read-only="true"/>
        </tx:attributes>
    </tx:advice>

最后一句

<tx:method name="*" propagation="REQUIRED" read-only="true"/>

所有不是配置里的前缀方法都为只读。
另一个配置只读就是注解@Transactional(readOnly = true),配置这个注解就会不能新增修改。
有时候@Transactional(readOnly = false)不能生效,这个可能是xml配置与注解配置有优先级的关系,我简单测试了一下是xml优先级大于注解,如果我说错了,请大佬指正。

<think>嗯,用户遇到了一个Spring的数据库异常:TransientDataAccessResourceException,提示连接是只读的,不允许修改数据。我需要帮他分析这个问题。 首先,看错误信息里的SQL是INSERT操作,这说明在执行写入操作。而异常明确说连接是只读的,所以问题应该出在连接的配置上。可能的原因有几个方面。 第一,数据库连接配置是否正确?比如,是否在数据源配置里设置了readOnly=true。有时候在配置多数据源的时候,可能会不小心把某个数据源设置为只读,导致无法写入。需要检查配置文件,比如application.yml或application.properties里的相关数据源设置,尤其是使用的那个数据源是否有read-only的标记。 第二,事务管理的问题。Spring的事务管理默认可能会根据方法名或注解来设置只读事务。比如,如果Service层的方法使用了@Transactional(readOnly = true),那么在这个事务里的所有操作都只能是只读的。用户可能在插入数据的方法上误加了readOnly属性,或者默认的事务配置有问题。需要检查Service层中执行插入操作的方法,看是否有@Transactional注解,特别是是否设置了readOnly为true。如果有的话,需要去掉或者设置为false。 第三,数据源本身的问题。如果使用的数据库账户权限不足,只有读取权限而没有写入权限,也会导致这个错误。这时候需要检查数据库的用户权限,确认该用户是否有执行INSERT等写操作的权限。 接下来,可能的解决方案包括: 1. 检查数据源配置,确保没有设置readOnly为true。比如,在Spring Boot的配置中,查看spring.datasource.hikari.read-only或者其他数据源相关的read-only属性是否被错误开启。 2. 检查事务注解,确保在涉及写操作的方法上,@Transactional没有设置readOnly=true。如果方法需要进行写操作,应该设置readOnly=false或者不设置该属性,因为默认就是false。 3. 验证数据库账户权限,确保该账户有执行INSERT语句的权限。可以通过数据库客户端工具登录该账户,手动执行INSERT语句来测试是否有权限问题。 另外,还要注意事务的传播行为是否正确。如果在一个只读的事务中调用了写操作,可能会导致问题。例如,如果外层方法开启了只读事务,而内部方法需要写数据,这时候如果没有正确配置传播行为,内部方法可能会继承外层的事务属性,从而导致错误。这时候可能需要调整事务的传播机制,比如使用REQUIRES_NEW来新建一个非只读的事务。 还有可能是在使用Spring的声明式事务管理时,AOP的切面配置有误,导致某些本应可写的方法被错误地标记为只读。需要检查事务切面的配置,确保写操作的方法没有被错误拦截。 如果使用的是多数据源配置,还需要确认当前操作是否正确地使用了支持写操作的数据源。有时候在多数据源环境下,如果没有正确指定数据源,可能会误用只读的数据源来执行写操作。 总结一下,解决这个问题的步骤应该是先检查数据源配置,再审查事务注解和配置,接着验证数据库权限,最后考虑事务传播和多数据源的问题。用户可以根据这些步骤逐一排查,找到具体的原因并进行修复。</think>这个错误表明你的数据库连接处于**只读模式**,但程序试图执行写操作(INSERT)。以下是逐步排查和解决方案: --- ### 一、错误分析 1. **异常类型**:`TransientDataAccessResourceException` Spring框架抛出的数据访问异常,通常与数据库连接或事务配置有关。 2. **核心错误信息**: `Connection is read-only. Queries leading to data modification are not allowed` 明确提示:当前数据库连接为只读模式,无法执行写操作(如INSERT)。 3. **关键代码定位**: - 涉及Mapper文件:`DefDatasourceConfigMapper.java` - 涉及SQL:`INSERT INTO def_datasource_config(...)` 说明问题出现在执行插入操作时。 --- ### 二、常见原因及解决方案 #### 1. **事务配置问题** - **原因**: 当前方法可能被标记为`@Transactional(readOnly = true)`,导致整个事务内的数据库操作强制为只读。 - **解决方案**: 检查Service层中调用`DefDatasourceConfigMapper.insert()`的方法,确保**未设置**`readOnly = true`。 正确示例: ```java @Transactional // 默认readOnly = false public void createDataSource(DefDatasourceConfig config) { defDatasourceConfigMapper.insert(config); } ``` #### 2. **数据源配置问题** - **原因**: 数据源(如HikariCP、Druid)被显式配置为只读模式(`readOnly = true`)。 - **解决方案**: 检查数据源配置(如`application.yml`或`application.properties`),确保未设置`readOnly`属性。 示例配置: ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/your_db username: root password: root hikari: read-only: false # 确保此处为false或删除此配置 ``` #### 3. **数据库用户权限问题** - **原因**: 数据库账号仅具备`SELECT`权限,无`INSERT`权限。 - **解决方案**: 登录数据库,检查账号权限: ```sql SHOW GRANTS FOR 'your_username'@'%'; ``` 授权示例: ```sql GRANT INSERT, UPDATE, DELETE ON your_db.def_datasource_config TO 'your_username'@'%'; ``` #### 4. **多数据源配置冲突(如有)** - **原因**: 在多数据源环境下,事务管理器或数据源路由错误地选择了只读数据源。 - **解决方案**: 检查`@DataSource`注解(如有)是否指向正确的可写数据源,并确保事务管理器与数据源匹配。 --- ### 三、验证步骤 1. **本地复现**: 在开发环境中复现问题,通过调试断点确认事务配置和数据源配置。 2. **日志排查**: 检查启动日志,确认数据源初始化时的`readOnly`状态: ``` Initializing HikariPool-1 - Configuration: ... readOnly=false ... ``` 3. **数据库权限测试**: 手动执行INSERT语句(如通过MySQL Workbench),验证账号是否有权限。 --- ### 四、总结 | 原因类型 | 检查点 | 修复措施 | |------------------|--------------------------------|-----------------------------| | 事务配置 | `@Transactional(readOnly)` | 移除`readOnly = true` | | 数据源配置 | `spring.datasource.read-only` | 设置为`false`或删除配置 | | 数据库权限 | 账号权限列表 | 授权`INSERT`权限 | | 多数据源路由 | 数据注解和路由逻辑 | 确保指向可写数据源 | 通过以上步骤,应能定位并解决连接只读问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值