Spring 声明式事务XML及注解实现

一. 基于XML的声明式事务控制

1.环境搭建

(1)创建maven的java项目并导入坐标

<dependencies>
  	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-context</artifactId>
  		<version>5.0.2.RELEASE</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>
  	<dependency>
  		<groupId>mysql</groupId>
  		<artifactId>mysql-connector-java</artifactId>
  		<version>5.1.6</version>
  	</dependency>
	<!--aop使用到的-->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.7</version>
    </dependency>
  </dependencies>

(2)创建配置文件并导入约束

需要导入aop和tx两个名称空间

<?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: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/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)准备数据库和实体类

数据库:

create database spring;
use spring;
创建表:
create table account(
	id int primary key auto_increment,
	name varchar(40),
	money float
)

实体类:Account

public class Account implements Serializable {

	private Integer id;
	private String name;
	private Float money;
	//重写set/get/toString方法 略
	}

(4)编写service层接口和实现类

接口:

public interface AccountService { 
     // 转账操作
    void transfer(String targetName,String sourceName,Float money);
}

实现类:

public class AccountServiceImpl implements AccountService {

    //注入Dao
    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
    /**
     * 转账
     */
    @Override
    public void transfer(String targetName, String sourceName, Float money) {
        //查询A账号信息
        Account targetAccount = accountDao.getByName(targetName);

        //查询B账号信息
        Account sourceAccount = accountDao.getByName(sourceName);

        //A-money
        targetAccount.setMoney(targetAccount.getMoney()-money);

        //B+money
        sourceAccount.setMoney(sourceAccount.getMoney()+money);

        //持久化数据到数据库
        accountDao.update(targetAccount);
        //int q=10/0;
        
        accountDao.update(sourceAccount);
    }
}

(5)编写dao层接口和实现类

接口:

public interface AccountDao {
    /**
     * 根据名字查询账号信息
     * (假设名字唯一)
     */
    Account getByName(String name);

    /**
     * 修改账号
     */
    int update(Account account);
}

实现类:

public class AccountDaoImpl implements AccountDao {

    //注入JdbcTemplate,实现数据库的增删改查
    private JdbcTemplate jdbcTemplate;

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * 根据名词查询账号信息
     */
    @Override
    public Account getByName(String name) {
        try {
            return jdbcTemplate.queryForObject("select * from account where name=?",new BeanPropertyRowMapper<Account>(Account.class),name);
        } catch (DataAccessException e) {
        }
        return null;
    }

    /**
     * 根据ID修改账号信息
     */
    @Override
    public int update(Account account) {
        return jdbcTemplate.update("update account set money=? where id=?",account.getMoney(),account.getId());
    }
}

(6)在配置文件中配置service层和dao层

	<!--
        AccountServiceImpl
        注入DAO
    -->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao" />
    </bean>

    <!--
        Dao->JdbcTemplate
    -->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate" />
    </bean>
	
	<!--
        JdbcTemplate->DataSource
    -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入DataSource-->
        <constructor-arg name="dataSource" ref="dataSource" />
    </bean>

2.事务控制配置步骤

配置文件

 <!--==========声明式事务配置===========-->
    <!--
       1.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://127.0.0.1:3306/spring"></property>
        <property name="user" value="root"></property>
        <property name="password" value="123"></property>
    </bean>

    <!--
        2.事务管理器配置
            DataSourceTransactionManager:实现事务的操作,实现了PlatformTransactionManager接口
    -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!--
        3.事务执行规则制定
          id="txAdvice":唯一标识
          transaction-manager="txManager":指定事务规则执行的对象
    -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <!--
            tx:attributes:事务约束的规则
        -->
        <tx:attributes>
            <!--
                name="*":指定受限制的方法名字,*:表示所有方法
                read-only:是否是只读事务。默认false,不只读。
				isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。 
				propagation:指定事务的传播行为。
				timeout:指定超时时间。默认值为:-1。永不超时。
				rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。没有默认值,任何异常都回滚。
				no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回滚。没有默认值,任何异常都回滚。
            -->
            <tx:method name="add*"
                       propagation="REQUIRED"
                       isolation="DEFAULT"
                       rollback-for="java.lang.Exception"
                       timeout="-1" />
            <!--
                只读事务:只能读取数据库数据,不能对数据库进行增删改
            -->
            <tx:method name="tran*" read-only="true" />
        </tx:attributes>
    </tx:advice>

    <!--
        4.通知配置
        配置切入点表达式和对应的事务
        aop:advisor:Spring内置的通知
        advice-ref="":被通知的对象,即事务
        pointcut:切入点  pointcut-ref:切入点表达式引用
    -->
    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.service.impl.AccountServiceImpl.*(..))" />
    </aop:config>
    <!-- 也可写成以下格式 -->
    <aop:config>
	<aop:pointcut expression="execution(* com.itheima.service.impl.*.*(..))" id="pt1"/>
	<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/>
	</aop:config>

