Skip to content

Categories:

SSH开发心得

前段时间开发一个J2EE的Web项目,使用SSH(Struts+Spring+hibernate)框架。开发过程中遇到一个相当郁闷的问题,困扰了我好几天。这里我跟大家分享一下。

问题是这样的:我用Spring的声明式事务管理来管理事务,当出现异常时能回滚事务。于是我做了一个测试,在一个方法里,我先添加了一条数据,然后再删除一条数据,在删除数据的时候我让它强行抛出异常,这时刚添加的那条数据应该回滚掉,可是我查看了一下数据库,发现数据已经插入,根本没有回滚,这是怎么回事呢?我的第一个反应就是Spring配置文件可能出问题了。

以下是我的Spring的事务管理的配置方式:

	<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
	<propertyname="sessionFactory"ref="sessionFactory"/>
	</bean>
 
	<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
	<!--事务拦截器bean需要依赖注入一个事务管理器-->
	<property name="transactionManager"ref="transactionManager"/>
	<property name="transactionAttributes">
	<!--下面定义事务传播属性-->
	<props>
	<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
	<prop key="*">PROPAGATION_REQUIRED,-Exception</prop>
	</props>
	</property>
	</bean>
		<!--定义BeanNameAutoProxyCreator-->
		<bean
		class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
			<!--指定对满足哪些beanname的bean自动生成业务代理-->
			<property name="beanNames">
				<!--下面是所有需要自动创建事务代理的bean-->
				<list>
					<value>*Bo</value>
				</list>
				<!--此处可增加其他需要自动创建事务代理的bean-->
			</property>
			<!--下面定义BeanNameAutoProxyCreator所需的事务拦截器-->
			<property name="interceptorNames">
				<list>
					<!--此处可增加其他新的Interceptor-->
					<value>transactionInterceptor</value>
				</list>
			</property>
		</bean>

带着这个问题,我到网络上查了很多关于Spring配置事务的资料,也做了很多次修改,但问题仍然存在。我开始怀疑难道是Spring配置方式根本就是正确的。那这样的话问题到底出在哪里呢?为什么抛出异常后事务没有回滚呢?

快接近崩溃边缘的我还是硬着头皮继续在网络上求教,突然在一篇文章里看到这样一句话“Mysql表的MyISAM类型不支持事务处理,InnoDB类型提供事务支持”。我马上查了一下数据库的表类型,发现我的表就是MyISAM类型的,太兴奋了,难道就这样搞定了?于是我马上将表类型改成InnoDB,重启测试,问题解决。兴奋之余总结一下:原因就是我一直以为是Spring配置文件出问题了,却一直忽略了其他的情况。最后,将Mysql这两种表类型的详细对比跟大家分享一下。

InnoDB和MyISAM是MySQL最常用的表类型,各有各的优缺点,选用哪个视具体应用场景而定。

MyIASM:基于传统的IASM类型,ISAM是Indexed Sequential Access Method(有索引的顺序访问方法)的缩写,IASM是存储记录和文件的标准方法。与其他存储引擎比较,MyISAM具有检查和修复表的大多数工具。MyISAM表可以被压缩,而且它们支持全文搜索。它们不是事务安全的,而且也不支持外键。如果事物回滚将造成不完全回滚,不具有原子性。如果执行大量的SELECT,MyISAM是更好的选择。MyISAM对IASM有如下扩展:

二进制层次的可移植性。

NULL列索引。

对变长行比ISAM表有更少的碎片。

支持大文件。

更好的索引压缩。

更好的键码统计分布。

更好和更快的auto_increment处理。

InnoDB:它是事务安全的,与BDB类型具有相同的特性。它们支持外键。InnoDB表速度很快,具有比BDB还丰富的特性,因此如果需要一个事务安全的存储引擎,建议使用它。如果你的数据执行大量的INSERT或UPDATE,出于性能与事务方面的考虑,应该使用InnoDB类型的表。

以下是InnoDB与MyISAM细节和具体实现的差别:

InnoDB有它自己的缓冲池,能缓冲数据和索引,InnoDB把数据和索引存放在表空间里面,可能包含好几个文件,在MyISAM中,表被存放在单独的文件中,InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。InnoDB不支持FULLTEXT类型的索引。

InnoDB支持行锁,提供和Oracle一样的一致性的不加锁读取,能增加并发读的用户数量并提高性能,不会增加锁的数量。另外,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如update table set num=1 where name like“%aaa%”。

InnoDB中不保存表的具体行数,也就是说,执行selectcount(*)fromtable时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。要注意的是,当count(*)语句包含where条件时,两种表的操作是一样的。

对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。

DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。

LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。

任何一种表类型都不是万能的,只能针对具体的应用场景来选择合适的表类型,这样才能最大限度地发挥MySQL的性能。

Posted in java.

Tagged with .


0 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.



Some HTML is OK

or, reply to this post via trackback.