先说下数据读取的几个异常情况:
1.读取脏数据(Dirty reads)。就是读取到了其他事务没有提交的数据。比如2个并发的事务A,B。A修改了字段age(原来为18)的值为20,这时B读取到age的值为20。如果A事务在后面的操作中回滚了,这样事务B取的age=20就是个脏数据。这种情况发生的很少,因为主流的数据库的隔离级别都能保证避免脏数据的读取。
2.不可重复读(non-repeatable reads)。就是修改了其他事务已经读取的数据。比如2个并发的事务A,B。A读到字段age=18。这时B对改字段做了修改age=20。这样事务A如果再次读取age时就会发现两次得到的数据是不同的。
3.幻读(phantom reads)。它和不可重复读类似,但也不同,它不是修改其他事务已经读取的数据,而是新增了其他进程没有读到的数据。这样会造成这种情况:A读取user_info表的记录数是100,事务B新增了2条记录,这样A再次读取时就会发现记录数成了102,数据不一致了。
而事务的隔离级别就是为了防止以上数据不一致的情况发生。
Dirty reads non-repeatable reads phantom reads
Serializable 不会 不会 不会
REPEATABLE READ 不会 不会 会
READ COMMITTED 不会 会 会
Read Uncommitted 会 会 会
实现原理就是对数据库表进行加锁。
Read Uncommitted自然是不加锁,READ COMMITTED是读取时对读取的行加锁,读取完成之后就解锁。REPEATABLE READ也是读取的内容加锁,但解锁是要等到所在事务提交。Read Uncommitted就是全表加锁。
Serializable的隔离级别效率太差,hibernate默认的隔离级别是REPEATABLE READ,不保证避免幻读。
配置的话具体见spring手册,下面从网络上考的一段配置文件:
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <constructor-arg> <ref local="jtaTransactionManager" /> </constructor-arg> </bean> <bean id="orderService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"> <ref local="transactionManager" /> </property> <property name="proxyInterfaces"> <list> <value>sample.services.OrderService</value> </list> </property> <property name="target"> <ref local="orderServiceTarget" /> </property> <property name="transactionAttributes"> <props> <prop key="save*">PROPAGATION_REQUIRED, ISOLATION_SERIALIZABLE</prop> <prop key="delete*">PROPAGATION_REQUIRED, ISOLATION_READ_UNCOMMITTED</prop> <prop key="find*">PROPAGATION_REQUIRED, ISOLATION_READ_UNCOMMITTED, readOnly</prop> </props> </property> </bean>