Spring学习03:事务控制TransactionManager

使用Spring配置事务控制

项目准备

  1. 在pom.xml中导入依赖的坐标

    <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.0.2.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.0.2.RELEASE</version>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.6</version>
            </dependency>
            
            <dependency>
                <groupId>com.mchange</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.2.1</version>
            </dependency>
            
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
            
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.6.8</version>
            </dependency>
            
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>5.0.2.RELEASE</version>
            </dependency>
            
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-tx</artifactId>
                <version>5.0.2.RELEASE</version>
            </dependency>
        </dependencies>
    
  2. 在resources目录下创建bean.xml

    <?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:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.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">
    </beans>
    
  3. 创建实体类

    public class Account {
    	private int accountId;
    	private String name;
    	private double money;
    	
    	public int getAccountId() {
    		return accountId;
    	}
    	
    	public void setAccountId(int accountId) {
    		this.accountId = accountId;
    	}
    	
    	public String getName() {
    		return name;
    	}
    	
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public double getMoney() {
    		return money;
    	}
    
    	public void setMoney(double money) {
    		this.money = money;
    	}
    
    	@Override
    	public String toString() {
    		return "Account{" +
    				"accountId=" + accountId +
    				", name='" + name + '\'' +
    				", money=" + money +
    				'}';
    	}
    }
    
  4. 创建service层接口及其实现类

    public interface AccountService {
    	/**
    	 * 查询所有账户
    	 * @return
    	 */
    	List<Account> findAll();
    	
    	/**
    	 * 转账
    	 * @param sourceName 转出账户
    	 * @param targetName 转入账户
    	 * @param money		 转账金额
    	 */
    	void transfer(String sourceName,String targetName,double money);
    }
    
    public class AccountServiceImpl implements AccountService {
      
      private AccountDao accountDao;
    
      public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
      }
    
      public List<Account> findAll() {
        return accountDao.findAll();
      }
    
      public void transfer(String sourceName, String targetName, double money) {
        // 1查询转出账户
        Account source = accountDao.findAccountByName(sourceName);
        // 2查询转入账户
        Account target = accountDao.findAccountByName(targetName);
        // 3转出账户减钱
        source.setMoney(source.getMoney() - money);
        // 4转入账户加钱
        target.setMoney(target.getMoney() + money);
        // 5更新转出账户
        accountDao.updateAccount(source);
        // 6更新转入账户
        accountDao.updateAccount(target);
      }
    }
    
  5. 创建dao层接口及其实现类

    public interface AccountDao {
    	/**
    	 * 查询所有账户
    	 * @return
    	 */
    	List<Account> findAll();
    	
    	/**
    	 * 更新账户
    	 * @param account
    	 */
    	void updateAccount(Account account);
    
    	/**
    	 * 根据名称查询账户
    	 * @param accountName
    	 * @return
    	 */
    	Account findAccountByName(String accountName);
    }
    
    public class AccountDaoImpl implements AccountDao {
    	
    	private JdbcTemplate jdbcTemplate;
    	
    	public List<Account> findAll() {
    		return jdbcTemplate.query("select * from account",new BeanPropertyRowMapper<Account>(Account.class));
    	}
    
    	public void updateAccount(Account account) {
    		jdbcTemplate.update("update account set name=?,money=? where accountId=?",account.getName(),account.getMoney(),account.getAccountId());
    	}
    
    	public Account findAccountByName(String accountName) {
    		List<Account> accounts = jdbcTemplate.query("select * from account where name=?",new BeanPropertyRowMapper<Account>(Account.class),accountName);
    		if(accounts.isEmpty()){
    			return null;
    		}
    		if(accounts.size() > 1){
    			throw new RuntimeException("结果集不唯一");
    		}
    		return accounts.get(0);
    	}
    }
    
  6. 在bean.xml中添加配置

    <context:component-scan base-package="com.chen"></context:component-scan>
        <!--配置service-->
        <bean id="accountService" class="com.chen.service.impl.AccountServiceImpl">
            <!--注入Dao-->
            <property name="accountDao" ref="accountDao"></property>
        </bean>
        <!--配置dao-->
        <bean id="accountDao" class="com.chen.dao.impl.AccountDaoImpl">
        	<!--注入数据源-->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
        <!--配置dataSource-->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <!--连接数据库的必备信息-->
            <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/account1?characterEncoding=utf-8"></property>
            <property name="user" value="root"></property>
            <property name="password" value="991105"></property>
        </bean>
    

