最近遇到的一个比较诡异的问题,貌似各种配置都正确了,事务不起效。
首先resin服务器的配置文件连接数据库的配置如下:
<database> <jndi-name>jdbc/bbs7_app</jndi-name> <driver> <type>com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource</type> <url>jdbc:mysql://192.168.74.5:3310/bbs7_pc_app?useUnicode=true&characterEncoding=GBK</url> <user>root</user> <password>root</password> </driver> <prepared-statement-cache-size>30</prepared-statement-cache-size> <max-connections>30</max-connections> <max-idle-time>120s</max-idle-time> </database>
spring的配置文件配置了注解开启:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <context:component-scan base-package="cn.pconline.bbs7"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan> <tx:annotation-driven transaction-manager="transactionManager"/>
要加事务的public方法也已经加上了注解(注解只对public方法有效)
@Transactional public int updateTopicAndGetFloor(User user, Topic topic, Date now) { int floor = 0; if (!topic.isNoUp()) { topic.setLastPostAt(now); } topic.setLastPosterId(user.getUid()); StringBuilder sql = new StringBuilder("UPDATE ").append(TABLE_NAME).append( " SET replyCount=replyCount + 1, lastPosterId=?").append( ", lastPostAt=?, updateAt=?, floor=floor + 1 WHERE tid=?"); int result = topicXdb.getJdbcTemplate(topic.getFid()).update(topicXdb.xsql(topic.getFid(), sql.toString()), topic.getLastPosterId(), topic.getLastPostAt(), new Date(), topic.getTid()); if (result > 0) { removeFromCache(topic); // throw new RuntimeException("测试事务异常"); floor = getFloorFromDB(topic); } return floor; }
但是,手动测试让方法抛出一个RuntimeException的时候,数据没有回滚。
排除了半天,发现mysql的事务是默认提交的,把mysql的全局事务默认提交关闭后(如何设置事务关闭,参考这里:http://breezylee.iteye.com/admin/blogs/2052861),用root权限的用户登录,还是无效(mysql的bug,root用户事务默认提交),于是,换成其它一般权限的用户连接,发现还是不行(此时一般用户的事务,不是默认提交了)。
听一个牛人同事说,mysql的驱动com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource,不支持事务的,于是换成了com.mysql.jdbc.Driver,所以,数据源驱动配置改为如下:
<database> <jndi-name>jdbc/bbs7_app</jndi-name> <driver> <type>com.mysql.jdbc.Driver</type> <url>jdbc:mysql://192.168.74.5:3310/bbs7_pc_app?useUnicode=true&characterEncoding=GBK</url> <user>bbs7_pc_app</user> <password>bbs7_pc_app</password> </driver> <prepared-statement-cache-size>30</prepared-statement-cache-size> <max-connections>30</max-connections> <max-idle-time>120s</max-idle-time> </database>
改成这样之后,方法就有了事务控制了,抛异常之后数据可以正常回滚。
更正下,com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource这个驱动并不是不支持事务,上面的实验证明,貌似和spring的 jdbcTemplate操作、声明式事务@Transactional有点冲突。如果改用纯的jdbc操作,这个驱动还是支持事务的。
Connection conn = dataSource.getConnection();这样每次都是拿到一个新的连接,事务只在同一个连接里面有效,如果是多个连接,就是分布式事务,要换另一些解决方案。参考这里:
http://www.iteye.com/problems/89655
----------------------2014.8.8------------------
在这个环境下:
(1)mysql关闭自动提交
(2)程序没有加事务控制
(3)mysql的驱动用 com.mysql.jdbc.Driver
(4)用非root权限的普通权限的用户连接mysql
用spring的批量更新方法:jdbcTemplate.batchUpdate(sql.toString(), batch),
方法是执行成功了,但数据库没有更新到,就是说事务没有提交成功,如果执行完上面的batchUpdate后再手动commit,事务是可以提交成功的。
同样的环境,如果把驱动换成 com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource这个之后,不用手动commit,事务也可以提交成功。
具体原因不明,貌似是com.mysql.jdbc.Driver这个驱动不支持批量更新的事务。
相关推荐
Spring @Transactional 注解失效解决方案 ...通过了解 @Transactional 注解的特性和事务传播模式,并遵循解决方案,我们可以解决 @Transactional 注解不回滚的问题,确保事务管理的正确性和可靠性。
如果使用mysql 关系型数据库,且存储引擎是 MyISAM 而非 InnoDB,那么事务将不起作用。注意,这种情况基本上不会遇到。 Spring事务失效的常见场景有七种,分别是:注解@Transactional 配置的方法非 public 权限修饰...
以下是对`jdbc+spring+mysql事务理解和分析`的详细说明: 1. **原子性(Atomicity)**:这是事务的基本特性,表示事务中的所有操作要么全部成功,要么全部回滚。如果在事务执行过程中发生错误,数据库会撤销所有已...
在Spring与Hibernate的结合下,MySQL的事务控制可以通过设置不同的隔离级别(如READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE)来优化并发性能和避免数据竞争问题。 在实际开发中,我们还需要...
同时,Mybatis3也支持使用`@Transactional`注解进行局部事务控制,但通常在Spring环境中,全局事务管理由Spring负责。 在这个"spring3+struts2+Mybatis3"的实例中,你将学习如何集成这三个框架,创建一个完整的Java...
总之,MySQL 的事务隔离机制允许用户根据需要选择合适级别的隔离,同时提供了 `SET TRANSACTION ISOLATION LEVEL` 命令和 Spring 的 `@Transactional` 注解来灵活配置,以保证数据的一致性和应用的性能。对于开发者...
### 关于Spring MyBatis纯注解事务不能提交的问题分析与解决 #### 问题背景 在使用Spring结合MyBatis框架进行开发时,有时会遇到事务管理方面的问题,特别是当项目采用纯注解的方式配置事务时,可能会出现事务无法...
SUPPORTED(不支持事务,如果有事务则挂起)、NEVER(不允许存在事务,如果有则抛出异常)、NESTED(嵌套事务,如果当前事务存在,则在嵌套事务内执行,否则新建事务)。 4. **Spring的回滚规则**:默认情况下,...
通过使用注解,如`@Autowired`注入DataSource,然后在方法上使用`@Transactional`进行事务管理,可以实现数据库操作的便捷性。例如,一个简单的JdbcTemplate查询可能使用`@Repository`注解的类,其中的方法用`@Query...
在Spring配置文件中开启注解事务,通常通过标注@Transactional注解实现;或者在XML文件中进行配置。 整合后的操作流程大致如下: - 首先,Spring框架启动时会读取配置信息,加载并初始化数据源、SqlSessionFactory...
Spring事务注解的使用使得开发者可以轻松地在应用程序代码中控制事务边界,而无需手动管理数据库连接和事务。通过结合MySQL的事务隔离级别设置和Spring的事务管理,可以有效地确保数据一致性并优化并发性能。
本文将深入探讨在Spring框架中如何管理事务,以“Spring 事务简单完整例子”为出发点,结合标签“spring,事务,jdbc事务”,我们将详细解释Spring事务管理的原理和实践。 首先,Spring提供了两种事务管理方式:编程...
声明式事务管理更常见,通过@Transactional注解在方法上开启事务。例如: ```java @Transactional public void createUserAndOrder(User user, Order order) { // 插入用户 insertUser(user); // 插入订单 ...
四、Spring事务注解管理 在Spring中,可以使用@Transactional注解来标记需要进行事务管理的方法。例如: ```java @Service public class UserService { @Transactional public void updateUserAndOrder(User ...
4. **事务管理**:在Spring中配置事务管理器,如`HibernateTransactionManager`,并使用`@Transactional`注解来声明方法级别的事务边界。 5. **DAO层**:创建数据访问对象(DAO),利用Spring的JdbcTemplate或...
在全注解开发中,我们可以使用@Autowired来自动装配bean,@Transactional来声明事务边界,@Service和@Repository则分别用于标记服务层和数据访问层的bean。 Hibernate是一个流行的Java ORM(对象关系映射)框架,它...
7. **事务管理**:Spring提供声明式事务管理,基于@Transactional注解。在方法上添加该注解,Spring会自动处理事务的开始、提交和回滚。例如: ```java @Transactional public void yourMethod() { // 数据库...
3. 配置和使用Spring的事务管理,了解如何通过@Transactional注解处理异常时的回滚逻辑。 4. 整合Hibernate的实体类和表之间的映射,学习如何通过注解定义实体属性和关系。 5. 错误和异常处理,包括自定义异常处理器...
综上所述,这个压缩包提供了一个完整的Spring与MySQL结合的示例,涵盖了Spring的数据库操作、MVC模式、事务管理等多个核心功能,是学习和理解Spring整合数据库的绝佳实践。通过这个项目,开发者可以深入理解Spring...
3. **异常回滚规则**:默认情况下,如果在@Transactional注解的方法中抛出未检查异常(继承自RuntimeException)或者Error,Spring会自动回滚事务。对于检查异常(非RuntimeException),如果不指定回滚规则,事务...