这是HeidiSQl截图查看不同引擎的特性:
getTransaction定义了事务的开启范围,这个可以在网上找到更详细的讲解,这里不累述。commit与rollback就是基本的事务控制机制。 AbstractPlatformTransactionManager实现了该接口,这个抽象类定义一些基本的对事务支持的操作,但是抽象了不同的orm框架对事务管理的细节。jdbc是通过dataSource Connection来进行事务管理,而hibernate是通过Sqlsession进行事务管理。使用jdbc进行事务管理,就注入DataSourceTransactionManager即可。并制定对应的数据源,然后只需要制定需要代理的类即可。 数据源的配置:
<bean id="driver" class="com.mysql.jdbc.Driver"></bean> <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource"> <property name="username" value="${username}" /> <property name="passWord" value="${password}" /> <property name="url" value="${url}" /> <property name="driver" ref="driver" /> </bean>首先我们制定事务管理器:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>然后我们定义需要事务传播机制,我们来创建一个常见,也可以采用其他的方式创建advice,这里的advice通知就是定义了需要做什么,这里就是 如果有事务加入事务,没有的话创建新事务:
<tx:advice id="advice" transaction-manager="transactionManager"> <tx:attributes> <!-- 如果有事务加入事务,没有的话创建新事务 --> <tx:method name="*" propagation="REQUIRED" timeout="3"/> </tx:attributes> </tx:advice>做什么定义完了,就需要指定在哪里做(pointcut)即切点,代理的方式有很多种,可以使用默认的代理DefaultAdvisorAutoProxyCreator。也可以使用注解的方式,很灵活,主要就是明白定义好切点(一般spring支持较好的是方法级别的拦截)即可。这里我们使用比较方便的schema标签支持aop代理:
<aop:config> <aop:pointcut id="txPointcut" expression="execution(* micro.test.spring.service..*Service*.*(..))" /> <aop:advisor advice-ref="advice" pointcut-ref="txPointcut"/> </aop:config>很多时候我们引入新的xml标签会报错,这个时候检查xml文件头是否引入了相关的schema即可,这点是初学者很容易犯错的地方。
<!-- 扫描到advice --> <context:component-scan base-package="micro.test.spring" /> <!-- mybatis中sqlSession由这个类来完成 --> <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="mapperLocations"> <list> <value>classpath:/sqlmap/ComputerMapper.xml</value> </list> </property> </bean>其他必要的配置跟本文不太相关就不贴了。 前面execution(* micro.test.spring.service..Service.*(..))就表示在这个包下面的所有方法都是切点,会被代理。这是service的一个方法,执行它:
public void testTransaction2() { Computer computer = new Computer(); computer.setBrand("test"); computerMapper.insert(computer);//事务会回滚 ComputerExample computerExample = new ComputerExample(); computerExample.or().andBrandEqualTo(computer.getBrand()); int a = 1; a /= 0; // 制造异常 computerMapper.insert(computer); }如果没事务管理机制,会插入一条记录。引入了事务管理机制,抛出异常(spring要求运行时异常)就不会插入记录,因为遇到了异常,当然如果去掉异常,两条都会插入进去,值得一提的是我数据库设置的默认应该不是读未提交,因为在调试到还没抛异常的时候也不会看到一条记录,如果是读未提交应该是看到出现了一条记录然后又消失了(被回滚),测试了几次,要么有0条,要么有两条(正常执行)。没有造成脏读的情况至少应该是读已提交。查询了一下: 果然可重复读,是能够不免脏读和不可重复度两个问题的。但是无法避免幻读。
新闻热点
疑难解答