ssm-spring整合mybatis事務
阿新 • • 發佈:2021-11-18
ssm-spring整合mybatis事務
事務
MyBatis-Spring庫的引入,無需建立新的MyBatis事務管理器,就能使MyBatis接入到Spring事。 引入的方式既可以是註解,也可以是aop。未配置事務例項
首先來看看未配置事務時,執行一組先增加後刪除(刪除異常)的資料庫語句場景。資料庫連線配置延用之前的,這裡不再介紹。- 編寫DAO
- mapper配置檔案中編寫對應sql:
- 分別編寫測試方法測試正確的增加和刪除: 增加:
- 模擬異常事務 現在模擬場景:新增後立即刪除。如果新增成功但是刪除失敗,此時我們的需求期望時整個過程需要回滾。現在先將刪除sql故意寫錯來模擬,看看異常現象:
聲明瞭新增和刪除兩個介面。public interface StudentMapper { void add(Map<Object, Object> student); void delete(String name); }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zx.demo.mybatis.spring.mapper.StudentMapper"> <insert id="add"> INSERT INTO student (`name`,sex) VALUES (#{name},#{sex}); </insert> <delete id="delete"> DELETE FROM student WHERE `name` = #{name}; </delete> </mapper>
執行後確定資料庫中有寫入一條新的資料:@Test public void testTransaction() throws Exception { ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml"); StudentMapper mapper = (StudentMapper) context.getBean("exampleMapper"); Map<Object, Object> student = new HashMap<>(); student.put("name", "曹操"); student.put("sex", "男"); mapper.add(student); }
刪除:
@Test
public void testTransaction() throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
StudentMapper mapper = (StudentMapper) context.getBean("exampleMapper");
mapper.delete("曹操");
}
執行後正確的將剛才新增的“曹操”記錄刪除:<delete id="delete">
DELETE FROM student WHERE `name` = #{name}s;
</delete>
@Test
public void testTransaction() throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
StudentMapper mapper = (StudentMapper) context.getBean("exampleMapper");
Map<Object, Object> student = new HashMap<>();
student.put("name", "曹操");
student.put("sex", "男");
mapper.add(student);
mapper.delete("曹操");
}
執行時發現,新增成功但是刪除時丟擲了語法錯誤的異常:我們看看資料庫結果:
雖然整個過程的第二步刪除失敗了,但資料還是寫入到了資料庫,這顯然與需求不符,下面我們來看看Mybatis-Spring是如何管理事務的。
Mybatis-Spring事務
基於上面的需求,我們現在來看看通過事務,將寫入和刪除一致性實現。按照官方的事務配置說明,這裡介紹註解式事務實現。- 將資料庫操作從test中抽離到業務介面
public class StudentServiceImpl implements StudentService { private StudentMapper mapper;
public StudentMapper getMapper() { return mapper; } public void setMapper(StudentMapper mapper) { this.mapper = mapper; } @Override public void handle() throws Exception { Map<Object, Object> student = new HashMap<>(); student.put("name", "曹操"); student.put("sex", "男"); mapper.add(student); mapper.delete("曹操"); }
}
<!--業務實現類,內部通過mapper介面實現了資料業務操作-->
<bean id="studentServiceImpl" class="com.zx.demo.mybatis.spring.service.StudentServiceImpl">
<property name="mapper" ref="exampleMapper"/>
</bean>
<!--配置Spring資料來源事務管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--使用上面宣告的資料來源-->
<constructor-arg ref="dataSource"/>
</bean>
注意:提供給transactionManager的資料來源一定和建立sqlSessionFactory使用同一個,否則無法生效。
<!--aop注入-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!--這裡一定是注入到mapper對應的業務介面或其實現方法上,否則不生效,也不要用在@Test方法上-->
<!--<aop:pointcut id="p" expression="execution( com.zx.demo.mybatis.spring.service.StudentServiceImpl.(..))"/>-->
<aop:pointcut id="p" expression="execution( com.zx.demo.mybatis.spring.service.StudentService.(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="p"/>
</aop:config>
注意:aop切入點一定是注入到mapper對應的業務介面或其實現方法上,否則不生效,也不要用在@Test方法上
<?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.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置資料來源,可以是實現了javax.sql.DataSource介面的任意資料來源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://xxxx"/>
<property name="username" value="xxx"/>
<property name="password" value="xxx"/>
</bean>
<!--1、SqlSessionFactoryBean:實現了介面org.springframework.beans.factory.FactoryBean-->
<!--2、SqlSessionFactory:通過SqlSessionFactoryBean物件的getObject()方法來構建-->
<!--3、dataSource和mapperLocations:getObject()方法中建立SqlSessionFactory物件的屬性-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:com/zx/demo/mybatis/**/.xml"/>
</bean>
<!--1、MapperFactoryBean:實現了介面org.springframework.beans.factory.FactoryBean-->
<!--2、StudentMapper:通過MapperFactoryBean物件的getObject()方法來構建-->
<!--3、mapperInterface和sqlSessionFactory:getObject()方法中建立StudentMapper介面代理實現物件的屬性-->
<bean id="exampleMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.zx.demo.mybatis.spring.mapper.StudentMapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<!--業務實現類,內部通過mapper介面實現了資料業務操作-->
<bean id="studentServiceImpl" class="com.zx.demo.mybatis.spring.service.StudentServiceImpl">
<property name="mapper" ref="exampleMapper"/>
</bean>
<!--開啟Spring資料來源事務管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--使用上面宣告的資料來源-->
<constructor-arg ref="dataSource"/>
</bean>
<!--aop注入-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!--這裡一定是注入到mapper對應的業務介面或其實現方法上,否則不生效,也不要用在@Test方法上-->
<!--<aop:pointcut id="p" expression="execution(* com.zx.demo.mybatis.spring.service.StudentServiceImpl.(..))"/>-->
<aop:pointcut id="p" expression="execution( com.zx.demo.mybatis.spring.service.StudentService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="p"/>
</aop:config>
</beans>
@Test
public void testTransaction() throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
StudentService studentService = (StudentService) context.getBean("studentServiceImpl");
studentService.handle();
}
刪除語句依舊報語法錯誤,我們到資料庫中看是否插入成功:
可以看出,並沒有寫入“曹操”這條資料,說明事務生效。