Spring事物不回滚

spring事物不回滚的问题

一、环境介绍

mysql数据库,springMVC,Mybatis,搭建完成测试过程中一个偶然的原因发现事物不回滚,立马想到数据库不支持。这个下面会有详细说明。

二、mysql数据库介绍

Mysql的存储引擎: MyIsAm、InnoDB、MEMORY、MERGE这四种,四种各有各的好处,技术选型可以针对不同的需求选择不同的方式。

  1.MyIsAm

MyISAM是MySQL的默认存储引擎。MyISAM不支持事务、也不支持外键,但其访问速度快,对事务完整性没有要求。 
MyISAM表还支持3中不同的存储格式: 
1 静态表 
2 动态表 
3 压缩表 
静态表是默认的存储格式,静态表中的字段都是非变长的字段,
优点是:存储非常迅速,容易缓存,出现故障容易恢复;
缺点是:占用的空间通常比动态表多。
(注意: 在存储时,列的宽度不足时,用空格补足,当时在访问的时候并不会得到这些空格)
动态表的字段是变长的,优点是:占用的空间相对较少,但是频繁地更新删除记录会产生碎片,
需要定期改善性能,并且出现故障的时候恢复相对比较困难。 
压缩表占用磁盘空间小,每个记录是被单独压缩的,所以只有非常小的访问开支。

2.InnoDB

InnoDB存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全。但是比起MyISAM存储引擎,
InnoDB写的处理效率差一些并且会占用更多的磁盘空间以保留数据和索引。
而且MySQL支持外键存储引擎只有InnoDB,在创建外键的时候,
要求附表必须有对应的索引,子表在创建外键的时候也会自动创建对应的索引。(被关联表的外键必须是关联表的主键) 
InnoDB的理想使用场合:高并发,更新操作比较多的表。需要使用事务的表。对自动灾难恢复有要求的表。

3.MEMORY

MEMORY存储引擎使用存在内存中的内容来创建表。
每个MEMORY表只实际对应一个磁盘文件。MEMORY类型的表访问非常得快,因为它的数据是放在内存中的,并且默认使用HASH索引。
但是一旦服务关闭,表中的数据就会丢失掉。Memory存储引擎的使用场合,速度要求快的,临时数据

  4.MERGE

merge存储引擎是一组MyISAM表的组合,这些MyISAM表结构必须完全相同,MERGE表中并没有数据, 对MERGE类型的表可以进行查询、更新、删除的操作,这些操作实际上是对内部的MyISAM表进行操作。 对于对MERGE表进行的插入操作,是根据INSERT_METHOD子句定义的插入的表,可以有3个不同的值, first和last值使得插入操作被相应的作用在第一个或最后一个表上,不定义这个子句或者为NO, 表示不能对这个MERGE表进行插入操作。可以对MERGE表进行drop操作,这个操作只是删除MERGE表的定义, 对内部的表没有任何影响。MERGE在磁盘上保留2个以MERGE表名开头文件:.frm文件存储表的定义; .MRG文件包含组合表的信息,包括MERGE表由哪些表组成,插入数据时的依据。 可以通过修改.MRG文件来修改MERGE表,但是修改后要通过flush table刷新。

三、解决方案

 现在对mysql的存储引擎有了解的话,那么就知道如果你的表的存储引擎方式是InnoDB的话,那么不支持事物回滚就是你的配置问题了。下面是具体的解决方法

  1.修改mysql的存储引擎方式

show engines; #显示数据库是否支持InnoDB
更改方式1:修改配置文件my.cnf
打开my.cnf,在[mysqld]最后添加为上default-storage-engine=InnoDB,重启数据库服务,数据库默认的引擎修改为InnoDB
更改方式2:在建表的时候指定或者建完表修改
create table tableName( id int primary key, name varchar(50) )type=InnoDB;

建完表之后修改也可以
alter table tableName ENGINE=InnoDB; #mysql5.0以后用这种方式
alter table tableName type = InnoDB; #mysql5.0之前用这种方式
修改
之后查看
show create table tableName; #这个信息可能比较多注意查看ENGINE这个关键字。