基于XML的Spring事务控制的配置

  1. 配置事务管理器并注入数据源

    <!--配置事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!--注入数据源-->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
  2. 配置事务的通知

    <!--配置事务的通知-->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <!--匹配所有方法-->
                <tx:method name="*" propagation="REQUIRED" read-only="false"/>
                <!--匹配所有查询方法-->
                <tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
            </tx:attributes>
        </tx:advice>
    

    其中的属性如下:

    • id:事务通知的唯一标识
    • transaction-manager:引入事务管理器
    • <tx:method>标签内的属性:
      • name:匹配的方法,可以使用通配符*
      • isolation:事务的隔离级别,Spring默认使用数据库的事务隔离级别
      • propagation:事务的传播行为,默认为REQUIRED,增删改方法应该用REQUIRED,查询方法可以使用SUPPORTS
      • read-only:事务是否为只读事务,默认为false,增删改方法应该用false,查询方法可以使用true
      • timeout:指定超时时间,默认值为-1,表示永不超时
      • rollback-for:指定一个异常,当发生该异常时,事务回滚;发生其他异常时,事务不回滚;无默认值,表示发生任何异常都回滚
      • no-rollback-for:指定一个异常,当发生该异常时,事务不回滚;发生其他异常时,事务回滚.;默认值,表示发生任何异常都回滚
  3. 配置AOP

    <!--配置AOP-->
        <aop:config>
            <!--配置切入点表达式-->
            <aop:pointcut id="pt" expression="execution(* com.chen.service.impl.*.*(..))"/>
            <!--为事务通知指定切入点表达式-->
            <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"></aop:advisor>
        </aop:config>
    

基于注解的Spring事务控制的配置

使用的注解

@EnableTransactionManagement:标识开启事务控制

  1. 创建事务控制配置类

    public class TransactionConfiguration {
        @Bean(name="transactionManager")
        public PlatformTransactionManager createTransactionManager(DataSource dataSource){
            return new DataSourceTransactionManager(dataSource);
        }
    }
    
  2. 创建JDBCConfig配置类

    public class JdbcConfiguration {
        @Value("${jdbc.driver}")
        private String driver;
    
        @Value("${jdbc.url}")
        private String url;
    
        @Value("${jdbc.user}")
        private String user;
    
        @Value("${jdbc.password}")
        private String password;
    
        @Bean(name = "jdbcTemplate")
        public JdbcTemplate createJdbcTemplate(DataSource dataSource){
            return new JdbcTemplate(dataSource);
        }
    
        @Bean(name = "dataSource")
        public DataSource createDataSource(){
            DriverManagerDataSource ds = new DriverManagerDataSource();
            ds.setDriverClassName(driver);
            ds.setUrl(url);
            ds.setUsername(user);
            ds.setPassword(password);
            return ds;
        }
    }
    
  3. 创建SpringConfiguration主配置类

    @Configuration
    @ComponentScan("com.chen")
    @Import({JdbcConfiguration.class,TransactionConfiguration.class})
    @PropertySource("classpath:jdbcConfig.properties")
    @EnableTransactionManagement
    public class SpringConfiguration {
    
    }
    
  4. 改写业务层实现类

    @Service("accountService")
    @Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
    public class AccountServiceImpl implements AccountService {
      @Autowired
      private AccountDao accountDao;
    
      public List<Account> findAll() {
        return accountDao.findAll();
      }
    
      @Transactional(propagation = Propagation.REQUIRED,readOnly = false)
      public void updateAccount(Account account) {
        accountDao.updateAccount(account);
      }
    
      @Transactional(propagation = Propagation.REQUIRED,readOnly = false)
      public void transfer(String sourceName, String targetName, double money) {
        // 1查询转出账户
        Account source = accountDao.findAccountByName(sourceName);
        // 2查询转入账户
        Account target = accountDao.findAccountByName(targetName);
        // 3转出账户减钱
        source.setMoney(source.getMoney() - money);
        // 4转入账户加钱
        target.setMoney(target.getMoney() + money);
        // 5更新转出账户
        accountDao.updateAccount(source);
        // 6更新转入账户
        accountDao.updateAccount(target);
      }
    }
    
posted @ 2020-04-14 11:55  codeDD  阅读(177)  评论(0编辑  收藏  举报