在Spring中數據庫事務是經過PlatformTransactionManager進行管理的,jdbcTemplate是不能支持事務的,而可以支持事務的是org.springframework.transaction.support.TransactionTemplate模板,它是Spring所提供的事務管理器的模板
•事務的建立、提交和回滾是經過PlatformTransactionManager接口來完成的。
•當事務產生異常時會回滾事務,在默認的實現中全部的異常都會回滾。咱們能夠經過配置去修改在某些異常發生時回滾或者不回滾事務。
•當無異常時,會提交事務。java
支持JTA事務,經常使用的是DataSourceTransactionManager,它繼承抽象事務管理器AbstractPlatformTransactionManager,而AbstractPlatformTransactionManager又實現了PlatformTransactionManager。這樣Spring就能夠如同源碼中看到的那樣使用PlatformTransactionManager接口的方法,建立、提交或者回滾事務了。mysql
MyBatis框架用得最多的事務管理器是DataSourceTransactionManager(org.springframework.jdbc.datasource.DataSourceTransactionManager),所以下面將以此例進行講解。若是使用的持久框架是Hibernate,那麼你就要用到spring-orm包org.springframework.orm.hibernate4.HibernateTransactionManager了。它們大同小異,通常而言咱們在使用時,還會加入XML的事務命名空間。下面配置一個事務管理器spring
<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 數據庫鏈接池 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/springmvc?useSSL=false&serverTimezone=Hongkong&characterEncoding=utf-8&autoReconnect=true"/> <property name="username" value="root"/> <property name="password" value="123456"/> <property name="maxActive" value="255"/> <property name="maxIdle" value="5"/> <property name="maxWait" value="10000"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 配置數據源事務管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> </beans>
這裏先引入了XML的命名空間,而後定義了數據庫鏈接池,因而使用了DataSourceTransactionManager去定義數據庫事務管理器,而且注入了數據庫鏈接池。這樣Spring就知道你已經將數據庫事務委託給事務管理器transactionManager管理了。在jdbcTemplate源碼分析時,筆者就已經指出,數據庫資源的產生和釋放若是沒有委託給數據庫管理器,那麼就由jdbcTemplate管理,可是此時已經委託給了事務管理器,因此jdbcTemplate的數據庫資源和事務已經由事務管理器處理了。sql
在Spring中可使用聲明式事務或者編程式事務,現在編程式事務幾乎不用了,由於它會產生冗餘,代碼可讀性較差。聲明式事務又能夠分爲XML配置和註解事務,但XML方式也已經不經常使用了,目前主流方法是註解@Transactional。數據庫
用Java配置的方式來實現Spring數據庫事務,須要在配置類中實現接口TransactionManagementConfigurer的annota-tionDrivenTransactionManager方法。Spring會把annotationDrivenTransactionManager方法返回的事務管理器做爲程序中的事務管理器
代碼清單:使用Java配置方式實現Spring數據庫事物apache
package com.ssm.chapter13.config; import org.apache.commons.dbcp.BasicDataSourceFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.TransactionManagementConfigurer; import javax.sql.DataSource; import java.util.Properties; @Configuration @ComponentScan("com.ssm.chapter13.*") //使用事務驅動管理器 @EnableTransactionManagement public class JavaConfig implements TransactionManagementConfigurer { //數據源 private DataSource dataSource = null; /** * 配置數據源. * @return 數據源. */ @Bean(name = "dataSource") public DataSource initDataSource() { if (dataSource != null) { return dataSource; } Properties props = new Properties(); props.setProperty("driverClassName", "com.mysql.cj.jdbc.Driver"); props.setProperty("url", "jdbc:mysql://localhost:3306/springmvc?useSSL=false&serverTimezone=Hongkong&characterEncoding=utf-8&autoReconnect=true"); props.setProperty("username", "root"); props.setProperty("password", "123456"); props.setProperty("maxActive", "200"); props.setProperty("maxIdle", "20"); props.setProperty("maxWait", "30000"); try { dataSource = BasicDataSourceFactory.createDataSource(props); } catch (Exception e) { e.printStackTrace(); } return dataSource; } /** * 配置jdbcTemplate * @return jdbcTemplate */ @Bean(name = "jdbcTemplate") public JdbcTemplate initjdbcTemplate() { JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(initDataSource()); return jdbcTemplate; } /** * 實現接口方法,使得返回數據庫事務管理器 */ @Override @Bean(name = "transactionManager") public PlatformTransactionManager annotationDrivenTransactionManager() { DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); //設置事務管理器管理的數據源 transactionManager.setDataSource(initDataSource()); return transactionManager; } }
實現了TransactionManagementConfigurer接口所定義的方法annotation DrivenTransactionManager,而且咱們使用DataSourceTransactionManager去定義數據庫事務管理器的實例,而後把數據源設置給它。注意,使用註解@EnableTransactionManagement後,在Spring上下文中使用事務註解@Transactional,Spring就會知道使用這個數據庫事務管理器管理事務了。編程
編程式事務以代碼的方式管理事務,換句話說,事務將由開發者經過本身的代碼來實現,這裏須要使用一個事務定義類接口——TransactionDefinition,暫時不進行深刻的介紹,咱們只要使用默認的實現類——DefaultTransactionDefinition就能夠了。
代碼清單:編程式事務mvc
package com.ssm.chapter13.main; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; public class MainTest { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("ssm/chapter13/spring-cfg.xml");//ctx爲Spring IoC容器 JdbcTemplate jdbcTemplate = ctx.getBean(JdbcTemplate.class); //事務定義類 TransactionDefinition def = new DefaultTransactionDefinition(); PlatformTransactionManager transactionManager = ctx.getBean(PlatformTransactionManager.class); TransactionStatus status = transactionManager.getTransaction(def); try { //執行SQL語句 jdbcTemplate.update("insert into t_role(role_name, note) " + "values('role_name_transactionManager', 'note_transactionManager')"); //提交事務 transactionManager.commit(status); } catch (Exception ex) { //回滾事務 transactionManager.rollback(status); } } }
從代碼中能夠看到全部的事務都是由開發者本身進行控制的,因爲事務已交由事務管理器管理,因此jdbcTemplate自己的數據庫資源已經由事務管理器管理,所以當它執行完insert語句時不會自動提交事務,這個時候須要使用事務管理器的commit方法,回滾事務須要使用rollback方法。
固然這是最簡單的使用方式,由於這個方式已經不是主流方式,甚至幾乎是不被推薦使用的方式,之因此介紹是由於它的代碼流程更爲清晰,有助於將來對編程式事務的理解。框架
編程式事務是一種約定型的事務,在大部分狀況下,當使用數據庫事務時,大部分的場景是在代碼中發生了異常時,須要回滾事務,而不發生異常時則是提交事務,從而保證數據庫數據的一致性。ide