测试文件

public class JdbcTemplateTest {
    /**
     * 转账
     */
    @Test
    public void testTransfer(){
        //获取容器ApplicationContext
        ApplicationContext act = new ClassPathXmlApplicationContext("spring.xml");

        //获取Service的实例
        AccountService accountService = (AccountService) act.getBean("accountService");

        //转账
        accountService.transfer("A","B",100f);
    }
}

二.基于注解的声明式事务控制

1.环境搭建

(1)创建maven的java项目并导入坐标

同xml

(2)创建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:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
	<!-- 包扫描 -->
	<context:component-scan base-package="com.itheima"></context:component-scan>
	
    <!--
        JdbcTemplate->DataSource
    -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入DataSource-->
        <constructor-arg name="dataSource" ref="dataSource" />
    </bean>

(3)创建数据库表和实体类

同xml

(4)创建业务层接口和实现类并使用注解让spring管理

@Service("accountService")
public class AccountServiceImpl implements AccountService {
	@Autowired
	private AccountDao accountDao;

	//其余代码和基于XML的配置相同
}

(5)创建Dao接口和实现类并使用注解让spring管理

@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {

	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	//其余代码和基于XML的配置相同
}

2.事务控制配置步骤

配置文件

  <!--==========声明式事务配置===========-->
    <!--
       1.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://127.0.0.1:3306/spring"></property>
        <property name="user" value="root"></property>
        <property name="password" value="123"></property>
    </bean>

    <!--
        2.事务管理器配置
            DataSourceTransactionManager:实现事务的操作,实现了PlatformTransactionManager接口
    -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!--新增:
        开启注解事务
        指定默认事务管理器
    -->
    <tx:annotation-driven transaction-manager="txManager" />

service层修改

@Transactional    //取代原先的通知配置
@Service(value = "accountService")
public class AccountServiceImpl implements AccountService {

    //注入Dao
    @Autowired
    private AccountDao accountDao;
    
    /**
     * 转账  
     */
    @Transactional(
            propagation= Propagation.REQUIRED,  //propagation= Propagation.REQUIRED:当前方法必须在事务下执行
            isolation = Isolation.DEFAULT,      //事务的隔离级别
            timeout = -1                       //超时配置
    )	//取代原先的事务执行规则
    @Override
    public void transfer(String targetName, String sourceName, Float money) {
      其余代码同xml形式
    }
}

测试文件:
代码同xml形式

三.全注解的声明式事务控制

新增SpringConfig.java

Configuration
@ComponentScan(basePackages = "com.itheima")
@EnableTransactionManagement  //取代原先的开启注解事务
public class SpringConfig {

    /**
     *创建事务管理器
     */
    @Bean
    public DataSourceTransactionManager transactionManager(DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }


    /**
     * 创建数据源对象
     * @return
     */
    @Bean
    public DataSource dataSource(){
        try {
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setDriverClass("com.mysql.jdbc.Driver");
            dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/spring5");
            dataSource.setUser("root");
            dataSource.setPassword("itcast");

            return dataSource;
        } catch (PropertyVetoException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 创建JdbcTemplate
     */
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource){
        return new JdbcTemplate(dataSource);
    }
}

测试文件
将ClassPathXmlApplicationContext(“spring.xml”)换成AnnotationConfigApplicationContext(SpringConfig.class)

 
public class JdbcTemplateTest {
    /**
     * 转账
     */
    @Test
    public void testTransfer(){
        //获取容器ApplicationContext
        ApplicationContext act = new AnnotationConfigApplicationContext(SpringConfig.class);

        //获取Service的实例
        AccountService accountService = (AccountService) act.getBean("accountService");

        //转账
        accountService.transfer("A","B",100f);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值