2.配置方式

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-4.1.xsd 
		http://www.springframework.org/schema/tx 
		http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
		http://www.springframework.org/schema/aop 
		http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
		">

	<!-- 配置数据源 使用的是Druid数据源 -->
	<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
		init-method="init" destroy-method="close">
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />

		<!-- 初始化连接大小 -->
		<property name="initialSize" value="0" />
		<!-- 连接池最大使用连接数量 -->
		<property name="maxActive" value="20" />
		
		<!-- 连接池最小空闲 -->
		<property name="minIdle" value="0" />
		<!-- 获取连接最大等待时间 -->
		<property name="maxWait" value="60000" />
		<property name="poolPreparedStatements" value="true" />
		<property name="maxPoolPreparedStatementPerConnectionSize"
			value="33" />
		<!-- 用来检测有效sql -->
		<property name="validationQuery" value="${validationQuery}" />
		<property name="testOnBorrow" value="false" />
		<property name="testOnReturn" value="false" />
		<property name="testWhileIdle" value="true" />
		<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
		<property name="timeBetweenEvictionRunsMillis" value="60000" />
		<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
		<property name="minEvictableIdleTimeMillis" value="25200000" />
		<!-- 打开removeAbandoned功能 -->
		<property name="removeAbandoned" value="true" />
		<!-- 1800秒,也就是30分钟 -->
		<property name="removeAbandonedTimeout" value="1800" />
		<!-- 关闭abanded连接时输出错误日志 -->
		<property name="logAbandoned" value="true" />
		<!-- 监控数据库 -->
		<property name="filters" value="mergeStat" />
	</bean>

	<!-- myBatis文件 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<!-- 添加mybatis的配置 -->
		<property name="configLocation" value="classpath:mybatis.xml"/>
		<!-- 自动扫描entity目录, 省掉Configuration.xml里的手工配置 -->
		<property name="mapperLocations" value="classpath:com/tanrice/dao/impl/*.xml" />
	</bean>

	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.tanrice.dao" />
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
	</bean>

	<!-- 配置事务管理器 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>


	<!-- 注解的方式配置事务 -->
	<!-- 在需要的地方配置 -->
	<!-- <tx:annotation-driven transaction-manager="transactionManager"  proxy-target-class="true"/> -->

	<!-- 注解方式配置事物 -->
	<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="add*" propagation="REQUIRED" isolation="READ_COMMITTED" />
			<tx:method name="append*" propagation="REQUIRED" isolation="READ_COMMITTED" />
			<tx:method name="insert*" propagation="REQUIRED" isolation="READ_COMMITTED" />
			<tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED" />
			<tx:method name="update*" propagation="REQUIRED" isolation="READ_COMMITTED" />
			<tx:method name="modify*" propagation="REQUIRED" isolation="READ_COMMITTED" />
			<tx:method name="edit*" propagation="REQUIRED" isolation="READ_COMMITTED" />
			<tx:method name="delete*" propagation="REQUIRED" isolation="READ_COMMITTED" />
			<tx:method name="remove*" propagation="REQUIRED" isolation="READ_COMMITTED" />
			<tx:method name="repair" propagation="REQUIRED" isolation="READ_COMMITTED" />
			<tx:method name="delAndRepair" propagation="REQUIRED" isolation="READ_COMMITTED" />
			<tx:method name="get*" propagation="SUPPORTS" isolation="READ_COMMITTED" />
			<tx:method name="find*" propagation="SUPPORTS" isolation="READ_COMMITTED" />
			<tx:method name="load*" propagation="SUPPORTS" isolation="READ_COMMITTED" />
			<tx:method name="search*" propagation="SUPPORTS" isolation="READ_COMMITTED" />
			<tx:method name="datagrid*" propagation="SUPPORTS" isolation="READ_COMMITTED" />
			<tx:method name="*" propagation="SUPPORTS" isolation="READ_COMMITTED" />
		</tx:attributes>
	</tx:advice>
	<!-- Spring aop事务管理 -->
	<aop:config>
		<aop:pointcut id="transactionPointcut" expression="execution(* com.tanrice.service..*Impl.*(..))" />
		<aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" />
	</aop:config>
	<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate" scope="prototype">
         <constructor-arg index="0" ref="sqlSessionFactory" /> 
    </bean>
</beans>

针对不同的情况在service里面的代码也不一样。
1. 使用aop的方式:那么将会注入所有的切面。这样务必会造成资源的部分浪费
  2. 使用注解的方式。这样可以在想要的地方加上 @Transactional注解。但是在交接,或者忙的时候会忘记。
这两种方式都可以,各有优缺点。下面是插入相关的代码
@Service
@Transactional
public class UserTaskServiceImpl implements UserTaskService{
public boolean updateUserTask(UserTask userTask,int id) {
		boolean flag = false;
		try{
			flag = userTaskDao.saveUserTask(userTask)>0?true:false;
			System.out.println("插入:"+flag);
			flag = taskDao.updateTaskLeftcountById(id)>0?true:false;
			System.out.println("修改:"+flag);
		}catch(Exception e){
			throw new RuntimeException();
		}
		return flag;
	}
}



测试类
@org.junit.Test
	public void testTrx(){
		UserTask userTask = new UserTask();
		userTask.setFullname("wanda");
		userTask.setUserid(10071);
		userTask.setTaskid(10026);
		userTask.setGettime(new Date().getTime());
		userTask.setState(5);
		
		System.out.println("结果是:"+userTaskService.updateUserTask(userTask, 10026));
	}

结果:在异常情况下,会回滚数据
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值