spring控制事务:声明式事务(注解)
生活随笔
收集整理的這篇文章主要介紹了
spring控制事务:声明式事务(注解)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
聲明式事務(注解)
spring聲明事務的方式,使用注解的方式
@Transactional
? 名稱:@Transactional
? 類型:方法注解,類注解,接口注解
? 位置:方法定義上方,類定義上方,接口定義上方
? 作用:設置當前類/接口中所有方法或具體方法開啟事務,并指定相關事務屬性
? 范例:
tx:annotation-driven 標簽用于開啟事務的注解驅動
? 名稱:tx:annotation-driven
? 類型:標簽
? 歸屬:beans標簽
? 作用:開啟事務注解驅動,并指定對應的事務管理器
? 范例:
聲明式事務(純注解驅動)
@EnableTransactionManagement 這個注解就是代替上面的標簽
? 名稱:@EnableTransactionManagement
? 類型:類注解
? 位置:Spring注解配置類上方
? 作用:開啟注解驅動,等同XML格式中的注解驅動
? 范例:
代碼演示(代碼中注釋為詳細解釋)
數據表account
構建maven項目
pom文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.fs</groupId><artifactId>day04_spring_AOP_Transaction_02</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.9.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.1.9.RELEASE</version></dependency><!-- jdbc--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.1.9.RELEASE</version></dependency><!-- spring整合mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.1</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.5</version></dependency><!-- mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><!--druid連接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.20</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version></dependency><!-- aop切面包--><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.5</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency></dependencies></project>jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://192.168.93.132:3306/test jdbc.username=root jdbc.password=root編寫配置類
SpringConfig
package com.fs.config;import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.Import; import org.springframework.transaction.annotation.EnableTransactionManagement;//表示這個類是一個spring的配置類,并將其存入到ioc容器中 @Configuration /*開啟掃描注解的那些包 <!-- 啟動spring掃描注解的包,只掃描spring的注解--><context:component-scan base-package="com.fs"/>*/ @ComponentScan("com.fs") //引入其他的配置類 @Import({JdbcConfig.class,MybatisConfig.class,TransactionManagerConfig.class}) //開啟切面自動代理 @EnableAspectJAutoProxy //開啟聲明式事務管理 相當于配置文件中的 <tx:annotation-driven transaction-manager="transactionManager"/> @EnableTransactionManagement public class SpringConfig { }JdbcConfig
package com.fs.config;import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource;/* <!-- 引入properties--><context:property-placeholder location="classpath:jdbc.properties"/>*/ @PropertySource("classpath:jdbc.properties") public class JdbcConfig {//@Value("${Key}")@Value("${jdbc.driver}")private String driver;@Value("${jdbc.url}")private String url;@Value("${jdbc.username}")private String username;@Value("${jdbc.password}")private String password;/*<!-- 整合druid,把DruidDataSource交給spring管理--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean>*///將返回的DruidDataSource交給ioc管理@Beanpublic DruidDataSource getDruidDataSource(){//創建DruidDataSourceDruidDataSource druidDataSource = new DruidDataSource();//給屬性賦值,這個是上面從配置文件中依耐注入給屬性的druidDataSource.setDriverClassName(driver);druidDataSource.setUrl(url);druidDataSource.setUsername(username);druidDataSource.setPassword(password);//返回DruidDataSource,然后交給ioc管理return druidDataSource;} }MybatisConfig
package com.fs.config;import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean;import javax.sql.DataSource;public class MybatisConfig {/*<!-- 配置MyBatis的會話工廠類 mybatis.spring 下的SqlSessionFactoryBean配置的sqlSessionFactory得到SqlSession,然后MyBatis從spring中拿到SqlSession.getMapper()去動態代理dao--><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 給MyBatis配置鏈接池,依耐注入--><property name="dataSource" ref="dataSource"/> <!-- 配置別名掃描的包,被掃描的包下的類起的別名就是類名首字母小寫,用于mapper.xml文件中使用--><property name="typeAliasesPackage" value="com.fs.pojo"/></bean>*/@Beanpublic SqlSessionFactoryBean getSqlSessionFactoryBean(@Autowired DataSource dataSource){//創建sql會話工廠類 //這里@Autowired也是從ioc拿DataSourceSqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();//從ioc容器中取出jdbcConfig中配置的druidDatasourcesqlSessionFactoryBean.setDataSource(dataSource);//配置起別名sqlSessionFactoryBean.setTypeAliasesPackage("com.fs.pojo");return sqlSessionFactoryBean;}/*<!--配置MyBatis掃描dao的包,讓MyBatis動態代理生成這個dao的實現類,并交給ioc管理mybatis-spring這個包下MapperScannerConfigurer提供了spring于MyBatis的整合--><bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- 告訴MyBatis我dao在哪里.然后MyBatis將這個dao實現,然后給spring管理--><property name="basePackage" value="com.fs.dao"/></bean>*///創建MyBatis動態代理掃描類@Beanpublic MapperScannerConfigurer getMapperScannerConfigurer(){//創建映掃描配置類MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();//設置動態代理掃描的dao的包mapperScannerConfigurer.setBasePackage("com.fs.dao");//交給spring管理return mapperScannerConfigurer;} }TransactionManagerConfig
package com.fs.config;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager;import javax.sql.DataSource;/* 聲明式事務配置類*/ public class TransactionManagerConfig {/*<!-- 將事務管理器交給ioc管理--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean>*/@Beanpublic PlatformTransactionManager getTransactionManager(@Autowired DataSource dataSource){//使用Spring的平臺事務管理器,是一個接口,使用他的實現類構造器傳遞一個連接池DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();//傳遞一個連接池dataSourceTransactionManager.setDataSource(dataSource);return dataSourceTransactionManager;} }實體類
Account
package com.fs.pojo;import lombok.Data;@Data public class Account {private Integer id;private String name;private Double money; }Dao
AccountDao
package com.fs.dao;import com.fs.pojo.Account; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update;import java.util.List;public interface AccountDao {@Select("select * from account")List<Account> findAll();//查詢所有//根據名字修改money@Update("UPDATE account SET money = #{money} WHERE name = #{name}")void transferMoney(Account account);//根據名字查詢賬戶信息@Select("select * from account where name = #{name}")Account findAccountByName(@Param("name") String name); }service
AccountService
package com.fs.service;import com.fs.pojo.Account; import org.springframework.transaction.annotation.Transactional;import java.util.List;/* 在接口上配置@Transactional,那么他下面的實現類都會進行事務管理 這個注解就相當于配置文件中的這些配置<tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="*" read-only="false"/></tx:attributes></tx:advice><aop:config><aop:pointcut id="pt" expression="execution(* com.fs.service.impl.*.*(..))"/><aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/></aop:config>如果不寫屬性,該注解的默認配置為@Transactional(readOnly = false,timeout = -1,isolation = Isolation.DEFAULT,rollbackFor = {ArithmeticException.class, IOException.class},noRollbackFor = {},propagation = Propagation.REQUIRES_NEW)*/ public interface AccountService {List<Account> findAll();Account findAccountByName(String name);//對這個方法開啟事務使用默認配置@Transactionalvoid transferMoneyAtoB(String aName,String bName,Integer money); }AccountServiceImpl
package com.fs.service.impl;import com.fs.dao.AccountDao; import com.fs.pojo.Account; import com.fs.service.AccountService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;import javax.sql.DataSource; import java.util.List;/*<!-- 把業務類 AccountServiceImpl 交給ioc管理 --><bean id="accountServiceImpl" class="com.fs.service.impl.AccountServiceImpl"> <!-- 依耐注入dao,這個dao被MyBatis動態代理實現后被spring存放在ioc容器中--><property name="accountDao" ref="accountDao"/></bean>*/ @Service public class AccountServiceImpl implements AccountService {//從ioc獲取MyBatis動態代理的accountDao實現類@Autowiredprivate AccountDao accountDao;@Autowiredprivate DataSource dataSource;@Overridepublic List<Account> findAll() {return accountDao.findAll();}@Overridepublic Account findAccountByName(String name) {return accountDao.findAccountByName(name);}//轉賬的業務實現@Overridepublic void transferMoneyAtoB(String aName, String bName, Integer money) {//先查出兩個人的數據Account aAccount = accountDao.findAccountByName(aName);Account bAccount = accountDao.findAccountByName(bName);//然后a減錢,b加錢aAccount.setMoney(aAccount.getMoney()-money);bAccount.setMoney(bAccount.getMoney()+money);//然后調用轉賬方法(sql語句為更新賬戶)accountDao.transferMoney(aAccount);//制作一個異常 // int i = 1/0;accountDao.transferMoney(bAccount);}}測試類
package com.fs.service.impl;import com.fs.config.SpringConfig; import com.fs.pojo.Account; import com.fs.service.AccountService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import java.util.List;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class) public class AccountServiceImplTest {@Autowiredprivate AccountService accountService;//測試查詢所有方法@Testpublic void findAll() {List<Account> all = accountService.findAll();System.out.println(all);}//測試轉賬方法已經使用@Transactional綁定事務@Testpublic void transferMoneyAtoB() {//測試轉賬方法accountService.transferMoneyAtoB("小付","小花",100);}}執行效果
業務層轉賬方法正常運行成功后數據表數據
由于我們測試代碼中是小付向小花轉賬100元,代碼執行成功后應該小付900,小花1100
業務層轉賬方法我們給制作一個異常1/0 的/ by zero異常,
運存測試轉賬方法控制臺輸出
數據庫中表的數據
小付原本900,小花1100,我們進行了轉賬業務,但是制作了異常,事務會進行回滾,所以金額不會發生變化
總結
以上是生活随笔為你收集整理的spring控制事务:声明式事务(注解)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring控制事务:声明式事务(XML
- 下一篇: Spring模板对象之RedisTemp